I'm using Jersey and I implemented a ContainerRequestFilter.
Now I also want to add a ContainerResponseFilter to add a header to each request but nothing happens when the webservice is accessed.
This is how the filter looks like:
public class ResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Cache-Control", "whatever");
}
}
My jersey dependencies:
compile 'org.glassfish.jersey.core:jersey-client:2.18'
compile 'org.glassfish.jersey.containers:jersey-container-servlet-core:2.18'
compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.18'
I register the providers in an xml like this:
<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>controller.webservice</param-value>
</init-param>
//This is the request filter, which is working fine
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>model.filter.AuthenticationFilter</param-value>
</init-param>
//Response filter, does not work
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>model.filter.ResponseFilter</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>
This didn't work, so I tried to register the provider with the annotation #Provider and in the webservice like this:
register(TokenModifier.class);
But none of these worked. I read several other posts but I couldn't find an answer to it. Does anyone have a thought on this?
This init-param
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>controller.webservice</param-value>
</init-param>
is used by Jersey to scan package(s) listed for #Path and #Provider annotated classes, and register them. The package(s) listed will be recursively scanned. So for example, with your current configuration, all the following packages will get scanned
controller.webservice
controller.webservice.x
controller.webservice.x.y
controller.webservice.x.y.z
The value of the param can also be multiple values separated by a comma or semi-colon. So if your filter is in a different package base, you can add that package to the list of packages to scan
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>controller.webservice, com.my.filters</param-value>
</init-param>
Personally though, if I'm using web.xml, I will just use one base package, and have all other packages extend from that package. Something like
com.company.app
com.company.app.domain
com.company.app.filters
com.company.app.resources
Then you can just put the com.company.app as the init-param value, and all other sub packages will get scanned also.
Related
In tomcat for a certain url, I want to skip all the filters and execute a servlet and I thought placing the servlet before the filter will to as I expected but still the filters behind the servlet mappings are executing. Am I doing anything wrong?
For instance, this is my web.xml
<servlet>
<servlet-name>APIRedirection</servlet-name>
<servlet-class>com.test.APIRedirection</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>APIRedirection</servlet-name>
<url-pattern>/abc/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>filter</filter-name>
<filter-class>com.test.filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
So when the incoming url contains "/abc/" I want my servlet to execute and skip the filters. I placed my servlet before all the filters but still the filters are getting executed when the incoming url contains '/abc/'.
There is no concept of servlet before filter.
If servlets url mapping qualify filters url mapping then filter is executed before servlet.
I got your requirement you just don't want to hit Filters for certain urls.
a. If your application is still in starting phase, you can configure as given below
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/filtered/servlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/filtered/servlet2</url-pattern>
</servlet-mapping>
...
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/filtered/*</url-pattern>
</filter-mapping>
And the servlet url for which you want to bypass filter
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/unfiltered/servlet1</url-pattern>
</servlet-mapping>
2. If your application is already developed, and you configured a filter already with mapping /* then you can not skip that filter being executed. But you can add one more filter before that filter. Here filter order plays an important role,(reference for filter order) you can perform same functionality which you expected from a servlet. In your filter you just have to break filter chain and send response as given below
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException
{
//your business logic
// construct responseToSend
response.getOutputStream().write(responseToSend);
return;
}
For more information of breaking filter chain refer this question
I have created a simple restful web service based on some examples and built it into a .war file(project structure has web.xml under WEB-INF), deploy it on glassfish ang get a 404 not found error when i try to call it.
My class containing the service is :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
* Created by Nikos Kritikos on 10/22/2015.
*/
#Path("/decks")
public class HS_Services {
#Path("sayHello/{name}")
#GET
public String doSayHello(#PathParam("name") String name) {
return "Hello there "+name;
}
}
my web.xml is this :
<servlet>
<servlet-name>HSRestServices</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HSRestServices</servlet-name>
<url-pattern>/hsrest/*</url-pattern>
</servlet-mapping>
i try to call it with http://localhost:8080/HSRestServices/hsrest/decks/sayHello/Nikos but i get 404 from glassfish..
Any help would be much appreciated, thank you.
You are missing the init-param where you specify which packages should be scanned for REST endpoint classes.
Change your web.xml to look like this:
<servlet>
<servlet-name>HSRestServices</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>insert.packagename.where.your.class.is.here</param-value>
</init-param>
</servlet>
Make sure to insert the name of the package which contains your class.
You don't need Spring for this.
There is also another way which works without web.xml. For details have a look at this question.
I have
#ApplicationPath("/resourcesP")
public class RestfulPrediction extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(PredictionsRS.class);
return set;
}
}
And
#ApplicationPath("/resourcesA")
public class RestfulAdage extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(Adages.class);
return set;
}
}
Two different ApplicationPath and the class are as follows.
#Path("/")
public class service.Adages {}
#Path("/")
public class webservices.PredictionsRS {}
Both of them are declared in different ApplicationPath. I'm using Jersey and the config in web.xml looks like
<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>
service
webservices
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
And I'm getting
SEVERE: Conflicting URI templates. The URI template / for root
resource class service.Adages and the URI template / transform to the
same regular expression (/.*)?
Why if I have two different ApplicationPath this exception comes at startup ?
If I take out a package in param-value this works, also if I change one of the #Path annotations this works, so it is a problem with my configuration ?
I'm using Jersey 1.10. Thanks all.
You did not define your JAX-RS applications in your web.xml. Try the following:
<servlet>
<servlet-name>full.name.RestfulAdage</servlet-name>
</servlet>
<servlet>
<servlet-name>full.name.RestfulPrediction</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>full.name.RestfulPrediction</servlet-name>
<url-pattern>/resourcesP/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>full.name.RestfulPrediction</servlet-name>
<url-pattern>/resourcesA/*</url-pattern>
</servlet-mapping>
and remove the #ApplicationPAth annotations from code.
I checked the above code with Jersey 2.7, servlet container 3.0 and it works. If still having that bug, try upgrading to Jersey 1.17 (which should not change any behavior from Jersey 1.10, and fix bugs instead) and eventually using also a servlet container 3.0.
UPDATE
After checking the possibilities the configuration below work with Jersey 1.17
<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.koitoer.webservices
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
It seems there is bug in the spec in older version of Jersey that kind of circle back the references and mark as duplicate endpoints. Using the configuration above both endpoints load without any problem.
8/04/2014 09:13:40 PM
com.sun.jersey.server.impl.container.servlet.JerseyServletContainerInitializer
addServletWithApplication INFO: Registering the Jersey servlet
application, named com.koitoer.webservices.chapter2.service2.RestfulPrediction, at the
servlet mapping, /resourcesP/*, with the Application class of the same
name
8/04/2014 09:13:40 PM com.sun.jersey.server.impl.container.servlet.JerseyServletContainerInitializer
addServletWithApplication INFO: Registering the Jersey servlet
application, named com.koitoer.webservices.chapter2.RestfulAdage, at
the servlet mapping, /resourcesA/*, with the Application class of the
same name
You should have a single subclass of javax.ws.rs.core.Application in your webapp, and then use different #Path annotation values on your service.Adages and webservices.PredictionsRS resource types.
AFAIK, in JEE6 containers, you are not allowed to have 2 such subclasses...
We have an existing Jersey REST service in our application(URL: /rest/*).
A sample URL looks like: http://xxx:8080/app/rest/company/getdata
Based on a property we need to redirect the REST call to another context(URL: /newrest/*):
A sample URL would look like: http://xxx:8080/app/newrest/company/getdata
So, I added a servlet mapping in my web.xml.
So, My web.xml looks like the below snippet.
<servlet>
<servlet-name>ServletAdaptor</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>xxx.httpservice</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>secureRESTFilter</filter-name>
<filter-class>xxx.RESTSecurityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>secureRESTFilter</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>NewAdaptor</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>xxx.newhttpservice</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>NewAdaptor</servlet-name>
<url-pattern>/newrest/*</url-pattern>
</servlet-mapping>
I have written a filter(to check for the property on the ServletAdaptor servlet and I need to redirect to the NewAdaptor servlet, if needed. Also, the final response should be sent back by the Servlet Adaptor servlet using the response from NewAdaptor servlet, if necessary(based on the property).
I need directions for solving this issue. Please help.
The dofilter method in my filter class looks like:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String productMode = "b";//hardcoded for this example
String url = request.getRequestURL().toString();
if(productMode.equals("a")){
chain.doFilter(req, res);
}else{
url=url.replace("rest", "newrest");
req.getRequestDispatcher(url).forward(req, res);
}
}
But the RequestDispatcher does not seem to forward the request to the new url.
From what i understand you are trying to create new services or integrate newer one.
Ideally you can version the URL's to support backward compatibilty in future.e.g.
http://{xxx}:8080/app/rest/v1_0/company/getdata,http://{xxx}:8080/app/rest/v2_0/company/getdata etc.
Why don't you wrap the new API call in the existing API call? So that the consumer talks to your API, internally you invoke the newer API and consume the response of it.Then you either return the new object or wrap your object around it.
You need to really re-look at the strategy you are trying to adopt!
How to pass pojo object as parameter to rest web service from prototypejs client.
Assume i have web service like this.
#Path("/postItem")
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Item postItem(Item item)
{
return new item;
}
From client side using prototypejs library how to pass pojo object as parameter to rest web service.
If parameter is of type string or integer i would have passed it as query param but it is pojo object in case.
I am about the syntax creation of the pojo object and then passing it to rest web service from prototypejs.
Which jax-rs implementation do you use? for Jersey, you can post json to the server by specify the jersey servlet:
<servlet>
<servlet-name>jersey-servlet</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>your package</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
then in your client code, you can directly post a json to the server, which will be deserialized to an Item instance