How can I change the port of a Spring JaxWs proxy? - spring

I have a working web service client based on Spring, defined as:
<bean id="myService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="wsdlDocumentUrl" value="classpath:/ex/MyService.wsdl" />
<property name="namespaceUri" value="http://ex.tld/namespace" />
<property name="serviceName" value="MyService" />
<property name="portName" value="MyServicePort01" />
<property name="serviceInterface" value="ex.MyService" />
</bean>
I need to access the same service on a list of different endpoints. Since the list is dynamic I cannot simply configure several Spring JaxWsPortProxy beans for this.
Can I change the binding dynamically? How can I solve this while still leveraging Spring facilities for WS clients?

I simply changed the endpoint address of the proxy:
((BindingProvider)myService).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://new/endpoint/address");
As seen above, the proxy that Spring returns can be casted to a BindingProvider (like a normal JaxWs proxy).
If someone adopts this, beware of synchronization issues.

I configured in xml, as you.
After, in postConsruct set endpoint, and call afterPropertiesSet:
#Autowired
private JaxWsPortProxyFactoryBean myService;
#PostConstruct
public void init() {
myService.setEndpointAddress("http://new/endpoint/address");
myService.afterPropertiesSet();
}

Related

Spring Framework 4.1 ignores custom Object Mapper in ContentNegotiation

I'm trying to upgrade to Spring 4.1.5.
I have a custom Object mapper defined like so
<bean id="apiObjectMapper" class="my.company.ApiObjectMapper" />
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
The object mapper itself looks like this:
public class ApiObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
public ApiObjectMapper() {
JaxbAnnotationModule module = new JaxbAnnotationModule();
module.setPriority(Priority.SECONDARY);
registerModule(module);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
}
The issue happens during content negotiation it seems
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorParameter" value="true" />
<property name="defaultContentType" value="text/xml" />
<property name="mediaTypes" >
<value>
json=application/json
xml=text/xml
</value>
</property>
</bean>
After upgrading, the object mapper is simply ignored. No Jaxb annotations are taken into account, NULLs appear.
Spring 4.0.9 works fine.
I tried Java Configuration with the same result.
Also tried configuring the new Jackson2ObjectMapperFactoryBean directly, but couldn't get the original behavior to happen either.
E.g.: Original output for an endpoint like "list.xml"
<result>
<typeB>
<itemA>...</itemA>
<itemB>...</itemB>
</typeB>
</result>
Now outputs (typeA is empty/null):
<result>
<typeA />
<typeB>
<itemA>...</itemA>
<itemB>...</itemB>
</typeB>
</result>
Any ideas?
I believe I found the culprit and fix for this issue.
When the content negotiation determines that the response should be serialized in JSON then org.springframework.http.converter.json.MappingJackson2HttpMessageConverter is used. However, if the response should be serialized in XML then org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter is used instead. Different message converter that will use a default object mapper if none is provided.
What I had to change was
public class ApiObjectMapper extends XmlMapper { // XmlMapper extends ObjectMapper
// same logic
}
and
<bean id="apiObjectMapper" class="my.company.ApiObjectMapper" />
<mvc:annotation-driven content-negotiation- manager="contentNegotiationManager">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
<!-- Added this bean configuration for XML serialization -->
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="apiObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
I have yet to find what changed in Spring Framework or Jackson to make this happen although my money is n the separation of Jackson XML handling into a different library (I'll update this answer once I do).
Hope it helps.
Leaving some more information for future reference.
Based on this Spring blog post, starting with Spring 4.1, Jackson XML is used to generate XML instead of Jaxb if the former is found on the classpath. That's the main reason for the output to change, because the library generating it changed.
Now after some trial and error, getting Jackson XML to generate the same output as Jaxb is quite the endeavour. Instead you could just remove all references to Jackson XML (not Jackson itself) and everything should work the same way it worked before.

OpenEntityManagerInViewInterceptor for CXF

I have a Web service application based on JPA (Hibernate), Spring and CXF.
I am facing some lazy-load exceptions after transactional business methods (because I need some extra beans to be rendered in the rpesentation layer), and I wanted to give a try to the OpenSession/EntityManagerInView pattern.
Please do not argue this choice, we are just giving it a try.
The issue is that, since I am using CXFServlet, instead of standard Spring Servlet, I cannot use OpenEntityManagerInViewFilter in web.xml.
I cannot use either OpenEntityManagerInViewInterceptor which applies as a WebRequest Interceptor (and does not work with CXF interceptor/filters).
Finally I am aware of the HibernateInterceptor, an AOP proxy which wraps any method into a session. But still : this one is for the Hibernate API, not JPA API (I am using EntityManagerFactory, rather than SessionFactory).
So, are you aware of either :
A HibernateInterceptor for the JPA API (EntityManagerInterceptor ?)
A way to adapt a Spring WebRequestInterceptor into a JAX-RSfilter ?
Any other solution ?
Thanks in advance for your help.
Once again, I finally found what I wanted ...
There is actually a JpaInterceptor that does what I want (it seems deprecated though. I do not really understand why).
Here is the resulting configuration that works like a charm, with a bit of auto proxy by name :
<bean id="jpaInterceptor" class="org.springframework.orm.jpa.JpaInterceptor">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="jpaAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
<property name="beanNames">
<list>
<value>myService1</value>
<value>myService2</value>
<value>...</value>
</list>
</property>
<property name="interceptorNames">
<list><value>jpaInterceptor</value></list>
</property>
</bean>
<jaxrs:server id="services" address="/">
<jaxrs:serviceBeans>
<ref bean="myService1" />
<ref bean="myService2" />
<ref bean="..." />
</jaxrs:serviceBeans>
</jaxrs:server>

spring web flow enable scopes

Spring web flow provides additional bean scopes like flow, conversation, flash etc. I can define flow scope beans in flow.xml using var or i can set values to new scoped variables. How i can define it in spring application context xml file. I tried to use this pattern:
<bean id="abc" class="abc" scope="flow"/>
I got error that no scope defined. I searched on google and found this thing
http://blog.springsource.org/2007/05/08/spring-web-flow-bean-scopes-and-jsf/
but don't know how to enable it in spring web flow 2.3
try to define it in your application context:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="flow">
<bean class="org.springframework.webflow.config.scope.FlowScope"/>
</entry>
</map>
</property>
</bean>

Blueprint CXF serviceFactories: Need an instance per request

I am using Apache Karaf, CXF, and Aries Blueprint.
I have a bundle which defines a number of JAX-RS services. By default, CXF will make these services singletons, but this will not work for me. I need a new instance to handle each request.
Referencing the CXF documentation, I tried to create JAX-RS ServiceFactories which return new instances of the services. The documentation had examples for Spring and I tried to Blueprint equivalent.
<reference id="groupService" interface="org.ozoneplatform.owf.server.service.api.GroupService"/>
<bean id="groups" class="org.ozoneplatform.owf.server.rest.GroupController" scope="prototype">
<property name="service" ref="groupService"/>
</bean>
<bean id="groupFactory" class="org.apache.cxf.blueprint.jaxrs.BlueprintResourceFactory">
<property name="beanId" value="groups" />
</bean>
<jaxrs:server id="ozoneplatform_cxf_endpoint" address="/owf">
<jaxrs:serviceFactories>
<ref bean="groupFactory" />
</jaxrs:serviceFactories>
Blueprint fails to start giving the error
org.osgi.service.blueprint.container.ComponentDefinitionException:
Error setting property: PropertyDescriptor <name: resourceProviders, getter: null, setter: [class org.apache.cxf.jaxrs.JAXRSServerFactoryBean.setResourceProviders(interface java.util.List)]
You must define "blueprintContainer" property for BlueprintResourceFactory instance as:
<bean id="groupFactory" class="org.apache.cxf.blueprint.jaxrs.BlueprintResourceFactory">
<property name="beanId" value="groups" />
<property name="blueprintContainer" ref="blueprintContainer"/>
</bean>
Where ref="blueprintContainer" is a reference to top-level manager (see 121.11 Blueprint Container)

How do I configure a Json provider for a JAX-RS test client using Spring?

I have set up a JAX-RS service using Apache CXF, which I would like to test using Apache CXF JAX-RS' Client API. The server has been configured to use Jackson as the json provider. Now I would like to do the same for the client: that is, letting Jacson handle the conversion to/from json.
Unfortunately I am unsure of how to "spring enable" the tests, having only superficial knowledge of Spring. I got away with programmatically setting up a provider in the test, but would like to know how to do it through Spring. So instead of
#BeforeClass
public static void setup() {
ProviderFactory.getSharedInstance().registerUserProvider(new JacksonJsonProvider());
}
I would want to just set it in springConfiguration.xml (or something like that :). When setting up the serverside, springConfiguration.xml looked like this.
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="echoService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
<jaxrs:extensionMappings>
<entry key="json" value="application/json"/>
</jaxrs:extensionMappings>
</jaxrs:server>
I tried to just add
<jaxrs:client id="restClient" >
<jaxrs:providers>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:client>
to springConfiguration.xml, but that did not do anything. No surprise, as I have not set up my JUnit tests to use Spring ... Could anyone tell me how to do this, or point me to any good resources with which I could assemble the necessary info?
The following annotations will load your application context prior to tests being run.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"applicationContext.xml"})
public class JaxRsTest {
#Autowired
MyBean myBean
public void testMyBean() {
//add some real tests here...
assertNotNull(myBean)
}
}

Resources