Results 1 to 8 of 8

Thread: Multiple jibx marshallers/unmarshallers

  1. #1
    Join Date
    Dec 2005
    Posts
    3

    Default Multiple jibx marshallers/unmarshallers

    Hi,

    I've just been able to set up a ws using jibx as the oxm solution. However I only did one "simple" case with one request object and one response defined.

    Here are the marshallers that I have defined.

    Code:
    	<bean id="jibxMyRequestUnmarshaller"
    		class="org.springframework.oxm.jibx.JibxMarshaller">
    		<property name="targetClass"><value>com.example.ws.MyRequest</value></property>
    	</bean>
    	<bean id="jibxMyResponseMarshaller"
    		class="org.springframework.oxm.jibx.JibxMarshaller">
    		<property name="targetClass"><value>com.example.ws.MyResponse</value></property>
    	</bean>
    And then referenced in the endpoint adapter in the order (marshaller, unmarshaller) :

    Code:
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <description>
            </description>
            <constructor-arg ref="jibxMyResponseMarshaller"/>
            <constructor-arg ref="jibxMyRequestUnmarshaller"/>
        </bean>
    This is working. But, as I'm working with the PayloadRootAnnotationMethodEndpointMapping to have multiple service methods/operations in the same class, each having their own xxxRequest/xxxResponse pair, I don't see clearly where I will have to declare the marshallers/unmarshallers for these objects ?

    Based on the config above, could anybody adapt it to make it able to handle the marshalling of MySecondRequest/MySecondResponse alongside the MyRequest/MyResponse ?


    I guess it can't be this :

    Code:
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <description>
            </description>
            <constructor-arg ref="jibxMyResponseMarshaller"/>
            <constructor-arg ref="jibxMyRequestUnmarshaller"/>
            <constructor-arg ref="jibxMySecondResponseMarshaller"/>
            <constructor-arg ref="jibxMySecondRequestUnmarshaller"/>
        </bean>
    since, if I remember the source well, there is only a constructor that takes a marshaller and another one that takes one marshaller with one unmarshaller.

    Thanks for your help

  2. #2
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    This is an issue I hadn't thought about earlier. Unfortunately, it is not an easy one to solve. The JibxMarshaller can't handle multiple objects, which make it less suitable to use in combination with the MarshallingMethodEndpointAdapter.

    Unfortunately, I don't see a nice way out of this. The only option I see is to not use the MarshallingMethodEndpointAdapter, but to create separate subclasses AbstractMarshallingEndpoints for each request/response pair. The AbstractMarshallingEndpoint only handles one request/response, and not multiple ones, so it does not have the same problem.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  3. #3
    Join Date
    Dec 2005
    Posts
    3

    Default

    Ok, thanks for the quick reply.

    I think I'll apply the workaround your propose.

    Any chance to be able to do this in the future ? You said you hadn't thought about it, but i'm still interested in your opinion about this usage of the combination jibx/MarshallingMethodEndpoint (good/bad idea/practice ) ?

    If it does have potential, maybe I can try to have a look at the JibxMarshaller source and see if it could be extended ?

  4. #4
    Join Date
    Jul 2005
    Location
    Rotterdam, the Netherlands
    Posts
    1,562

    Default

    The way Jibx is designed results in a marshaller that is preconfigured for a particular class/xml stream. This preconfiguration is one of the reasons JiBX is so fast.

    So you could make the marshaller more generic, but that would probably make it slower. Especially in the case of unmarshalling: you have to peek in the XML stream, determine which Jibx IMarshallingContext matches it, and use that context to unmarshal the stream.

    I am reluctant to put this feature in Spring-WS, because it is quite fragile, and also because I believe it should be added to the Jibx codebase, and not Spring-WS.
    Arjen Poutsma

    Spring Web Services Dev Lead
    Please read the FAQ

  5. #5
    Join Date
    Feb 2009
    Location
    London
    Posts
    128

    Default

    Guys,
    anyone got solution to handle multiple objects for different request/responses.. I am struggling to have the same. I have diffrent pair of reqesut/response and If i have multiple <oxm:jibx-marshaller> with different targetClass values then also it does not work.....

  6. #6
    Join Date
    Feb 2008
    Posts
    5

    Default Multiple jibx marshallers/unmarshallers - Fix

    Arjen,

    I also have the requirement to be able to bind multiple jibx request/response objects when using the @Endpoint annotations in my service class. Below is the configuration I tried using Spring-WS 1.5.9 and Jibx 1.2.2:

    Code:
    <!-- Service endpoint class -->
    <bean id="policyService" class="com.amfam.policyservice.PolicyService" />
    
    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />
    
    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
         <constructor-arg ref="pingMarsheller" />
         <constructor-arg ref="pingUnmarsheller" />
    </bean>	
    	
    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
         <constructor-arg ref="retrieveSummaryMarsheller" />
         <constructor-arg ref="retrieveSummaryUnmarsheller" />
    </bean>
        
    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
         <constructor-arg ref="retrievePolicyMarsheller" />
         <constructor-arg ref="retrievePolicyUnmarsheller" />
    </bean>
    	
    <!-- Jibx marshellers -->
    <oxm:jibx-marshaller id="pingUnmarsheller" target-class="com.amfam.policyservice.domain.Ping" bindingName="ping" />
    <oxm:jibx-marshaller id="pingMarsheller" target-class="com.amfam.policyservice.domain.PingResponse" bindingName="ping" />
        
    <oxm:jibx-marshaller id="retrieveSummaryUnmarsheller" target-class="com.amfam.policyservice.domain.RetrieveSummary" bindingName="retrieve_summary" />
    <oxm:jibx-marshaller id="retrieveSummaryMarsheller" target-class="com.amfam.policyservice.domain.RetrieveSummaryResponse" bindingName="retrieve_summary" />
    				
    <oxm:jibx-marshaller id="retrievePolicyUnmarsheller" target-class="com.amfam.policyservice.domain.RetrievePolicy" bindingName="retrieve_policy" />
    <oxm:jibx-marshaller id="retrievePolicyMarsheller" target-class="com.amfam.policyservice.domain.RetrievePolicyResponse" bindingName="retrieve_policy" />
    When I ran this configuration the retrieveSummary and retrievePolicy marshallers and unmarshellers would never be used. This was because the ping marsheller's and unmarsheller's supports method would match any of the bindings classes and it was configured as the first MarshellingMethodEndpointAdapter. Effectively the ping's MarshellingMethodEndpointAdapter would try to marshall/unmarshell any jibx class, acting as a catch all. The problem is the bindingFactory was still configured specifically for the 'ping' binding file so when the retrieveSummary operation is called the ping marsheller/unmarsheller tries to bind the retrieveSummary xml element and fails with the following message:

    Code:
    <soapenv:Fault>
         <faultcode>soapenv:Server</faultcode>
         <faultstring xml:lang="en">JiBX unmarshalling exception: No unmarshaller for element "{http://schema.amfam.com/policyservice/v1}retrieveSummary" (line -1, col -1); nested exception is org.jibx.runtime.JiBXException: No unmarshaller for element "{http://schema.amfam.com/policyservice/v1}retrieveSummary" (line -1, col -1)</faultstring>
    </soapenv:Fault>
    Basically the wrong BindingFactory is being used to unmarshall the retrieveSummary element because the ping marsheller returned true from its supports method. After digging into it, I found the supports method was asking the BindingFactory which classes it can map. The problem is the BindingFactory is aware of all the compiled jibx classes not just the ones for the specific binding file it is configured to handle, in this case the ping binding file. Since the JibxMarsheller objects are configured with the root elements they need to map I wasn't sure why the BindingFactory was being asked at all. Why not simple compare the element trying to be bound to the classes already configured on the JibxMarsheller objects.

    To test my theory I copied the code from the JibxMarsheller class and created my own class. Then I change the supports method to this:

    Code:
    public boolean supports(Class clazz) {
         Assert.notNull(clazz, "'clazz' must not be null");
         return this.targetClass.equals(clazz);
    }
    Once I did this the correct JibxMarsheller was selected and therefore the correct BindingFactory configuration. I now have my service working with the @Endpoint annotation for multiple Jibx bindings. Here is what my configuration file looks like now. Mainly I had to change the oxm:jibx syntax back to standard Spring bean syntax to use my custom JibxMarshaller class.

    Code:
         <!-- Service endpoint class -->
        <bean id="policyService" class="com.amfam.policyservice.PolicyService" />
    
        <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />
    
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <constructor-arg ref="pingMarsheller" />
            <constructor-arg ref="pingUnmarsheller" />
        </bean>
    
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <constructor-arg ref="retrieveSummariesMarsheller" />
            <constructor-arg ref="retrieveSummariesUnmarsheller" />
        </bean>
    
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <constructor-arg ref="retrieveSummaryMarsheller" />
            <constructor-arg ref="retrieveSummaryUnmarsheller" />
        </bean>
    
        <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
            <constructor-arg ref="retrievePolicyMarsheller" />
            <constructor-arg ref="retrievePolicyUnmarsheller" />
        </bean>
    
        <!-- Jibx marshellers -->
        <bean id="pingUnmarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.Ping" />
            <property name="bindingName" value="ping" />
        </bean>
        <bean id="pingMarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.PingResponse" />
            <property name="bindingName" value="ping" />
        </bean>
    
        <bean id="retrieveSummaryUnmarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrieveSummary" />
            <property name="bindingName" value="retrieve_summary" />
        </bean>
        <bean id="retrieveSummaryMarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrieveSummaryResponse" />
            <property name="bindingName" value="retrieve_summary" />
        </bean>
    
        <bean id="retrieveSummariesUnmarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrieveSummaries" />
            <property name="bindingName" value="retrieve_summary" />
        </bean>
        <bean id="retrieveSummariesMarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrieveSummariesResponse" />
            <property name="bindingName" value="retrieve_summary" />
        </bean>
    
        <bean id="retrievePolicyUnmarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrievePolicy" />
            <property name="bindingName" value="retrieve_policy" />
        </bean>
        <bean id="retrievePolicyMarsheller" class="com.amfam.policyservice.JibxMarshaller">
            <property name="targetClass" value="com.amfam.policyservice.domain.RetrievePolicyResponse" />
            <property name="bindingName" value="retrieve_policy" />
        </bean>
    Is this a bug in JibxMarshaller or is the supports method written that way to handle some other scenario I am unaware of?

    Thanks,
    Josh
    Last edited by swanjr; Nov 23rd, 2010 at 08:29 AM.

  7. #7
    Join Date
    Mar 2012
    Posts
    1

    Default

    For those like me that are fighting with this issue (in my case, I'm using AnnotationMethodHandlerAdapter and I would like to integrate jibx by adding multiple MarshallingHttpMessageConverter converters), be aware that it has been fixed in the latest JibxMarshaller version (3.1.0.RELEASE). Now the supports method looks like:


    Code:
    	public boolean supports(Class<?> clazz) {
    		Assert.notNull(clazz, "'clazz' must not be null");
    		if (this.targetClass != null) {
    			return this.targetClass.equals(clazz);
    		}
    		String[] mappedClasses = this.bindingFactory.getMappedClasses();
    		String className = clazz.getName();
    		for (String mappedClass : mappedClasses) {
    			if (className.equals(mappedClass)) {
    				return true;
    			}
    		}
    		return false;
    	}
    So there's no longer need to override this class (it was a pain, since targetClass and others are private...). And now we can make use of the short style (oxm:jibx-marshaller) to define them...

  8. #8

    Default

    Can you supply an example of how to use JiBX, along with @Endpoint and @PayloadRoot annotations?

    Thanks,

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •