Announcement Announcement Module
Collapse
No announcement yet.
"argument type mismatch" issue with Spring WS and JAXB marshelling Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • "argument type mismatch" issue with Spring WS and JAXB marshelling

    Hi,

    I'm trying to add spring web service module to my project. I've added the the necessary beans and the required schema definition files. But I'm facing some issues with the name space declarations.

    I'm using annotation based endpoints in my spring configurations(XPathParamAnnotationMethodEndpointA dapter).

    In my schema definition I've declared the "targetNamespace" as "http://apj.com/ws/invoice-ops/".
    If I use @XmlRootElement(namespace="http://apj.com/ws/invoice-ops/", name="invoiceCountRequest") in my marshlling class, during the web service client request I'm getting an error saying
    2010-09-24 10:05:04,718 [main] TRACE org.springframework.ws.client.MessageTracing.sent - Sent request [<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1"><wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1"><wsse:Username>Bert</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">DmT+jElaKcgQ6I2X+3TYcc0qckM=</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">5kuvcV3D7Wsq62xdRDvBSg==</wsse:Nonce><wsu:Created>2010-09-24T04:35:04.640Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header><soapenv:Body><ns2:invoiceCountRequ est xmlns:ns2="http://apj.com/ws/invoice-ops/" xmlns:ns3="http://apj.com/ws/invoice-ops"><accountId>5</accountId><key>5555</key><fromDate>2010-09-24T10:05:04.453+05:30</fromDate><toDate>2010-09-24T10:05:04.453+05:30</toDate><codes>cld</codes></ns2:invoiceCountRequest></soapenv:Body></soapenv:Envelope>]
    2010-09-24 10:05:05,656 [main] TRACE org.springframework.ws.client.MessageTracing.recei ved - Received response [<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><soapenv:Fault><faultcode>soapenv: Server</faultcode><faultstring xml:lang="en">argument type mismatch</faultstring></soapenv:Fault></soapenv:Body></soapenv:Envelope>] for request [<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1"><wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1"><wsse:Username>Bert</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">DmT+jElaKcgQ6I2X+3TYcc0qckM=</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">5kuvcV3D7Wsq62xdRDvBSg==</wsse:Nonce><wsu:Created>2010-09-24T04:35:04.640Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header><soapenv:Body><ns2:invoiceCountRequ est xmlns:ns2="http://apj.com/ws/invoice-ops/" xmlns:ns3="http://apj.com/ws/invoice-ops"><accountId>5</accountId><key>5555</key><fromDate>2010-09-24T10:05:04.453+05:30</fromDate><toDate>2010-09-24T10:05:04.453+05:30</toDate><codes>cld</codes></ns2:invoiceCountRequest></soapenv:Body></soapenv:Envelope>]
    org.springframework.ws.soap.client.SoapFaultClient Exception: argument type mismatch
    at org.springframework.ws.soap.client.core.SoapFaultM essageResolver.resolveFault(SoapFaultMessageResolv er.java:37)
    at org.springframework.ws.client.core.WebServiceTempl ate.handleFault(WebServiceTemplate.java:738)
    at org.springframework.ws.client.core.WebServiceTempl ate.doSendAndReceive(WebServiceTemplate.java:564)
    at org.springframework.ws.client.core.WebServiceTempl ate.sendAndReceive(WebServiceTemplate.java:502)
    at org.springframework.ws.client.core.WebServiceTempl ate.marshalSendAndReceive(WebServiceTemplate.java: 351)
    at org.springframework.ws.client.core.WebServiceTempl ate.marshalSendAndReceive(WebServiceTemplate.java: 345)
    at org.springframework.ws.client.core.WebServiceTempl ate.marshalSendAndReceive(WebServiceTemplate.java: 337)
    at InvoiceCountRequestTest.request(InvoiceCountReques tTest.java:37)
    at InvoiceCountRequestTest.main(InvoiceCountRequestTe st.java:53)
    But if I change the XmlRootElement as "@XmlRootElement(namespace="http://apj.com/ws/invoice-ops", name="invoiceCountRequest")" (namespace without the last slash) then the request works fine but the schema validation fails.

    Can you help me to resolve this issue. I'll be happy to provide any more information required by you.

    I'm attaching my schema, and the endpoint below.


    In my schema definition is as follows
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <schema targetNamespace="http://apj.com/ws/invoice-ops/" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://apj.com/ws/invoice-ops/">
    
    
    
        <element name="invoiceCountRequest" type="tns:invoiceCountRequest"></element>
    
        <complexType name="invoiceCountRequest">
        	<sequence>
        		<element name="accountId">
        			<simpleType>
        				<restriction base="int">
        					<minInclusive value="1"></minInclusive>
        				</restriction>
        			</simpleType>
        		</element>
        		<element name="key">
        			<simpleType>
        				<restriction base="string">
        					<minLength value="1"></minLength>
        				</restriction>
        			</simpleType>
        		</element>
        		<element name="fromDate" type="dateTime"></element>
                <element name="toDate" type="dateTime"></element>
                <element name="codes" type="string" minOccurs="1"
        			maxOccurs="unbounded">
        		</element>
    
        	</sequence>
        </complexType>
    
        <complexType name="invoiceCountResponse">
        	<sequence>
        		<element name="countMap" type="tns:MyMap"></element>
        	</sequence>
        </complexType>
    
        <element name="invoiceCountResponse" type="tns:invoiceCountResponse"></element>
    
        <complexType name="MyMap">
        	<sequence>
        		<element name="Entry" type="tns:MapEntry" minOccurs="1" maxOccurs="unbounded"></element>
        	</sequence>
        </complexType>
    
        <complexType name="MapEntry">
        	<attribute name="key" type="string"></attribute>
        	<attribute name="value" type="string"></attribute>
        </complexType>
    </schema>
    Then I created my model objects using the xjc.bat utility from jaxb.

    My endpoint class is as follows
    Code:
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    import org.springframework.ws.server.endpoint.annotation.Endpoint;
    import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
    
    @Endpoint
    @Component("InvoiceCountRequestEndPoint")
    public class InvoiceCountRequestEndPoint {
    	private static Log log = LogFactory
    			.getLog(InvoiceCountRequestEndPoint.class);
    
    	@PayloadRoot(localPart = "invoiceCountRequest", namespace = "http://apj.com/ws/invoice-ops/")
    	public InvoiceCountResponse memberDetails(InvoiceCountRequest request)
    			throws EncryptionException {
    
    		InvoiceCountResponse response = new InvoiceCountResponse();
    		
    		Map<String, String> m=new HashMap<String, String>();
    		m.put("00", "0000000");
    		
    		response.setCountMap(m);
    		
    		return response;
    	}
    }
    I'm using the following class to test the web service
    Code:
    import java.io.IOException;
    import java.util.Date;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.ws.client.core.WebServiceTemplate;
    import org.springframework.ws.soap.client.SoapFaultClientException;
    
    public class InvoiceCountRequestTest {
    
    	private WebServiceTemplate webServiceTemplate;
    
    	public void setWebServiceTemplate(WebServiceTemplate webServiceTemplate) {
    		this.webServiceTemplate = webServiceTemplate;
    	}
    
    	public void request() throws IOException {
    
    		try {
    			InvoiceCountRequest request = new InvoiceCountRequest();
    			request.setAccountId(5);
    			request.setFromDate(new Date());
    			request.setKey("5555");
    			request.setToDate(new Date());
    			request.getCodes().add("cld");
    			InvoiceCountResponse response = (InvoiceCountResponse) webServiceTemplate
    					.marshalSendAndReceive(request);
    
    			System.out.println("result: " + response);
    		} catch (SoapFaultClientException e) {
    			e.printStackTrace();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	public static void main(String[] args) throws IOException {
    
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    				"applicationContext.xml", InvoiceCountRequestTest.class);
    		InvoiceCountRequestTest echoClient = (InvoiceCountRequestTest) applicationContext
    				.getBean("client");
    		echoClient.request();
    	}
    
    }
    Thank You,
    Arun P Johny

  • #2
    Hi

    Could you send your spring configuration? At first glance - you say you use XPathParamAnnotationMethodEndpointAdapter but you should use org.springframework.ws.server.endpoint.adapter.Gen ericMarshallingMethodEndpointAdapter.

    @PayloadRoot annotation is handled by org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping, but parameters are handled by endpoint adapter. Your endpoint should not be invoked by XPathParamAnnotationMethodEndpointAdapter...

    regards
    Grzegorz Grzybek

    Comment


    • #3
      Originally posted by Grzegorz Grzybek View Post
      Hi

      Could you send your spring configuration? At first glance - you say you use XPathParamAnnotationMethodEndpointAdapter but you should use org.springframework.ws.server.endpoint.adapter.Gen ericMarshallingMethodEndpointAdapter.

      @PayloadRoot annotation is handled by org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping, but parameters are handled by endpoint adapter. Your endpoint should not be invoked by XPathParamAnnotationMethodEndpointAdapter...

      regards
      Grzegorz Grzybek
      Hi,

      Thanks for your reply.

      Sorry I think I made a mistake related to the endPoint adapter. The adapter used is "MarshallingMethodEndpointAdapter".

      Here is my spring configuration file
      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      
      <beans xmlns="http://www.springframework.org/schema/beans"
      	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
      	xmlns:tx="http://www.springframework.org/schema/tx"
      	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
      		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
      		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
      
      	<context:annotation-config />
      	<context:component-scan base-package="com.apj.cougar.ws" />
      
      	<!-- Spring Web Service Configurations -->
      
      	<!-- Web service request mapping for messageDispatcher -->
      	<bean name="/go.gws" id="messageDispatcher"
      		class="org.springframework.ws.soap.server.SoapMessageDispatcher" />
      
      	<bean id="messageFactory"
      		class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
      		<property name="payloadCaching" value="true" />
      	</bean>
      
      	<bean
      		class="org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter">
      		<property name="messageFactory" ref="messageFactory" />
      	</bean>
      	<bean
      		class="org.springframework.ws.transport.http.WsdlDefinitionHandlerAdapter">
      	</bean>
      	<bean class="org.springframework.ws.transport.http.XsdSchemaHandlerAdapter">
      	</bean>
      
      	<!-- Used to load the annotated end points -->
      	<bean
      		class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
      		<property name="interceptors">
      			<list>
      				<ref bean="loggingInterceptor" />
      				<ref bean="wsSecurityInterceptor" />
      			</list>
      		</property>
      	</bean>
      
      
      	<!-- WS request handling adapters used by messageDispatcher -->
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.MessageMethodEndpointAdapter"></bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.MessageEndpointAdapter"></bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter"></bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.MessageMethodEndpointAdapter"></bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.PayloadMethodEndpointAdapter"></bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.XPathParamAnnotationMethodEndpointAdapter">
      	</bean>
      
      	<!-- Security -->
      	<bean id="wsSecurityInterceptor"
      		class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
      		<property name="validationActions" value="UsernameToken" />
      		<property name="validationCallbackHandler">
      			<bean
      				class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
      				<property name="users">
      					<props>
      						<prop key="Bert">Ernie</prop>
      					</props>
      				</property>
      			</bean>
      		</property>
      	</bean>
      
      	<!-- Logging -->
      	<bean id="loggingInterceptor"
      		class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor" />
      
      	<!-- Exception resolver -->
      	<bean id="springWsExceptionResolver"
      		class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
      		<property name="order" value="2" />
      		<property name="defaultFault" value="SERVER" />
      		<property name="exceptionMappings">
      			<props>
      				<prop key="org.springframework.oxm.ValidationFailureException">CLIENT,Invalid request modified</prop>
      			</props>
      		</property>
      	</bean>
      	<bean id="springWsAnnatationExceptionResolver"
      		class="org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver">
      		<property name="order" value="1" />
      		<property name="defaultFault" value="SERVER" />
      	</bean>
      
      
      	<!-- Spring Web Service clients -->
      
      	<!-- epicAdmin -->
      	<bean id="epicAdminSSecurityInterceptor"
      		class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
      		<property name="securementActions" value="UsernameToken" />
      		<property name="securementUsername" value="${gws.epicAdmin.username}" />
      		<property name="securementPassword" value="${gws.epicAdmin.password}" />
      	</bean>
      	<bean id="epicAdminJaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
      		<property name="contextPath" value="com.apj.cougar.ws.admin.model" />
      	</bean>
      	<bean id="epicAdminWebServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
      		<constructor-arg ref="messageFactory" />
      		<property name="marshaller" ref="epicAdminJaxb2Marshaller" />
      		<property name="unmarshaller" ref="epicAdminJaxb2Marshaller" />
      		<property name="messageSender">
      			<bean
      				class="org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender">
      				<property name="hostnameVerifier">
      					<bean class="com.apj.common.http.TrustAllHostNameVerifier"></bean>
      				</property>
      				<property name="trustManagers">
      					<list>
      						<bean class="com.apj.common.http.TrustAllX509TrustManager"></bean>
      					</list>
      				</property>
      			</bean>
      		</property>
      		<property name="defaultUri" value="${gws.epicAdmin.default.uri}" />
      		<property name="interceptors">
      			<list>
      				<ref bean="epicAdminSSecurityInterceptor" />
      			</list>
      		</property>
      	</bean>
      
      	<!-- Spring Web Service definitions -->
      	<bean name="/ws/invoice-ops.wsdl"
      		class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
      		<property name="schema">
      			<bean class="org.springframework.xml.xsd.SimpleXsdSchema">
      				<property name="xsd" value="classpath:/gws/invoice-ws.xsd" />
      			</bean>
      		</property>
      		<property name="portTypeName" value="adminOpsService" />
      		<property name="serviceName" value="adminOpsService" />
      		<property name="locationUri" value="http://apj.com/invoice-ops/ws" />
      	</bean>
      	<bean id="invoiceJaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
      		<property name="contextPaths">
      			<list>
      				<value>com.apj.common.ws.model</value>
      				<value>com.apj.cougar.ws.invoice.model</value>
      			</list>
      		</property>
      	</bean>
      	<bean
      		class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
      		<description>Enables the MessageDispatchServlet to invoke methods
      			requiring OXM marshalling.</description>
      		<property name="marshaller" ref="invoiceJaxb2Marshaller" />
      		<property name="unmarshaller" ref="invoiceJaxb2Marshaller" />
      	</bean>
      </beans>
      This file contains all the configurations used by the spring-ws. I've other configuration files which deals with Spring MVC/Service/Dao layers.

      With Regards,
      Arun P Johny
      Last edited by arunpjohny; Sep 24th, 2010, 11:05 PM. Reason: Clarification

      Comment


      • #4
        Hi

        It would be much easier if you could send me your zipped project to let me run it on my machine. Don't send WEB-INF/lib/*.jars. If you can't send it, I'll find some time to recreate your problems locally.

        regards
        Grzegorz Grzybek

        Comment


        • #5
          Sample Source Code

          Originally posted by Grzegorz Grzybek View Post
          Hi

          It would be much easier if you could send me your zipped project to let me run it on my machine. Don't send WEB-INF/lib/*.jars. If you can't send it, I'll find some time to recreate your problems locally.

          regards
          Grzegorz Grzybek
          Thanks for spending your time on this issue.

          I've created a sample project in github. Please find the project here. You can download the project by clicking here.

          The github project has two branches master(with referenced libraries) and without-lib(without referenced libraries).

          Comment


          • #6
            Hi

            Thanks for the git repository link! SpringWS was not invoking your Endpoint, because JAXB2 unmarshaller returned not InvoiceCountRequest but JAXBElement<InvoiceCountRequest>... That's because of your ObjectFactory class generated by xjc.

            Another method of letting JAXBContext know what are its managed classes is to use jaxb.index file.

            So - working solution for your project is to delete ObjectFactory class and create jaxb.index file in the same location with the following content:
            Code:
            InvoiceCountRequest
            InvoiceCountResponse
            And then everything will work fine

            regards
            Grzegorz Grzybek

            Comment


            • #7
              Originally posted by Grzegorz Grzybek View Post
              Hi

              Thanks for the git repository link! SpringWS was not invoking your Endpoint, because JAXB2 unmarshaller returned not InvoiceCountRequest but JAXBElement<InvoiceCountRequest>... That's because of your ObjectFactory class generated by xjc.

              Another method of letting JAXBContext know what are its managed classes is to use jaxb.index file.

              So - working solution for your project is to delete ObjectFactory class and create jaxb.index file in the same location with the following content:
              Code:
              InvoiceCountRequest
              InvoiceCountResponse
              And then everything will work fine

              regards
              Grzegorz Grzybek
              Does it means that we should not be using the ObjectFactory instead we should be using obly jaxb.index.

              In my second sample I'd used jaxb.index instead of ObjectFactory. Then when we should be using ObjectFactory?
              Is it possible to configure the xjc to create the model objects I want(ie returns InvoiceCountRequest) instead of JAXBElement<InvoiceCountRequest>?
              Last edited by arunpjohny; Sep 28th, 2010, 03:50 AM.

              Comment


              • #8
                Hi

                In my second sample I'd used jaxb.index instead of ObjectFactory. Then when we should be using ObjectFactory?
                Is it possible to configure the xjc to create the model objects I want(ie returns InvoiceCountRequest) instead of JAXBElement<InvoiceCountRequest>?
                The use of ObjectFactory is creating objects for XML Schema declarations. XSD consists mainly of xsd:elements and xsd:complexTypes. ComplexType maps directly to Java class - creating object is easy - use "new", but there may be many xsd:elements referring to the same xsd:complexType and distinguished by name - so JAXBElement<T> must be used. ObjectFactory makes it easier to create these objects. And JAXB runtime makes use of the ObjectFactory if it finds one.

                But we have to prevent this behavior - by using plain jaxb.index. So JAXB will unmarshall "complexTypes" as plain objects instead of JAXBElements.

                I'm not sure whether my explanation fits the intentions of JAXB creators, but in practice - it works.

                regards
                Grzegorz Grzybek

                Comment


                • #9
                  Originally posted by Grzegorz Grzybek View Post
                  Hi



                  The use of ObjectFactory is creating objects for XML Schema declarations. XSD consists mainly of xsd:elements and xsd:complexTypes. ComplexType maps directly to Java class - creating object is easy - use "new", but there may be many xsd:elements referring to the same xsd:complexType and distinguished by name - so JAXBElement<T> must be used. ObjectFactory makes it easier to create these objects. And JAXB runtime makes use of the ObjectFactory if it finds one.

                  But we have to prevent this behavior - by using plain jaxb.index. So JAXB will unmarshall "complexTypes" as plain objects instead of JAXBElements.

                  I'm not sure whether my explanation fits the intentions of JAXB creators, but in practice - it works.

                  regards
                  Grzegorz Grzybek
                  Hi,

                  Thank you for your support and time.

                  Comment

                  Working...
                  X