Unifying endpoints with different JSON providers in Apache CXF with Spring - spring

Background
We are using Apache CXF 2.5.x , JSR 311 1.1.1 , and Spring 2.5.x
We currently have 2 endpoints, ABC and DEF, that use Jackson as the JSON provider. Our Spring file looks something like:
<bean id="jacksonMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="jsonProvider"class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" p:mapper-ref="jacksonMapper"/>
<jaxrs:server id="service1" address="/">
<jaxrs:serviceBeans>
<ref bean="resourceABC" />
<ref bean="resourceDEF" />
</jaxrs:serviceBeans>
<jaxrs:providers >
<ref bean="jsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
Using annotations on the Java classes, these endpoints are available via http://company.com/api/rest/ABC and http://company.com/api/rest/DEF
Challenge
We want to introduce a new endpoint, IJK, that uses Gson as a JSON provider. We would like the endpoint to map to http://company.com/api/rest/IJK.
Note: Indeed, it is trivially easy to map to http://company.com/api/rest/new/IJK by using a different endpoint, but we'd like to avoid that.
Approaches
We've tried defining a new server with the same address:
<jaxrs:server id="service2" address="/">
<jaxrs:serviceBeans>
<ref bean="resourceIJK" />
</jaxrs:serviceBeans>
<jaxrs:providers >
<ref bean="gsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
but that doesn't work. We've tried using multiple providers in the same server element, but no dice.
This link discusses using serverFactories elements. Such as:
<beans>
<jaxrs:server id="customerService" address="/service1">
<jaxrs:serviceFactories>
<ref bean="sfactory1" />
<ref bean="sfactory2" />
</jaxrs:serviceFactories>
</jaxrs:server>
<bean id="sfactory1" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
<property name="beanId" value="customerBean1"/>
</bean>
<bean id="sfactory2" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
<property name="beanId" value="customerBean2"/>
</bean>
<bean id="customerBean1" class="demo.jaxrs.server.CustomerRootResource1" scope="prototype"/>
<bean id="customerBean2" class="demo.jaxrs.server.CustomerRootResource2" scope="prototype"/>
</beans>
This looks promising, but how to set the JSON provider for the services, customerBean1 and customerBean2 in Spring?
Question
Can someone clarify the last approach above, with serviceFactories? Can we achieve the goal of introducing resourceIJK (at the same endpoint root) with Gson instead of Jackson?
If it can be done only with Apache CXF 2.7, that is OK and useful info.

Related

Connecting to multiple ActiveMQ Servers using Spring Integration XML Configuration

I have been trying for couple days to set up multiple ActiveMQ connections in Spring Integration using XML configuration.
I am using spring boot, SI looks for a bean called jmsConnectionFactory in the context and uses it. But what if I have to send/listen to jms messages from/to different ActiveMQ servers?
What I have right now is this:
<bean id="jmsConnectionFactory1"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
</property>
<property name="sessionCacheSize" value="10" />
<property name="cacheConsumers" value="false" />
</bean>
<bean id="jmsConnectionFactory2"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.1.59:61616" />
</bean>
</property>
<property name="sessionCacheSize" value="10" />
<property name="cacheConsumers" value="false" />
</bean>
...
<jms:message-driven-channel-adapter channel="jmsInChannel" destination-name="queue.demo" />
<int:channel id="jmsInChannel" />
...
When trying to start the spring boot app I get this error:
***************************
APPLICATION FAILED TO START
***************************
Description:
A component required a bean named 'jmsConnectionFactory' that could not be found.
The following candidates were found but could not be injected:
- Bean method 'jmsConnectionFactory' in 'ActiveMQXAConnectionFactoryConfiguration' not loaded because #ConditionalOnClass did not find required class 'javax.transaction.TransactionManager'
Action:
Consider revisiting the entries above or defining a bean named 'jmsConnectionFactory' in your configuration.
I came across this solution, https://stackoverflow.com/a/43401330/3367392 it's a java configuration. Also I looked into this but it's using camel https://stackoverflow.com/a/13288312/3367392
Is there a way to achieve the same for Spring Integration using XML configuration?
Ok so I got it, for a simple case I just had to add the right connectionFactory to the adapters like this
<jms:message-driven-channel-adapter channel="jmsInChannel"
destination-name="queue.demo"
connection-factory="jmsConnectionFactory1" />

How to internationalize REST Spring-MVC application?

I am new with spring and I still don't know well about hierarchy and terminology of spring. I am implementing a RESTful app with spring. After searching and reading about how to internationalize spring, I tried to do it in my app. But it seems to me it is not configured properly. Because I get exception. I would like to show you the screenshot of my project structure. And I would like to ask you why my applicationContext.xml show a problem exist.
spring-servlet.xml
<!-- SPRING INTERNALIZATION CONFIGURATION -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
The javadoc of ReloadableResourceBundleMessageSource.setBaseNames() says:
Set an array of basenames, each following the basic ResourceBundle convention of not specifying file extension or language codes, but in contrast to ResourceBundleMessageSource referring to a Spring resource location: e.g. "WEB-INF/messages" for "WEB-INF/messages.properties", "WEB-INF/messages_en.properties", etc.
But you've placed your message properties files under src/main/resources in the Maven project structure, so they will end up at the root of the classpath instead (which means that even if Spring looked for them in the classpath, the /resources prefix you've used in the configuration would prevent Spring to find them).
So place the properties file under WEB-INF, and use WEB-INF/messages as the basenames property.

Spring - Jaxb2Marshaller - How to Automatically Add JAXB2 Classes using Annotations

I am using Spring 3.1.x and CXF 2.6.1 for REST services. I using jaxbXmlProvider as shown below.
<jaxrs:server ...
<jaxrs:providers>
<ref bean="jaxbXmlProvider" />
</jaxrs:providers>
...
</jaxrs:server>
<bean id="jaxbXmlProvider" class="org.apache.cxf.jaxrs.provider.JAXBElementProvider">
<property name="jaxbElementClassNames" ref="elements" />
</bean>
<util:list id="elements">
<value>com.model.City</value>
<value>com.model.Cities</value>
</util:list>
I would like to use jaxb2-marshaller for scanning all the POJOS in a package(com.model). Any usage help is appreciated.
You can call a method of another bean that provides the list of classes something like:
<property name="jaxbElementClassNames" value="#{ myBean.classNamesFromPackage}"/>
Configure myBean that takes package name as a property and has getClassNamesFromPackage method:
<bean id="myBean" class="x.y.z.MyBean">
<property name="packageName" value="com.model" />
</bean>
In getClassNamesFromPackage method of MyBean, you can use the code suggested in How do I read all classes from a Java package in the classpath?.

Spring "XStreamMarshaller" is failing to identify the Java class for mapping to XML while unmarshalling

Recently facing an issue with XStream which i'm using with Spring. We have a REST application where we are using XStream for marshalling & unmarshalling XML.
We have configured as shown below,
<bean id="xStreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="annotatedClasses">
<list><value>com.bestbuy.commerce.repobjects.OfflineOrderRepresentation</value></list>
</property>
<property name="autodetectAnnotations" value="true" />
</bean>
And this XStreamMarshaller is configured to HttpMessageconverter as shown,
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xStreamMarshaller" />
<property name="unmarshaller" ref="xStreamMarshaller" />
</bean>
</util:list>
</property>
</bean>
The issue here is when i post proper XML it should match to it's corresponding XStream annotated class "OfflineOrderRepresentation",
but that is happening randomly, some times i'm getting syntactically incorrect message, and issue is getting fixed randomly if i restart the server.
Below is the error logs i'm getting,
[org.springframework.http.converter.xml.MarshallingHttpMessageConverter#712625b0]
[org.springframework.web.bind.annotation.support.HandlerMethodInvoker]
Reading [com.bestbuy.commerce.repobjects.OfflineOrderRepresentation]
[org.springframework.http.converter.xml.MarshallingHttpMessageConverter#712625b0]
[org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver]
[com.bestbuy.commerce.controllers.OrderController#799a92d1]:
org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.bestbuy.commerce.repobjects.OfflineOrderRepresentation];

Issue with Spring Method interceptor

I'm having an issue with using Spring interceptor. I've a CXF service endpoint method which I'm trying a wrap with an interceptor to do some initialization. For some reason, the interceptor is not being invoked. Here's my spring entry:
<jaxrs:server id="acadConnectServer" address="/rest/acadconnect3">
<jaxrs:serviceBeans>
<ref bean="acadConnectResource" />
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="acadConnectResource"
class="com.test.connectchannel.service.AcadConnectChannelResource" />
<bean id="connectResource" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="acadConnectResource" />
<property name="interceptorNames">
<list>
<value>methodPointCut</value>
</list>
</property>
</bean>
<bean id="methodPointCut"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice">
<ref local="methodInterceptor" />
</property>
<property name="mappedNames">
<list>
<value>search</value>
<value>searchJSONP</value>
</list>
</property>
</bean>
<bean id="methodInterceptor"
class="com.test.connectchannel.util.ConnectChannelInterceptor">
</bean>
As you can see, I've a CXF endpoint class AcadConnectChannelResource which has couple of methods search and searchJSONp. I've created the Named Method Cut interceptor to intercept these two method calls and so some initialization using the custom intercetor class.But, everytime the methods are invoked, the interceptor is not being called.
Not sure what I'm missing here, any pointer will be appreciated.
-Thanks
I might be entirely wrong, but don't you want
<ref bean="connectResource" />
instead of
<ref bean="acadConnectResource" />
in your <jaxrs:server>? You're proxying the resource, but using the raw resource instead of the proxy.

Resources