Announcement Announcement Module
Collapse
No announcement yet.
Multiple jibx marshallers/unmarshallers Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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.

    Comment


    • #3
      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 ?

      Comment


      • #4
        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.

        Comment


        • #5
          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.....

          Comment


          • #6
            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, 08:29 AM.

            Comment


            • #7
              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...

              Comment


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

                Thanks,

                Comment

                Working...
                X