How do I get Jersey 2.2 (JAX-RS) to generate log output, including Json request bodies - jersey

I'm running a Jersey 2.2 Servlet inside Jetty 9.0.4 in order to serve REST requests.
Mostly everything is good and requests get served, but I have never seen ANY log from Jersey classes. And I can't find any doco indicating what chickens I need to sacrifice to make that happen with Jersey 2.2
So my first question is - what do I need to do to get Jersey to generate some log.
When a request does run awry (eg because the Json request body can't be parsed) Jersey will throw a ContainerException with message like "Can not deserialize instance of java.util.ArrayList out of START_OBJECT token" etc. At that point it would be really lovely to have logged the incoming request body so I can inspect the Json. Again I can't find anything in the current doco outlining such a beast although I'm sure there is one. And in any case until I solve question 1 up above it's moot.
So my 2nd question is how do I log the incoming request body (without disrupting the request).
The Jersey Servlet config in web.xml looks like:
<servlet >
<servlet-name>Jersey Servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>au.com.xandar.wirelesstiming.recorder.web.rest.JerseyApplication</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
My JerseyApplication is:
public final class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
super(
//JacksonFeature.class // Switching on Jackson
// (My) JerseyLoggingFilter.class // Log requests using Jersey ContainerRequestFilter
MyApplicationEventListener.class // Log Requests using Jersey RequestEventListener
);
packages("au.com.xandar.wirelesstiming.recorder");
// Enable LoggingFilter & output entity.
// NB This does NOT generate any log.
registerInstances(new LoggingFilter(Logger.getLogger(JerseyApplication.class.getName()), true));
}
}

Jersey doesn't log much by itself. For 2.x we're working on a development mode which would include tracing support (see Tracing in Jersey), default logging of incoming requests / outgoing responses (incl. entity bodies and tracing messages). This feature should be out soon.
Regarding your second question - you can register LoggingFilter which is able to log incoming requests / outgoing responses (method, headers, ..) as well as entity bodies (when configured). You can configure it via (3rd option illustrates how to turn-on entity logging):
web.xml (add it to the JAX-RS servlet definition):
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.filter.LoggingFilter</param-value>
</init-param>
Application extension:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>() {{
// Add your resources.
add(HelloWorldResource.class);
// Add LoggingFilter.
add(LoggingFilter.class);
}};
}
}
ResourceConfig instance (demonstrating also outputting the entity here):
public class MyApplication extends ResourceConfig {
public MyApplication() {
// Resources - add your package name here to enable package scanning.
packages(...);
// Enable LoggingFilter & output entity.
registerInstances(new LoggingFilter(Logger.getLogger(MyApplication.class.getName()), true));
}
}

Related

What exactly is the ResourceConfig class in Jersey 2?

I have seen a lot of Jersey tutorials that starts with something like
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
without explaining what exactly the ResourceConfig class is. So where can I find its documentation, usage, etc.? Googling for "jersey resourceconfig" does not yield any official doc.
Some of my questions about this class and its usage are:
What things can I do inside the subclass of ResourceConfig?
Do I need to register the subclass of ResourceConfig somewhere so that it can be found or is it automatically detected by Jersey?
If the subclass is automatically detected what happens if I have multiple subclasses of ResourceConfig?
Is the purpose of ResourceConfig the same as the web.xml file? If so what happens if I have both in my project? Does one of them take precedence over the other?
Standard JAX-RS uses an Application as its configuration class. ResourceConfig extends Application.
There are three main ways (in a servlet container) to configure Jersey (JAX-RS):
With only web.xml
With both web.xml and an Application/ResourceConfig class
With only an Application/ResourceConfig class annotated with #ApplicationPath.
With only web.xml
It is possible to configure the application in a standard JAX-RS way, but the following is specific to Jersey
<web-app>
<servlet>
<servlet-name>jersey-servlet</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.mypackage.to.scan</param-value>
</init-param>
</servlet>
...
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
...
</web-app>
Since Jersey runs in a servlet container, it is only right that the Jersey application runs as a servlet. The Jersey Servlet that handles incoming requests is the ServletContainer. So here we declare it as the <servlet-class>. We also configure an <init-param> telling Jersey which package(s) to scan for our #Path and #Provider classes so it can register them.
Under the hood, Jersey will actually create a ResourceConfig instance, as that's what it uses to configure the application. Then it will register all the classes that it discovers through the package scan.
With both web.xml and Application/ResourceConfig
If we want to programmatically configure our application with an Application or ResourceConfig subclass, we can do so with one change to the above web.xml. Instead of setting an init-param to scan for packages, we use an init-param to declare our Application/ResourceConfig subclass.
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.JerseyApplication</param-value>
</init-param>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</servlet>
package com.example;
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here, we configure the init-param javax.ws.rs.Application with the fully qualified name of our ResourceConfig subclass. And instead of using the init-param that tells Jersey which package(s) to scan, we just use the convenience method packages() of the ResourceConfig.
We could also use the methods register() and property() to register resources and providers, and to configure Jersey properties. With the property() method, anything that can be configured as an init-param, can also be configured using the property() method. For instance instead of calling packages(), we could do
public JerseyApplication() {
property("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
}
With only Application/ResourceConfig
Without a web.xml, Jersey needs a way for us to provide the servlet-mapping. We do this with the #ApplicationPath annotation.
// 'services', '/services', or '/services/*'
// is all the same. Jersey will change it to be '/services/*'
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here with the #ApplicationPath, it's just like if we configured the servlet mapping in the web.xml
<servlet-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
When using only Java code for configuration, there needs to be some way for Jersey to discover our configuration class. This is done with the use of a ServletContanerInitializer. This is something that was introduced in the Servlet 3.0 Specification, so we cannot use "Java only" configuration in earlier servlet containers.
Basically what happens is that the implementor of the initializer can tell the servlet container what classes to look for, and the servlet container will pass those classes to the initializer onStartup() method. In Jersey's implementation of the initializer, Jersey configures it to look for Application classes and classes annotated with #ApplicationPath. See this post for further explanation. So when the servlet container starts the application, Jersey's initializer will get passed our Application/ResourceConfig class.
What things can I do inside the subclass of ResourceConfig
Just look at the javadoc. Its mostly just registration of classes. Not much else you need to do with it. The main methods you will be using are the register(), packages(), and property() methods. The register() method lets you manually register classes and instances of resources and providers manually. The packages() method, discussed earlier, lists the package(s) you want Jersey to scan for #Path and #Provider classes and register them for you. And the property() method allows you to set some configurable properties 1.
The ResourceConfig is just a convenience class. Remember, it extends Application, so we could even use the standard Application class
#ApplicationPath("/services")
public class JerseyApplication extends Application {
private final Set<Class<?>> classes;
private final Set<Object> singletons;
public JerseyApplication() {
// configure in constructor as Jersey
// may call the getXxx methods multiple times
this.classes = new HashSet<>();
this.classes.add(MyResource.class);
this.singletons = new HashSet<>();
this.singletons.add(new MyProvider());
}
#Override
public Set<Class<?>> getClasses() {
return this.classes;
}
#Override
public Set<Object> getSingletons() {
return this.singletons;
}
#Override
public Map<String, Object> getProperties() {
final Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
return properties;
}
}
With a ResourceConfig, we would just do
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(MyResource.class);
register(new MyProvider());
packages("com.mypackages.to.scan");
}
}
Aside from being more convenient, there are also a few thing under the hood that help Jersey configure the application.
An SE Environment
All the examples above assume you are running in an installed server environment, e.g. Tomcat. But you can also run the app in an SE environment, where you run an embedded server and start the app from a main method. You will sometimes see these examples when searching around for info, so I want to show what that looks like, so that if you ever do come across this, you are not surprised and know how it differs from your setup.
So sometimes you will see an example like
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
What is most likely happening here is that the example is using an embedded server, like Grizzly. The rest of the code to start the server might be something like
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
String baseUri = "http://localhost:8080/api/";
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), config);
server.start();
}
So in this example, there is a standalone server being started and the ResourceConfig is used to configure Jersey. The different here and from previous examples is that in this example, we are not extending the ResourceConfig, but instead just instantiating it. It wouldn't be any different if we were to do
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.my.package");
register(SomeFeature.class);
property(SOME_PROP, someValue);
}
}
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), new JerseyConfig());
Say you were going through some tutorial and it showed a configuration for a standalone app where they instantiate the ResourceConfig. But you are running your app in an installed servlet container and have been using the earlier configuration where you are extending the ResourceConfig. Well now you know what the difference is and what changes you need to make. I've seen people do some really weird stuff because they didn't understand this difference. For example I saw someone instantiating a ResourceConfig inside a resource class. So this is why I added this extra little piece; so you don't make the same mistake.
Footnotes
1. There are a number of different configurable properties. The link to the ServerProperties are just some general properties. There are also different properties related to specific features. The documentation should mention these properties in the section of the docs related to that feature. For a complete list of all configurable properties, you can look at all the Jersey constants and look for the ones where the string value starts with jersey.config. If you are using a web.xml, then you would use the string value as the init-param param-name. If you are using Java config (ResourceConfig), then you would call property(ServerProperties.SOME_CONF, value)

How to allow GET method for endpoint programmatically?

I am loading a .war file and add it as web app to the embedded Tomcat server.
#Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
LOGGER.info("Adding web app");
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
String appHome = System.getProperty(Environment.APP_HOME);
String targetFileName = "web-0.0.1-SNAPSHOT.war";
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(targetFileName);
LOGGER.info(System.getProperty("user.name"));
LOGGER.debug("Loading WAR from " + appHome);
File target = new File(Paths.get(appHome, targetFileName).toString());
try {
LOGGER.info(String.format("Copy %s to %s", targetFileName, target.getAbsoluteFile().toPath()));
java.nio.file.Files.copy(resourceAsStream, target.getAbsoluteFile().toPath(), StandardCopyOption.REPLACE_EXISTING);
Context context = tomcat.addWebapp("/", target.getAbsolutePath());
context.setParentClassLoader(getClass().getClassLoader());
} catch (ServletException ex) {
throw new IllegalStateException("Failed to add webapp.", ex);
} catch (Exception e) {
throw new IllegalStateException("Unknown error while trying to load webapp.", e);
}
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
This is working so far but if I access http://localhost:8080/web I am getting
2017-03-04 11:18:59.588 WARN 29234 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound : Request method 'GET' not supported
and the response
Allow: POST
Content-Length: 0
Date: Sat, 04 Mar 2017 10:26:16 GMT
I am sure all I have to do is to allow the GET method on /web and hopefully the static web content provided from the loaded war file will be accessible via web browser.
How/where can I configure the endpoint such that it allows GET requests?
I tried to introduce a WebController as described in this tutorial.
#Controller
public class WebController {
private final static Logger LOGGER = Logger.getLogger(WebController.class);
#RequestMapping(value = "/web", method = RequestMethod.GET)
public String index() {
LOGGER.info("INDEX !");
return "index";
}
}
In the log output I can see that this is getting mapped correctly:
RequestMappingHandlerMapping : Mapped "{[/web],methods=[GET]}" onto public java.lang.String org.ema.server.spring.controller.dl4j.WebController.index()
but it does not change the fact that I cannot visit the website.
I've also configured a InternalResourceViewResolver:
#Configuration
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
private final static Logger LOGGER = Logger.getLogger(MvcConfiguration.class);
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
LOGGER.info("configureViewResolvers()");
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setSuffix(".html");
registry.viewResolver(resolver);
}
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
web.xml
Since I configure everything in pure Java, this file does not define a lot:
<?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"
version="3.0">
<display-name>Easy Model Access Server</display-name>
<listener>
<listener-class>org.ema.server.ServerEntryPoint</listener-class>
</listener>
<context-param>
<param-name>log4j-config-location</param-name>
<param-value>WEB-INF/classes/log4j.properties</param-value>
</context-param>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/web/*.html</url-pattern>
</servlet-mapping>
</web-app>
Reproduce
If you want to reproduce this you can simply checkout the entire code from github. All you need to do this:
mkdir ~/.ema
git clone https://github.com/silentsnooc/easy-model-access
cd easy-model-access/ema-server
mvn clean install
java -jar server/target/server-*.jar
This will clone, build and run the server.
The directory ~/.ema directory is required at the moment. It is where the WAR is being copied as the server starts.
My guess is that your web.xml maps any path to the Spring DispatcherServlet, something like:
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Because of <url-pattern>/</url-pattern> any request must be handled by a Spring controller, for this reason your static files are not served by Tomcat. Also a pattern like /*.html would have same effect.
If you have only a few pages you might add one or more mapping to the predefined default servlet for them, before the mapping of Spring (and also before Spring Security if you use it):
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>index.html</url-pattern>
</servlet-mapping>
You may also use <url-pattern>*.html</url-pattern> or, if your resources are under the web path and there are only static resources there: <url-pattern>/web/*</url-pattern>
Maybe all this is done instead in Java code in the org.ema.server.ServerEntryPoint that you have as a listener in web.xml
I think the mapping I wrote up in web.xml is done in your case in method getServletMappings of class org.ema.server.spring.config.AppInitializer, I changed it to use a more strict pattern /rest-api/* instead than /, not sure pattern is correct and everything else works, but now http://127.0.0.1:8080/index.html works
#Override
protected String[] getServletMappings() {
return new String[] { "/rest-api/*" };
}
as I see the url: http://localhost:8080/web is wrong.
You can try: http://localhost:8080/[name-of-war-file]/web

ResourceFilterFactory and non-Path annotated Resources

(I'm using Jersey 1.7)
I am attempting to add a ResourceFilterFactory in my project to select which filters are used per method using annotations.
The ResourceFilterFactory seems to be able to filters on Resources which are annotated with the Path annotation but it would seem that it does not attempt to generate filters for the methods of the SubResourceLocator of the resources that are called.
#Path("a")
public class A {
//sub resource locator?
#Path("b")
public B getB() {
return new B();
}
#GET
public void doGet() {}
}
public class B {
#GET
public void doOtherGet() { }
#Path("c")
public void doInner() { }
}
When ran, the Filter factory will only be called for the following:
AbstractResourceMethod(A#doGet)
AbstractSubResourceLocator(A#getB)
When I expected it to be called for every method of the sub resource.
I'm currently using the following options in my web.xml;
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>com.my.MyResourceFilterFactory</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.my.resources</param-value>
</init-param>
Is my understanding of the filter factory flawed?
You need to use #Path annotation at class level for Class B. When Jersey does the resource scan I bet you that it doesnt pick up this class as a resource.

GWTP using Spring in server side

I am working with gwtp and I would like to use Spring on the server side. I have seen that Spring is include in gwtp, but I don't know how I can use it. Anyone can help me about that?
Will be cool some example.
I have looked for by google, but no way :(
Thanks a lot!!
GWTP is using GIN pattern (Dependency Injection at Client Side) and it's default integration with GUICE at DI server side. for more detail GWTP
Spring is server side DI pattern.
I have seen that Spring is include in gwtp,
It does not include Spring at all. it's default integration with GUICE. but you can use spring with it.
gwtp-sample-basic-spring example
Well, at first you have to configure Spring in your web.xml descriptor:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<url-pattern>/yourProjectName/springGwtServices/*</url-pattern>
</servlet-mapping>
Notice that you need the Spring4GWT library for this example.
Next, in your RemoteService interfaces you need to specify the RemoteServiceRelativePath like this example:
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.google.gwt.user.client.rpc.RemoteService;
#RemoteServiceRelativePath("springGwtServices/userService")
public interface UserService extends extends RemoteService{
public User getUserByLogin(String name);
public void logout();
public void deleteUserById(Long userId);
}
And now, you just need to implement your service as in any Spring app.
Example, suppose you want an action to delete a User by ID and using the GWTP paradigm:
In server side, here is the Handler:
#Repository("deleteUserHandler")
public class DeleteUserHandler extends AbstractActionHandler<DeleteUserAction, DeleteUserResult> {
#Autowired
private UserService userService;
public DeleteUserHandler(){
super(DeleteUserAction.class);
}
#Override
public DeleteUserResult execute(DeleteUserAction action, ExecutionContext arg1)
throws ActionException {
Long idToDel = action.getUserToDeleteId();
if(idToDel != null){
userService.deleteUserById(idToDel);
}
return new DeleteUserResult();
}
#Override
public void undo(DeleteUserAction arg0, DeleteUserResult arg1,
ExecutionContext arg2) throws ActionException {
// TODO Auto-generated method stub
}
}
The DeleteUserAction is as follows
public class DeleteUserAction extends UnsecuredActionImpl<DeleteUserResult> {
private Long userToDeleteId;
public DeleteUserAction(Long userToDel) {
this.userToDeleteId = userToDel;
}
/**
* For serialization only.
*/
#SuppressWarnings("unused")
private DeleteUserAction() {
}
public Long getUserToDeleteId() {
return userToDeleteId;
}
public void setUserToDeleteId(Long userToDeleteId) {
this.userToDeleteId = userToDeleteId;
}
}
And finally the Result class:
public class DeleteUserResult implements Result {
/**
* For serialization only.
*/
//#SuppressWarnings("unused")
public DeleteUserResult() {
}
}
I hope this helps.
PS: I suppose you can do the Spring things (application context etc..) by yourself, if not, please tell
You can find some good examples on GWTP repository in Github. We recently migrated all of our from Google Code to Github, which hosts the latest version.
Remember you can also use REST communication using the new GWTP-Dispatch-Rest, with that you don't need a lot of configuration code to integrate GWTP with Spring server side.
https://github.com/ArcBees/GWTP-Samples

How to inject jersey filter without adding it web.xml

I dont know if this is possible or not but I have created the Jersey Filter for logging extending the logging filter and I added
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.chegg.commons.web.logging.WebRequestLogger</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.chegg.commons.web.logging.WebRequestLogger</param-value>
</init-param>
in my web.xml and every thing works fine. I want to take it at one more level. Can servlet container call the filter without the entry in web.xml by any annotation on the top of my logging class. Something like #Aspect. I dont want to use #Aspect as it is not a filter.
Yes you can always use #Provider annotation to annotate your CustomFilterClasses and just register these manually or let jersey scan your filters automatically.
for instance:
package com.test.poc.filters;
#Provider
public class CustomFilter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext requestContext){
//filter logic..
}
}
is one filter which we want to be auto discovered by jersey at runtime so for this we can easily specify one class which extends ResourceConfig
#ApplicationPath("api")
public class CustomResourceConfig extends ResourceConfig{
public CustomResourceConfig(){
super();
packages("com.test.poc.filters;com.test.poc.restservices;com.test.poc.providers");
//ragister any other classes like
//register(JacksonFeature.class);
}
}
This will automatically scan for all the classes annotated with #Provider or #Path in the specified packages

Resources