RestEASY Interceptor Not Being Called - java

I've created a RestEASY Interceptor to allow me to set header values on the HTTP response after my webservice call has completed. My code looks like this...
#Provider
#ServerInterceptor
#Precedence("HEADER_DECORATORS")
public class MyHeaderInterceptor implements
MessageBodyWriterInterceptor {
#Override
public void write(MessageBodyWriterContext context) throws IOException,
WebApplicationException {
....do stuff here....
}
}
When I make a call to my service, however, the interceptor is never called. I see the webservice call complete successfully, but none of the code in my interceptor is ever executed. Is there anything beyond this that I need to do to register my interceptor? Does it have to be declared anywhere else? Are there any special web.xml parameters that need to be included?

You have to list the interceptor in the resteasy.providers context-param of your web.xml. Adding annotation to the Interceptor class is not enough.
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>org.resteasy.test.ejb.exception.FooExceptionMapper</param-value>
</context-param>

As for Resteasy 2.x you could also have it to automatically scan WEB-INF/lib jars and WEB-INF/classes directory for both #Provider and JAX-RS resource classes (#Path, #GET, #POST etc..) and register them:
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
Or can have Resteasy to Scan for #Provider classes and register them :
<context-param>
<param-name>resteasy.scan.providers</param-name>
<param-value>true</param-value>
</context-param>
In both cases you dont have to list the interceptors explicitly into web.xml.
Otherwise if both context-params 'resteasy.scan' and 'resteasy.scan.providers' are not enabled (and they are disabled by default) you may want to specify a comma delimited list of fully qualified #Provider class names you want to register inside the 'resteasy.providers' element:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.test.Interceptor1,com.test.Interceptor2</param-value>
</context-param>
That's taken from the doc : http://docs.jboss.org/resteasy/docs/2.3.3.Final/userguide/html_single/index.html#d0e72

Related

Spring mvc servlet url does not map correctly

When I go to the first url, it calls my home() method in the controller but when I go to the second url it does not call my homeTest() method. Why is that?
I get 404 error.
http://localhost:9083/MYAPP/foo ------ first url
http://localhost:9083/MYAPP/foo/bar ------ second url
web.xml
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
Controller:
#RequestMapping(value="/foo", method = RequestMethod.GET)
public String home(Model model){
return "home";
}
#RequestMapping(value="/foo/bar", method = RequestMethod.GET)
public String homeTest(Model model){
return "home";
}
You need to configure your RequestMappingHandlerMapping.
The official documentation goes into detail about handler mappings and some of their properties. The relevant one here is alwaysUseFullPath:
alwaysUseFullPath If true, Spring uses the full path within the current Servlet context to find an appropriate handler. If false
(the default), the path within the current Servlet mapping is used.
For example, if a Servlet is mapped using /testing/* and the
alwaysUseFullPath property is set to true, /testing/viewPage.html
is used, whereas if the property is set to false, /viewPage.html is
used
In short, when trying to find a mapping for /foo/bar, it removes the part that was matched by the Servlet environment, the /foo, and only uses the /bar to find a handler. You have no handler mapped to /bar.
By setting the property above to true, it will use the full path.
You can configure this in a #Configuration annotated WebMvcConfigurationSupport subclass, by overriding requestMappingHandlerMapping
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setAlwaysUseFullPath(true);
return handlerMapping;
}
Or whatever mechanism is appropriate for your configuration (there's an XML equivalent for example).
There's a special case for the exact match of /foo. It's not particularly relevant here.
Just change:
<url-pattern>/foo/*</url-pattern>
To
<url-pattern>/foo/**</url-pattern>

Loading context in web.xml

What is the difference between loading context in context param and loading it in init-param of Dispatcher Servlet.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
vs
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value> /WEB-INF/mvc-config.xml </param-value>
</init-param>
What i understood is context-param is loaded by context listener and should only contain middle tier beans. Where as Dispatcher Servlet in its init method should load web tier beans. Is this understanding correct? Why do we load 2 things seperately?
<context-param>
Is written outside <Servlet> tag and is inside <webapp> tag.
The values decalred will be available to the whole application
Any servlet in the application (declared in the web.xml) can access the values
So we use this when we want to share the the same set of values across the servlet in the application such as Data base configuration details.
You can use public String getInitParameter(String name) method of ServletContext interface to get value.
getServletContext() method of ServletConfig interface returns the object of ServletContext.
getServletContext() method of GenericServlet class returns the object of ServletContext.
Example 1 : ServletContext application=getServletConfig().getServletContext();
Example 2 : ServletContext application=getServletContext();
<init-param> .
Is written inside <Servlet> tag.
The values declared will be available only to the servlet.
You can use public String getInitParameter(String name) method of ServletConfig interface to get value.
getServletConfig() method of Servlet interface returns the object of ServletConfig.
Example : ServletConfig config=getServletConfig();
In the context-param "contextConfigLocation" you should include your application contexts, as you have already said middle tier beans, like: services, datasource...
The Spring DispatcherServlet will look for config files in WEB-INF/servletName-servlet.xml. Using the init-param you can change this default behaviour. The servlets contexts (web contexts) are isolated but might hold the application contexts as parent. You can use both or one of them independently.

Intercept JAX-RS Request: Register a ContainerRequestFilter with tomcat

I am trying to intercept a request to my JAX-RS webservice by a ContainerRequestFilter. I want to use it with a custom annotation, so I can decorate certain methods of the webservice. This should enable me to handle requests to this methods based on the information whether they are made on a secure channel
or not, before the actual method is executed.
I tried different approaches, searched several posts and then implemented mostly based on the answer by Alden in this post.
But I can't get it working.
I have a method test in my webservice decorated with my custom annotation Ssl.
#POST
#Path("/test")
#Ssl
public static Response test(){
System.out.println("TEST ...");
}
The annotation looks like this:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
public #interface Ssl {}
Then I setup a filter implementation
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
#Ssl
#Provider
public class SslInterceptor implements ContainerRequestFilter
{
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
System.out.println("Filter executed.");
}
}
But the filter is never executed nor there occur any error messages or warnings. The test method runs fine anyway.
To resolve it, I tried to register the filter in the web.xml as described here.
<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.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.my.packagewithfilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.my.packagewithfilter.SslInterceptor</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.my.packagewithfilter</param-value>
</init-param>
</servlet>
But that also doesn't work. What am I missing? Any ideas how to make that filter work? Any help is really appreciated!
You're using JAX-RS 2.0 APIs (request filters, name binding, ...) in your classes but Jersey 1 proprietary init params in your web.xml (package starting with com.sun.jersey, Jersey 2 uses org.glassfish.jersey). Take a look at this answer and at these articles:
Registering Resources and Providers in Jersey 2
Binding JAX-RS Providers to Resource Methods
Just compiling the answer from Michael Gajdos to help someone who do not want open more tabs:
When you are using Jersey-2 you must use the follow configuration to register your filter into the web.xml
jersey.config.server.provider.classnames
instead of
com.sun.jersey.spi.container.ContainerRequestFilters (jersey-1x)
<!-- This is the config needed -->
<servlet>
//...
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>com.your_package_path.yourClassFilter</param-value>
</init-param>
//...
</servlet>
Have a look at this blog post for the more 'classical' approaches (without using the annotation)

Is there a way to change the output type for restful webservices by a parameter in java?

I wanna use the same restful webservice path to produce xml or json, or a xml with xsl header.
Is it possible using any framework(jersey or resteasy) in java?
Eg:
#Path("/person")
public class PersonService {
#GET
#Path("/find")
public Person find(#QueryParam("name") String name, #QueryParam("outputformat") String outputformat) {
// do some magic to change output format
return dao.findPerson(name);
}
}
Maybe you can write a servlet filter that takes the query string and uses it to set the request's accept header accordingly, then jersey should dispatch to whatever method is annotated with #Consumes that matches.
For example, servlet filter intercepts request "?outputFormat=xml" and sets the Accept header to "application/xml". Then, jersey should dispatch to whichever method in your resource is annotated with: #Consumes("application/xml")
This question might help: REST. Jersey. How to programmatically choose what type to return: JSON or XML?
You could also easily customize Jersey ServletContainer and you won't require another param to pass along. You could negotiate representation using .json or .xml in your URL.
public class MyServletContainer extends ServletContainer {
#Override
protected void configure(ServletConfig servletConfig, ResourceConfig resourceConfig, WebApplication webApplication) {
super.configure(servletConfig, resourceConfig, webApplication);
resourceConfig.getMediaTypeMappings().put("json", MediaType.APPLICATION_JSON_TYPE);
resourceConfig.getMediaTypeMappings().put("xml", MediaType.APPLICATION_XML_TYPE);
}
}
In your web.xml, you could define the custom servlet as shown below.
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.MyServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sun.jersey.MyWebApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You could use Jersey and use the annotation #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}). You would need to add a mapping feature for POJOs in your application as well. The include in the web.xml file would be
<filter>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Other configurations would be necessary, but it is all in the documentation http://jersey.java.net/nonav/documentation/latest/user-guide.html

Start class right after deployment, not at session start for JSF

For a web application I make use of JSF 1.2 and Facelets.
The problem is that we now do the initialisation via a singleton pattern and that takes about 5-15 seconds because it read in data files (we are not using a database). This happens when the first user browses to the corresponding web page (the 2nd and other users don't have this delay).
I would like to have this singleton initialised right after deployment. How can I do this? I've tried to add an application bean but it does not get called. I've also tried to add a servlet as followings:
<servlet>
<description>MyApplicationContextListener Servlet</description>
<display-name>MyApplicationContextListener Servlet</display-name>
<servlet-name>MyApplicationContextListener</servlet-name>
<servlet-class>mydomain.beans.MyApplicationContextListener</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>mydomain.beans.MyApplicationContextListener</listener-class>
</listener>
with the following code:
package mydomain.beans;
import javax.servlet.ServletContextEvent;
public class MyApplicationContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("MyApplicationContextListener.contextInitialized started");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("MyApplicationContextListener.contextInitialized stopped");
}
}
An example including changes needed in web.xml and/or faces-config.xml would be nice!
How about using a ServletContextListener ? Its contextInitialized(..) method will be called at the moment the context is initialized. It's mapped in web.xml like this:
<listener>
<listener-class>com.example.MyServletContextListener</listener-class>
</listener>
Also, (not sure this would work), you can configure your faces-servlet to be loaded on startup.:
<load-on-startup>1</load-on-startup>
Clarification: For the listener approach, your listener must implement the ServletContextListener:
public class MyServletContextListener implements ServletContextListener { .. }

Categories

Resources