CXF is ignoring Spring bean configuration - java

I have a web application which is exposing a rest web service by cxf jax-rs. In my application context file I have something like this:
...
<bean id="service" class="SomeClass">
<constructor-arg index="0">
<ref bean="bean1" />
</constructor-arg>
<constructor-arg index="1"
value="some value" />
</bean>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="service" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
...
I also have a constructor in my service class that accepts those two parameters and initializes the service.
When I deploy my application, spring context loader is creating the service bean correctly and the correct constructor is getting called. The problem is when the first Rest request comes to service. Cxf Jax-rs is creating its own instance by "default constructor" and I will lose those two properties.
The same thing happens if I user property setters instead of constructor args. When I researched cxf jax-rs, none of the examples had a service which has some properties! Is there a reason for this or is this some implementation constraint by cxf?
Any ideas?

Related

RMI with Spring and AOP

I am trying to implement a Spring application with RMI and AOP. I am having problems with my server component. If the service interface which i want to expose does not extend Remote and the methods do not throw an RemoteException, I am getting the error:
UnknownAdviceTypeException: Advice object [org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#1f90645] is neither a supported subinterface of [org.aopalliance.aop.Advice] nor an [org.springframework.aop.Advisor]
if the interface extends Remote it works just fine with starting and so on.
My application.xml has only one bean declared:
<bean id="testService" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="TestService" />
<property name="service" ref="testServiceImpl"/>
<property name="serviceInterface"
value="xxx.service.TestService" />
</bean>
My interface only has the #Transactional annotation, while the implementation has the #Service annotation.
In my client i get errors as well. Here i get an error of a not unique bean: found bean testService and testServiceImpl. My client.xml looks like this:
<bean class="xxx.start.Client">
<property name="testService" ref="testService"/>
</bean>
<bean id="testService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:1099/TestService"/>
<property name="serviceInterface" value="xxx.service.TestService"/>
</bean>
I followed this guide, but go the errors above. If you could help me id be very glad. If i run my JUnit test without RMI, its working all fine
i found out why it throws the error. it was because i had default-autowiring set to byType, but the RmiServiceExporter should have autowire=no

Cxf Failure Interceptor for one service bean in multi-bean service

I've a declaration in spring two services which are deployed on the same address. I would like to declare failure interceptor for only one of them, but is there a easy way to do that without changing address for two services? I would like to have them on the same address.
<jaxrs:server id="service" address="http://0.0.0.0:${service.port:7070}/">
<jaxrs:serviceBeans>
<ref bean="firstService"/>
<ref bean="secondService"/>
</jaxrs:serviceBeans>
<jaxrs:outInterceptors>
<ref bean="failureInterceptor" />
</jaxrs:outInterceptors>
<jaxrs:features>
<cxf:logging/>
<ref bean="commonValidationFeature"/>
</jaxrs:features>
<jaxrs:providers>
<ref bean="jsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
You can declare two jax-rs server, each one with its own interceptor if you could adapt slightly the relative path of the services
For example, you can use both equivalently
<jaxrs:server id="ServiceAImpl" address="/test/a">
<jaxrs:server id="ServiceBImpl" address="/test/b">
<jaxrs:server id="serviceImpl" address="/test">
<jaxrs:serviceBeans>
<ref bean="serviceABean"/> <!-- /test/a service -->
<ref bean="serviceBBean"/> <!-- /test/b service -->
but it is not allowed
<jaxrs:server id="ServiceAImpl" address="/test">
<jaxrs:server id="ServiceBImpl" address="/test">
If it is not possible for you, you could determine at interceptor which is the source service bean ( analysing method name or uri) and fire the especific interceptor manager

Preferred Semantics for CXF JAX-RS

I was wondering what the preferred semantics are for jaxrs:server configurations in a CXF XML context file.
For example, if I have two service implementations for users and orders, and they're accessible from a relative path "/user" and "/order".
Would I configure the services this way:
<jaxrs:server id="userService" address="/user">
<jaxrs:serviceBeans>
<bean class="com.example.UserServiceImpl />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<jaxrs:server id="orderService" address="/order">
<jaxrs:serviceBeans>
<bean class="com.example.OrderServiceImpl />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
Or this way:
<jaxrs:server id="appService" address="/">
<jaxrs:serviceBeans>
<!--
Path configured using #Path annotations on the class definition:
#Path(value="/user")
public class UserServiceImpl {...}
-->
<bean class="com.example.UserServiceImpl />
<bean class="com.example.OrderServiceImpl />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
It seems like it's only a semantic difference. The second way allows us to not repeat the providers. But I was wondering what I should be considering when performing this configuration?
Thank you!
I use the second way and try to group services together if they relate... if you can get orders for specific user, then they relate. So I usually have one "v1" api server (versioning support), one for documentation of it (there I use different providers or extension mappings), one for specialized (like admin with more strict security) access, etc.
But i would use some address and not leave it empty, for example "api" or version "v1" at least.
In other way, your cxf.xml can be full of jaxrs servers. And if they relate, there is little chance that they will need different providers, mappings, extensions.
But this question is about opinion and perhaps will be closed.
I would usually group them if they have same base address
lets say we have resource URLs like this
<jaxrs:server id="userService" address="api/user">
</jaxrs:server>
<jaxrs:server id="orderService" address="api/order">
</jaxrs:server>
as
<jaxrs:server id="appService" address="/api">
<jaxrs:serviceBeans>
<!--
#Path(value="/user")
-->
<bean class="com.example.UserServiceImpl />
<bean class="com.example.OrderServiceImpl />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
and individually incase they have different Base URLs
like
/profile/user
/cart/orders

Alternate to #XmlRootElement?

in process of exposing existing statefull service as a RESTfull service.
I do not want to make any changes to any existing java class.I have been able to configure other annotations such as #path, #GET using spring-config.xml
spring-config.xml
<!-- Inquiry Services -->
<bean id="retrieveContactHistoryBP" class="com.csc.fs.ws.contact.history.impl.RetrieveContactHistoryBPService"/>
<!-- Update Services -->
<bean id="startContactBP" class="com.csc.fs.ws.contact.impl.StartContactBPService"/>
<!-- REST services -->
<bean id="startContactBPRest" class="com.csc.fs.rest.contact.StartContactBP" scope="prototype" />
<bean id="retrieveContactHistoryBPRest" class="com.csc.fs.rest.contact.RetrieveContactHistoryBP" scope="prototype" />
<!-- Exposing beans as rest services -->
<jaxrs:server id="restServer" address="/rest/">
<jaxrs:model id="restModel">
<jaxrs:resource name="com.csc.fs.rest.contact.RetrieveContactHistoryBP" path="retrieveContactHistoryBP">
<jaxrs:operation name="retrieve" path="{partyId}" consumes="application/json" produces="application/json" verb="GET">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="partyId" type="PATH"/>
</jaxrs:operation>
</jaxrs:resource>
<jaxrs:resource name="com.csc.fs.rest.contact.StartContactBP" path="startContactBP">
<jaxrs:operation name="startContact" path="/" consumes="application/json" produces="application/json" verb="PUT">
<jaxrs:param name="req" type="CONTEXT"/>
<jaxrs:param name="startContact" type="REQUEST_BODY"/>
</jaxrs:operation>
</jaxrs:resource>
</jaxrs:model>
<jaxrs:serviceBeans>
<!-- <ref bean="startContactBPRest"/> --> <!-- Instead configure above -->
<!-- <ref bean="retrieveContactHistoryBPRest"/> -->
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="feed" value="application/atom+xml"/>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
<entry key="html" value="text/html"/>
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jaxbProvider"/>
<ref bean="jsonProvider" />
</jaxrs:providers>
</jaxrs:server>
The thing I am facing problem is with the #XmlRootElement. I have not been successful in configuring it through the xml.
And I get the following error when trying to access the REST service
org.apache.cxf.interceptor.Fault
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:67)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:315)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
root cause
java.lang.NullPointerException
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleOperation(WadlGenerator.java:310)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleResource(WadlGenerator.java:253)
org.apache.cxf.jaxrs.model.wadl.WadlGenerator.handleRequest(WadlGenerator.java:185)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.checkMetadataRequest(RequestPreprocessor.java:189)
org.apache.cxf.jaxrs.impl.RequestPreprocessor.preprocess(RequestPreprocessor.java:82)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:112)
org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:88)
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113)
org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:105)
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461)
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188)
org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:108)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
So, Is there a way to configure the information in the XmlRoot annotation externally, so we don’t have to add it to Java code?
From the Apache-cxf documentation on jaxrs-data-bindings:
Alternatively to using #XmlRootElement and Collection wrappers, one can
provide an Object factory which will tell JAXB how to marshal a given
type (in case of Collections - its template type). Another option is to
return/accept a JAXBElement directly from/in a given method.
Another option is to register one or more JAX-RS ContextResolver providers
capable of creating JAXBContexts for a number of different types. The
default JAXBElementProvider will check these resolvers first before
attempting to create a JAXBContext on its own.

bind Spring HandlerInterceptor only to one controller

Using Spring 3.0.2.RELEASE. I'm having 2 Controllers in package com.myCompany. The Controllers are activated via Component-scan
<context:component-scan base-package="com.myCompany" />
then I'm having a interceptor bind to the 2 controllers via
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="myInterceptor"/>
</list>
</property>
</bean>
How can i bind the interceptor to only one specific Controller or to only certain methods inside a Controller?
Background: I want to inspect the URL that it contains certain parameters
Docu Link
When you inject interceptors into a HandlerMapping bean, those interceptors apply to every handler mapped by that HandlerMapping. That was fine in the pre-annotation days, since you'd just have configure multiple HandlerMapping beans. However, with annotations, we tend to have a single DefaultAnnotationHandlerMapping that maps everything, so this model doesn't work.
The solution is to use <mvc:interceptors>, where you explicitly map paths to interceptor beans. See the docs, and this example:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

Categories