I'm developing web service using XFire,Spring JSR181 implementation.
I need to use SOAP header in mode INOUT.
I've define the following operation in web service interface:
@WebMethod(operationName = "op")
@WebResult(name = "opRes")
public String op(@WebParam(name = "ws_header", header = true, mode = WebParam.Mode.INOUT)Holder<SessionInfoHeader> ws_header);
The implementation is simple it just prints some string.
(see attached ServiceAWS.java,ServiceAImpl.java)
The problem is that I have a following exception:
Please see attache the eclipse project XFireProblem.zip the war as it was deployed in JBoss.
I've used the client: com.jacada.ServiceAClient
the exception is:
java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.codehaus.xfire.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:54)
at org.codehaus.xfire.service.binding.ServiceInvocationHandler.sendMessage(ServiceInvocationHandler.java:271)
at org.codehaus.xfire.service.binding.ServiceInvocationHandler$1.run(ServiceInvocationHandler.java:84)
at org.codehaus.xfire.service.binding.ServiceInvocationHandler.execute(ServiceInvocationHandler.java:132)
at org.codehaus.xfire.service.binding.ServiceInvocationHandler.invoke(ServiceInvocationHandler.java:107)
at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
at org.codehaus.xfire.transport.DefaultEndpoint.onReceive(DefaultEndpoint.java:64)
at org.codehaus.xfire.transport.AbstractChannel.receive(AbstractChannel.java:38)
at org.codehaus.xfire.transport.http.XFireServletController.invoke(XFireServletController.java:301)
at org.codehaus.xfire.transport.http.XFireServletController.doService(XFireServletController.java:130)
at org.codehaus.xfire.transport.http.XFireServlet.doPost(XFireServlet.java:116)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:81)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.jboss.web.tomcat.security.CustomPrincipalValve.invoke(CustomPrincipalValve.java:39)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:159)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:59)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWorkerThread.java:112)
at java.lang.Thread.run(Unknown Source)
java.lang.IllegalArgumentException: wrong number of arguments
(I will provide the stack trace later).
I saw in org.codehaus.xfire.service.binding.ServiceInvocationHandler class in
protected Object[] fillInHolders(MessageContext context,OperationInfo opInfo, MessageInfo inMsg, MessageInfo outMsg, MessagePartContainer headerMsg,
MessagePartContainer outHeaderMsg, List params) method calculation of the number of the parameters:
int outSize = 0;
if (outMsg != null)
{
outSize = outHeaderMsg.size() + outMsg.size();
if (outSize != 0) outSize--;
}
int total = inMsg.size() + headerMsg.size() + outSize;
In my case for method "op" which takes only one parameter (the header) the value of total is 2.
Later the allocated array
Object[] newParams = new Object[total];
used in Java reflection to find the method, BUT there's no method with 2 parameters, but only with one parameter.
So it seems that there's a bug here.
I don't understand why does outSize participates in calculation of total.
Would it be correct to make the line:
int total = inMsg.size() + headerMsg.size();
May the problem in some other place.
I have an idea for what may be the problem:
the fillInHolders() method does not take into consideration the fact that in case of JSR181 the parameter may be of mode INOUT, in this case it will be counted twice one for being IN parameter and one for being OUT parameter.
I have suggestion for a fix:
(Please let me know if the fis is OK and what next)
(the file attached ServiceInvocationHandler.java)
/************** JACADA_CHANGE START ***********************/
{
) {
return true;
}
{
private boolean isMessagePartExistByQName(List parts,QName name) {
if (parts == null || name == null) { return false; }
for (Iterator it = parts.iterator(); it.hasNext()
MessagePartInfo part = (MessagePartInfo)it.next();
QName n = part.getName();
if (name.equals
}
return false;
}
// calculates the number of the different parameters.
// the reason is that the parameters in JSR181 may be: IN,OUT,INOUT
// in case of INOUT the parameter will appear both in "in" parameters container and "out" parameters container
// but it should be counted only once
private int calculateDifferentParametersNumber(MessagePartContainer in, MessagePartContainer out) {
int size = 0;
if (in == null && out == null) { return 0; }
if (in == null) { return out.size(); }
if (out == null) { return in.size(); }
// iterate on "out" parameters container and if the parameter does not appear in "in"
// container as well increment the counter
// (the "out" was chosen arbitrary due to the simmetry)
for (Iterator it = out.getMessageParts().iterator(); it.hasNext()
MessagePartInfo outPart = (MessagePartInfo)it.next();
QName name = outPart.getName();
if( !isMessagePartExistByQName(in.getMessageParts(), name)) { size++; }
}
// add all the parameters in "in" containers
return size + in.size();
}
/**
*/
protected Object[] fillInHolders(MessageContext context,
OperationInfo opInfo,
MessageInfo inMsg,
MessageInfo outMsg,
MessagePartContainer headerMsg,
MessagePartContainer outHeaderMsg,
List params) throws XFireFault
{
int paramSize = calculateDifferentParametersNumber(inMsg, outMsg);
int headerSize = calculateDifferentParametersNumber(headerMsg, outHeaderMsg);
int total = paramSize + headerSize;
// the outh param should not be counted
if (outMsg.size() > 0) { total--; }
/************** JACADA_CHANGE END ***********************/