Reputation: 679
I am using the Spring framework.
I have multiple mashallers and multiple endpoints. The Jaxb context for my marshallers are defined with xml-binding files (using the eclipselink-oxm-xml jaxbContextProperties) since I have multiple marshalling tasks. Using annotations was not a good solution because the same object requires a different marshalling/unmarshalling procedure depending on endpoint.
My configuration at the moment for a single JaxbMarshaller and Endpoint looks like so:
<sws:annotation-driven marshaller="marshallerA" unmarshaller="marshallerA"/>
<bean id="loggingInterceptor"
class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
<bean id="messageReceiver"
class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointAdapters">
<list>
<ref bean="defaultMethodEndpointAdapter" />
</list>
</property>
</bean>
<bean id="defaultMethodEndpointAdapter"
class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter">
<property name="methodReturnValueHandlers">
<list>
<ref bean="marshallingPayloadMethodProcessor"/>
</list>
</property>
<property name="methodArgumentResolvers">
<list>
<ref bean="marshallingPayloadMethodProcessor"/>
</list>
</property>
</bean>
<bean id="marshallingPayloadMethodProcessor"
class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
<constructor-arg ref="marshallerA" />
<constructor-arg ref="marshallerA" />
</bean>
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="order" value="1" />
</bean>
<sws:dynamic-wsdl id="myEndpointA"
portTypeName="WebService"
locationUri="/ws/myEndpointServiceA/"
targetNamespace="http://company.com/schema/webServices" >
<sws:xsd location="classpath:/path/to/schema/mySchemaA.xsd"/>
</sws:dynamic-wsdl>
<bean id="marshallerA" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="x.y.z:x.y.w"/>
<property name="jaxbContextProperties">
<util:map>
<entry key="eclipselink-oxm-xml">
<list>
<value>file:/bindingFileOne.xml</value>
<value>file:/bindingFileTwo.xml</value>
<value>file:/bindingFileThree.xml</value>
</list>
</entry>
</util:map>
</property>
</bean>
Now say I have a second endpoint and a second marshaller, how can I force an Endpoint to use a specific marshaller?
Thanks for any help! :)
Upvotes: 1
Views: 1861
Reputation: 19050
Just clarifying some points of the accepted answer, you can make the reference do the Endpoint just receiving as parameter the endpoint, like a normal bean:
@Bean
public SpecificEndpointAdapter csvEndpointAdapter(MyEndpoint myEndpoint) {
List<MethodArgumentResolver> argumentResolvers =
new ArrayList<>();
argumentResolvers.add(methodProcessor());
List<MethodReturnValueHandler> returnValueHandlers =
new ArrayList<>();
returnValueHandlers.add(methodProcessor());
SpecificEndpointAdapter specificEndpointAdapter = new SpecificEndpointAdapter();
specificEndpointAdapter.setMethodArgumentResolvers(argumentResolvers);
specificEndpointAdapter.setMethodReturnValueHandlers(returnValueHandlers);
specificEndpointAdapter.setAcceptedEndpoints(Arrays.asList(myEndpoint));
return specificEndpointAdapter;
}
private MarshallingPayloadMethodProcessor methodProcessor() {
return new MarshallingPayloadMethodProcessor(marshaller());
}
private Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.company.application");
marshaller.setMtomEnabled(true);
return marshaller;
}
The MyEndpoint
:
@Endpoint
public class MyEndpoint {
//...
}
Upvotes: 0
Reputation: 679
I ended up extending the DefaultMethodEndpointAdapter, creating SpecificEndpointAdapter. I only need to override one method, the implementation is as follows:
public class SpecificEndpointAdapter extends DefaultMethodEndpointAdapter {
private List<Object> acceptedEndpoints;
public void setAcceptedEndpoints(List<Object> acceptedEndpoints) {
this.acceptedEndpoints = acceptedEndpoints;
}
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
if(acceptedEndpoints.contains(methodEndpoint.getBean()))
return super.supportsInternal(methodEndpoint);
return false;
}
}
In my context file, this allows me to restrict an endpoint adapter to a specific endpoint, thus having a specific marshaller:
<bean id="serviceAEndpointAdapter" class="my.package.SpecificEndpointAdapter">
<property name="acceptedEndpoints">
<list>
<ref bean="serviceAEndpoint"/>
</list>
</property>
<property name="methodReturnValueHandlers">
<list>
<ref bean="serviceA.marshallingPayloadMethodProcessor"/>
</list>
</property>
<property name="methodArgumentResolvers">
<list>
<ref bean="serviceA.marshallingPayloadMethodProcessor"/>
</list>
</property>
</bean>
<bean id="serviceBEndpointAdapter" class="my.package.SpecificEndpointAdapter">
<property name="acceptedEndpoints">
<list>
<ref bean="serviceBEndpoint"/>
</list>
</property>
<property name="methodReturnValueHandlers">
<list>
<ref bean="serviceB.marshallingPayloadMethodProcessor"/>
</list>
</property>
<property name="methodArgumentResolvers">
<list>
<ref bean="serviceB.marshallingPayloadMethodProcessor"/>
</list>
</property>
</bean>
In my MarhsallingPayloadProcessor I can now declare which marshaller to use. Note that I ended up using the bean id as the SpecificEndpointAdapter reference, so if you are using annotations, you will need to figure out the bean id of that endpoint.
I hope this helps anyone who was facing the same issue, let me know if the answer requires more clarification.
Upvotes: 1