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.
Related
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
I am creating a simple web service using Spring 3 with Hibernate 5.
My maven dependencies for those are:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>3.2.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.0.1.Final</version>
</dependency>
This isn't my full dependency list but it gives a good idea of the versions I'm using.
The basic requirements of this web service are to provide an endpoint by which a user can request some data based on a unique ID. The data has to be returned as JSON. The data is being retrieved from a SQL Server 2008 database view.
I have successfully configured the web service to use Hibernate and JPA to get the correct data where an ID is matched on a row in the view. The ID is provided as a parameter with the URL, for example:
http://some/resource/location.json?id=1234
Now as I said, this works fine, gets the data if the ID is matched and returns a POJO marshalled as json to the user.
My issue is the requirement to include the '.json' file extension as part of the URL. Ideally I would like the URL to look something like this instead:
http://some/resource/location?id=1234
Notice no '.json'
The view resolver I am using is configured as follows, just ignore the xml stuff, I have that in there because I will need it further down the line:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
<constructor-arg>
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
Is there a different view resolver I should implement maybe?
I can include more detail if needed, just ask, thanks for any help on this.
check this spring.io tutorial. it will fit in your needs and more specially this xml config, because i see that you use xml config instead of java config:
<!-- Total customization - see below for explanation. -->
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="favorParameter" value="false" />
<property name="parameterName" value="mediaType" />
<property name="ignoreAcceptHeader" value="true"/>
<property name="useJaf" value="false"/>
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>
I think I customise it for your needs.
Nikolay pointed me in the right direction, but the actual answer was such a small section of that tutorial I thought it would be more helpful to others looking for similar answers to show exactly what solution I used in the end here.
Basically the key was to add a produces = {"application/json"} param to my controller method that I mapped to a URl, like so:
#RequestMapping(
value = "/some/resource/location",
method = RequestMethod.GET,
produces = {"application/json"}
)
public #ResponseBody CustomClass getSomething(#RequestParam String id) {
return customService.getSomethingById(id);
}
Plus I had to be quite specific with my servlet URL mapping, moving away from mapping by extension to mapping by specific URI. I'm sure this could be done differently but it worked for my specific requirements:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/servlet-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/some/resource/location</url-pattern>
</servlet-mapping>
I should note that I got some help with the servlet url pattern configuration from another stack overflow answer discussing what values the url pattern would except.
And that's it, it just worked, no need to include a special content negotiator bean after all.
I simply use the end point like this:
http://some/resource/location?id=1234
And it returns json.
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
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?
I have a Spring 2.5.x application which I'm migrating to Spring 3 and just bumped into a little problem.
I have an handler mapping like so:
<bean id="handlerMappings1" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="interceptor1" />
<ref bean="interceptor2" />
....
<ref bean="interceptorN" />
</list>
</property>
<property name="urlMap">
<map>
<entry key="/url1.html" value-ref="controller1" />
<entry key="/url2.html" value-ref="controller2" />
....
<entry key="/url100.html" value-ref="controller100" />
</map>
</property>
</bean>
and another one like this:
<bean id="handlerMappings2" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/urlA.html" value-ref="controllerA" />
<entry key="/urlB.html" value-ref="controllerB" />
....
<entry key="/urlN.html" value-ref="controllerN" />
</map>
</property>
</bean>
I'm slowly replacing both with #RequestMapping annotations with a <context:component-scan> (which basically registers a DefaultAnnotationHandlerMapping).
In Spring 3 I saw the <mvc:interceptors> tag which can be used to add interceptors to certain URLs but you can specify only one interceptor, at least that's what I see from the schema.
From what I can figure, I have to register one of these for each interceptor which will duplicate all my URLs for as many times as I have interceptors (and I don't even know in what order they will run).
On the other hand I can't add the iterceptors on the DefaultAnnotationHandlerMapping because they will run for all my controllers annotated with #RequestMapping and I don't want that.
So how can I specify interceptors is Spring 3 for some URLs, without repeating the URL's and
keeping the URL to controller mapping based on the #RequestMapping annotation?
You could have a look at the SelectedAnnotationHandlerMapping and the IgnoreSelectedAnnotationHandlerMapping classes from the springplugins project. The sources are some years old but the idea still stands.
There is a presentation on the creator's blog here: Spring Framework Annotation-based Controller Interceptor Configuration. Make sure you also read the comments to the blog post.
One option would be to create a custom interceptor which can delegate to a collection of injected interceptors.