JsonParseExceptionMapper not called by Jersey - java

I use Jersey and Jackson to implement RESTful services provided by my server. Data is exchanged between the client and server as JSON documents. Jackson does the mapping between the JSON documents and the POJOs. This works well.
But I ran into one issue. When calling a service with a malformed JSON document, the server returns with an 500 error. I would expect a 400 BAD-Request error instead. Some searching in the Jersey docs showed me that ExceptionMappers can be used to archive this behavior. I also found out that Jackson already has a implementation a JsonParseExceptionMapper but it never gets called.
Do I have to register the mapper and if so how can I do this outside of the source code.?

Ok I found out how to register the mapper classes.
In your web.xml where Jersery ServletContainer is registered you have to pass the Jackson package name org.codehaus.jackson.jaxrs beside your package name e.g. com.example.myapp.api;. The server then scans these packages on start up and registers the listener it find.
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.example.myapp.api;org.codehaus.jackson.jaxrs</param-value>
</init-param>
</servlet>

Related

What is the purpose of CXF servlet

I was going through a demo project setup for Restful webservice using Apache CXF, where I happened to come by a piece of code inside web.xml:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
I did not really understand the use of a servlet class in this web.xml. I googled for org.apache.cxf.transport.servlet.CXFServlet and found:
The CXFServlet class, which is defined by Apache CXF, is generated and
registered to handle incoming requests.
Now, I really do not understand what that line means
Does this servlet pose as a front-controller, like in Spring MVC flow?
What is the actual purpose of using this servlet class?
How does CXF use Spring to provide XML configuration of services defined in the project?
Does org.glassfish.jersey.servlet.ServletContainer serve the same purpose in Jersey Implementation as org.apache.cxf.transport.servlet.CXFServlet with Apache CXF?
Help me clarify these questions.
The JAX-RS specification is built on top of the Servlet specification. Each implementation should have a Servlet as an entry point to the application. When a request comes in, it gets processed by that Servlet. CXFServlet is CXF's implementation of that entry point Servlet.
Does this servlet pose as a front-controller, like in Spring MVC flow?
Pretty much. It's analogous to Spring MVC's DispatcherServlet
What is the actual purpose of using this servlet class?
As mentioned above, it's the entry point to the JAX-RS (CXF) application.
How does CXF use Spring to provide XML configuration of services defined in the project?
It uses Spring to wire up components; connect all of them together. But it's not required (see also).
Does org.glassfish.jersey.servlet.ServletContainer serve the same purpose in Jersey Implementation as org.apache.cxf.transport.servlet.CXFServlet with Apache CXF?
Pretty much.

REST Service and Servlet

So here I am writing my first REST Service and one thing regarding which my understanding is not clear is that there is an entry for a servlet in my web.xml file as follows:
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
So how is my service using this servlet?As in what's the use of a servlet in a REST Service?Is the service just a framework that uses the servlet's built in HTTP methods?
CXFServlet is one of the transport Apache CXF uses in order to publish rest services. In other words CXF uses under the hood when publishing a Rest services JAXRS annotated (#Path) a simple Java Servlet.
So the final URL where your rest services will be deployed is a concatenation between CXFServlet mapping and your rest services path.
There are other kind of transport. See http://cxf.apache.org/docs/transports.html just to understand that they are more options.
Hope this clarify you.

how to have spring manage bean lifecycle instead of jersey

I'm using jersey 2.17 on tomcat 8, and I'm having a problem with what I think should be a very straightforward and common use case.
I have various beans defined in a spring XML file. I've now annotated one of them to expose some methods as rest APIs. This is a singleton bean, with a reference to another bean injected in the spring XML configuration.
My rest APIs are working, but the problem is that every time one is invoked a new instance of the bean class is created, and my bean reference is null. My understanding is that this is because jersey is managing the lifecycle instead of spring, and I need SpringComponentProvider, which will then provide the singleton.
I included jersey-spring3-2.17.jar in my application, and I specified the spring package in the servlet configuration in web.xml, as follows:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.rest.package;org.glassfish.jersey.server.spring</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.tracing.type</param-name>
<param-value>ALL</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I know that the jersey.config.server.provider.packages parameter is being picked up because the annotated class in my.rest.package gets found, but the SpringComponentProvider is apparently not being registered, because I'm still getting a new instance of my bean every time.
I tried specifying the class explicitly like this:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.spring.SpringComponentProvider</param-value>
</init-param>
That didn't change the behavior either.
Any insights or debugging suggestions appreciated.
UPDATE: I realized that the version of my spring jars was behind the version expected by my jersey jars, and I think that's the problem. Once I'm able to update spring, if that fixes it I'll close this.
Jersey will create a new instance on each call regardless if you have an XML bean of the same class as singleton in spring context:
https://jersey.java.net/documentation/latest/jaxrs-resources.html#d0e2331
Also see this response on how to change that behavior:
https://stackoverflow.com/a/14739010/2879838
Within your Jersey Resource class, since you already added the jersey-spring dependency, you can simply add the #Autowire annotation on your member variable that you say is injected via XML file in spring. This will spring-inject the dependency when Jersey instantiates the resource on each request.
Hope this helps.
When I finally was able to update my spring, it turned out that was not the issue. I had to add #Component as well as #Singleton to my resource in order for jersey to recognize it as a spring-managed singleton. This problem would never have arisen if I was using annotations for spring; it happened because I was using XML to create the spring beans.

Apache Camel CXF SOAP WS WSDL

In my application I am trying to expose one soap web service and doing basic operations. This is what I have done:
Created Interface with soap operations as per JAX-WS standard. Added all needed annotations
in WEB.xml added
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservices/*</url-pattern>
</servlet-mapping>
created one route
from uri="cxf:/myservice?serviceClass="x.x.x.myInterface&dataFormat=PAYLOAD"
I am able to see the WSDL details in browser (localhost:8080/pro/webservices/myservice?wsdl), but if I hit the service using SOAP UI project my request is not coming through. I'm getting the below error in SOAP UI project:
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>org/apache/cxf/frontend/MethodDispatcher</faultstring>
</soap:Fault>
If I use dataFormat=MESSAGE my service is invoked by SOAPUI and getting response. But my WSDL is not coming in browser. Please tell which dataFormat i have to use in cxf component.
It jar issue. After using latest Jar it is working fine

spring web services configuration in web.xml?

I am using spring-ws and I have the below configuration in my web.xml
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>**transformWsdlLocations**</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Here I have transformWsdlLocations configured. Please explain me the use of transformWsdlLocations here. I am using the dynamic WSDL generation concept.
Is transformWsdlLocations really required for dynamic WSDL generation?
Thanks!
Given that it only takes a couple of minutes to remove the value and redeploy your application, I would advise you to do that and see what happens. Just try accessing the WSDL through "localhost" and through "127.0.0.1", and see what differences there are.
However I'll explain what you should see here...
When you read the WSDL that is generated, you should find that there are URLs in there.
i.e. From the local machine you might use:
http://localhost:8080/myservice.wsdl
But when you go live, your service might be:
http://www.<yourdomain>.com/myservice.wsdl
You don't want someone downloading the WSDL from your production domain to have those values populated with "localhost:8080". Likewise, you can't test your service properly if the URL being returned in the WSDL is for your production server. Or you might have multiple production services with different URLs.
transformWsdlLocations ensures that this is generated dynamically based on whatever URL is being used to access the service.
It is not needed for dynamic WSDL generation, but I have always found it very useful to have it. However, it is not enabled by default, so if you do want those URLs to be generated dynamically then it's best to include it.

Categories