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