I am trying to learn jersey by creating a small RESTful service. I want to use the Filters for specific reasons(Like I want to use the ContainerResponseFilter for CORS headers to allow cross domain requests). However, I am just not able to get these filters intercept my call. I have seen all the posts for this problem and most of them say to register with annotation provider or in web.xml.
I have tried registering the files in web.xml as well as giving a #Provider annotation for the container
Here is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html#d4e194 -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring/config/BeanLocations.xml</param-value>
</context-param>
<servlet>
<servlet-name>Jersey Web Application</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.rest.example</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.rest.example.cors</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.rest.example.CORSFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.rest.example.RequestFilter</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webresources/*</url-pattern>
</servlet-mapping>
</web-app>
Here are my Filters:
package com.rest.example.cors;
import javax.ws.rs.ext.Provider;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
#Provider
public class CORSFilter implements ContainerResponseFilter {
public ContainerResponse filter(ContainerRequest creq,
ContainerResponse cresp) {
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "*");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS, HEAD");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
return cresp;
}
}
package com.rest.example.cors;
import javax.ws.rs.ext.Provider;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
#Provider
public class RequestFilter implements ContainerRequestFilter {
public ContainerRequest filter(ContainerRequest request) {
System.out.println("request filter");
return request;
}
}
Link to my github project.
I added a Jersey Application class and registered the filter in the class, which solved my problem. Also upgraded my jersey version to 2.x from 1.x
public class MyApplication extends ResourceConfig {
/**
* Register JAX-RS application components.
*/
public MyApplication () {
register(RequestContextFilter.class);
register(JacksonFeature.class);
register(CustomerResource.class);
register(Initializer.class);
register(JerseyResource.class);
register(SpringSingletonResource.class);
register(SpringRequestResource.class);
register(CustomExceptionMapper.class);
}
}
I solved the problem on Wildfly 10 / rest easy like this (CORSFilter is my ContainerResponseFilter):
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/rest")
public class JaxRsActivator extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> resources = new HashSet<Class<?>>();
resources.add(CORSFilter.class);
return resources;
}
}
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>org.anchepedheplatform.infrastructure.core.filters.ResponseCorsFilter</param-value>
</init-param>
First, I wrote a class which implements com.sun.jersey.spi.container.ContainerResponseFilter
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;
/**
* Filter that returns a response with headers that allows for Cross-Origin
* Requests (CORs) to be performed against the platform API.
*/
public class ResponseCorsFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response) {
final ResponseBuilder resp = Response.fromResponse(response.getResponse());
resp.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
final String reqHead = request.getHeaderValue("Access-Control-Request-Headers");
if (null != reqHead && !reqHead.equals(null)) {
resp.header("Access-Control-Allow-Headers", reqHead);}
response.setResponse(resp.build());
return response;
}
and later I had put this reference of this class in intit-param web.xml.
If you are extending the ResourceConfig class the process of registering all the providers can be tedious one and chances are there that one can even miss few providers.
What here can be done with a type of ResourceConfig is you can use packages method in the default constructor to specify the packages("") which will contain your rest resources and the providers. For Instance lets say we have a package com.test.poc.rest which contains all the rest services and another package namely com.test.poc.providers then our resourceConig will look like:
public class CustomResourceConfig extends ResourceConfig{
public CustomResourceConfig(){
super();
packages("com.test.poc.rest;com.test.poc.providers");
//register any custom features
register(JacksonFeature.class); // enabling JSON feature.
}
}
and boom jersey will now scan for your webservices annotated with #Path and for the providers annotated with #Provider.
Related
#EJB not working, returning null pointer exception when used. I am using jersey. It is working in the similar project of jersey earlier.
Rest API class
#Path("")
public class Services
{
#EJB
UserSessionBeanLocal userBean;
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("register")
public Response register(#FormParam("userName") final String name, #FormParam("userPassword") final String pass, #FormParam("userEmail") String email)
{
if (userBean.isEmailRegistered(email)) // userBean is null here
{
// code
}
}
}
Stateless EJB
#Stateless
public class UserSessionBean implements UserSessionBeanLocal
{
static ArrayList<User> usersList = new ArrayList<User>();
static int userCount = 0;
User u = null;
#Override
public boolean isEmailRegistered(final String email)
{
return usersList.stream().anyMatch(d -> d.getEmail().equals(email));
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.enovate.assignment.ejb1</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
</web-app>
Any help is appreciated. Thanks in advance.
I was expecting it should work fine. Now I have to use the JNDI lookup way to instantiate the bean.
As I mentioned it is working in almost similar project. I found something that #EJB does not work in non-managed bean if is related, but I don't understand it.
Coding a JAXRS service using jersey and deployed on tomcat. Application subclass
#ApplicationPath("/rest")
public class RestApplication extends Application {
public RestApplication() {
// TODO Auto-generated constructor stub
System.out.println("Inside RestApplication Constructor");
}
#Override
public Set<Class<?>> getClasses() {
// TODO Auto-generated method stub
System.out.println("Get Class");
Set<Class<?>> s=new HashSet<Class<?>>();
s.add(SupportDataService.class);
return s;
}
}
Resource class
#Path("/supportdata")
public class SupportDataService {
public SupportDataService() {
// TODO Auto-generated constructor stub
System.out.println("Inside SupportDataService Constructor");
}
#Path("/support")
#GET
#Produces(MediaType.TEXT_XML)
public String getSupportData(){
String xmlSupport=null;
xmlSupport="<SupportData><Support><key>path1</key><value>value1</value></Support><Support><key>path2</key><value>value2</value></Support></SupportData>";
return xmlSupport;
}
}
Added all jersey jar in WEB-INF/lib except javax.servlet-api-3.0.1.jar and hitting url
http://localhost:8080/RestConfigurator/rest/supportdata/support
but getting 404 error. Not specified any web.xml as subclassed Application.
So with Tomcat 6, which is a Servlet 2.5 implementation, we are required to have a web.xml declaring the ServletContainer. You can see more about it here. Basically, if you want to keep your RestApplication class, the web.xml would look something like
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>thepackge.of.RestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Given you have added all the jars from Jersey JAX-RS 2.0 RI bundle (besides the servlet-api), this should work. I've tested with Maven on Tomcat 6 and it works fine. Maven just pulls in all most of the jars from that bundle. But the app deployment doesn't differ.
I'm trying to create my own RESTful WS application using Jersey 2.12 based from this article. I want to return an XML representation of a class depending on the id been passed from the url, however, I'm getting a 500 response code when trying from either Advanced Rest Client Application (google chrome app) or browser. Below are the details:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>WS_RESTful_Practice</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Register resources and providers under com.vogella.jersey.first package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>test.services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
TestRestModel.java
package test.model;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class TestRestModel{
/**
*
*/
private static final long serialVersionUID = -8391589100962515747L;
private String name;
private String content;
public TestRestModel(String name, String content){
this.name = name;
this.content = content;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
TestResource.java
package test.services;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import test.dao.TestModelDao;
import test.model.TestRestModel;
#Path("/test")
public class TestResource {
#GET
#Path("{id}")
public Response getModel(#PathParam("id") String id){
return Response.ok().entity(TestModelDao.instance.getModel().get(id)).build();
}
}
TestModelDao.java
package test.dao;
import java.util.HashMap;
import java.util.Map;
import test.model.TestRestModel;
public enum TestModelDao {
instance;
private Map<String, TestRestModel> container = new HashMap<String, TestRestModel>();
private TestModelDao(){
TestRestModel model = new TestRestModel("a", "this is first");
container.put("1", model);
model = new TestRestModel("b", "this is second");
container.put("2", model);
model = new TestRestModel("c", "this is third");
container.put("3", model);
}
public Map<String, TestRestModel> getModel(){
return container;
}
}
I'm totally new to Jersey and REST. And I don't know how to log error from Jersey yet.
This happens when you don't provide a default no arg constructor to your JAXB bean. So in your case you should amend the class by adding one:
public TestRestModel(){
}
This is due to a requirement in the JSR-222:
existing types, authored by users, are required to provide a no arg
constructor. The no arg constructor is used by an unmarshaller during
unmarshalling to create an instance of the type.
Stuff below is not the answer, but will probably help Johne to find out, whats up.
Out of the comments I've extract, that the main problem is, that you don't have any noticeable debug output in your console. So you are not able to find the issue by yourself, rather than give us some logs which would help to find out, what the exact problem could be.
Therefore pls implement an ExceptionMapper first, which will force console output of the stacktrace:
Example:
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class HelpMeExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
e.printStackTrace();
return Response
.status(Status.INTERNAL_SERVER_ERROR)
.type(MediaType.APPLICATION_JSON)
.entity(e.getCause())
.build();
}
}
The ExceptionMapper has to be in a subpackage of your resource-config/providers path test.services:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>test.services</param-value>
</init-param>
As i didn't implement your/vogellas code i would like to recommend you, to debug this step by step to find out whats up.
I reckon, that you miss to import something. But who knows ...
Have a nice day ...
To the ones with the same problem, I had something like it but in my case it was a List that i wanted in my response. The source of the problem was that the object had a lazy load relationship and when I used GenericEntity> to return my list the same problem as occurred to me.
Just change to null the relationship or bring the lazy load relation to the object before create GenericEntity> and it will be fine.
We need to understand this problem first
Jersey returns 500 when trying to return an XML response. This issue is coming because of missing dependency in pom.xml and that is:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.11</version>
</dependency>
But this is not enough. This will resolve the 500 Error but one more error will come, while using endpoint.
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: com/sun/xml/bind/v2/model/annotation/AnnotationReader
To resolve this you need to add following dependencies too into pom.xml
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
So this is the complete solution, to make your Jersey webApp work
I have a problem deploying a RESTful web application (JAX-RS) on JBoss 7.1
This is the web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>HEODWS</display-name>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>it.heod.ws.WSApplication</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
While the class implementing the web service is:
#Path("/")
public class LoginService {
public LoginService() {
}
#GET
#Path("helloworld")
#Produces(MediaType.TEXT_PLAIN)
public Response helloWorld() {
Utils utils = Utils.getInstance();
utils.logExecutingMethod();
ResponseBuilder responseBuilder = null;
Response response = null;
responseBuilder = Response.ok();
responseBuilder.entity("Hello, world!");
response = utils.completeResponse(responseBuilder);
return (response);
}
}
The class WSApplication is:
public class WSApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public WSApplication(){
singletons.add(new LoginService());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
Now, if I deploy the WAR file on my local copy of JBoss 7.1 and I go to
http://localhost:8080/HEODWS/helloworld
the service behaves correctly and I get the desired response, while if I deploy it on another server, running JBoss 7.1, and I go to
http://anotherhost:8080/HEODWS/helloworld
I get a 404 not found.
Can anybody understand why, i.e. what is the difference between the two servers? Maybe I have configured (in the past) my local server in such a way that I can't recall now?
Thanks a lot in advance,
Gianluca
JBoss AS 7.1 provides you with Java EE 6 support, so you don't need to use the servlet dispatcher provided by RESTEasy (it's only necessary if you deploy on Tomcat or Jetty).
Then, you can remove the content from web.xml and declare your JAX-RS Activator in a pure Java form like this:
#ApplicationPath("/")
public class WSApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> empty = new HashSet<Class<?>>();
public WSApplication(){
singletons.add(new LoginService());
}
#Override
public Set<Class<?>> getClasses() {
return empty;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
You can even remove all the methods and fields in your WSApplication class (ie, just have an empty subclass of javax.ws.rs.core.Application) and annotate your LoginService class with #RequestScoped (or #Stateless).
HTH.
Xavier
I actually didn't know what happened, but by copying and pasting all the classes and the web.xml in a new project and deploying, it worked. I suppose it was just Eclipse that went crazy. Thanks everyone for the answers.
Please find the following code.
Service:DataResource.java
package com.mypack.pack2;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import com.mypack.pack1.DataClass;
#Path("data")
public class DataResource {
//Just retrieves the data members of the class
//i.e., 10 Ram
// Able to retrieve successfully.
#GET
#Produces("text/plain")
public String display()
{
DataClass obj1=new DataClass();
return obj1.getId()+obj1.getName();
}
#POST
#Path("/{id}/{name}")
#Produces("text/plain")
#Consumes("text/plain")
public void newData(#PathParam("id") int no,
#PathParam("name") String name) {
DataClass obj= new DataClass();
obj.setData(name,no);
System.out.println("Success");
System.out.println("Data after changes"+obj.getId()+obj.getName());
}
//TodoDao.instance.getModel().put(id, todo);
}
DataClass.java
package com.mypack.pack1;
public class DataClass {
private String ename="Ram";
private int eno=10;
public void setData(String name,int no)
{
this.ename=name;
this.eno=no;
}
public int getId()
{
return eno;
}
public String getName()
{
return ename;
}
}
Web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>de.vogella.jersey.jaxb</display-name>
<servlet>
<servlet-name>Jersey REST Service</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.mypack.pack2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
I am not able to change the values of class members ename and eno of DataClass. Can anyone please tell me why it is not changing? Is it because i am trying the code in a wrong way?
How are you invoking the POST URI (localhost:8080/JerseyProject/rest/data/11/John)? Be sure you are not invoking it from your browser, cause this way you would be invoking the verb GET o the /data/{id}/{name} that doesn't have implementation. That would explain why you're getting the status 405.
Usually the CREATE operation is used using the HTTP VERB POST on the collection URI with its params in the payload not on the path. In this case using POST on /data instead of /data/{id}/{name}.