latest CXF with Spring: WARNING: javax.ws.rs.NotFoundException - java

I am able to access REST services from the browser url: http://localhost:8080/assignment/services/services/test/test1
From My servlet, I use to call service method as shown below. Now I need to call through REST services but getting below error.
URL url = new URL("http://localhost:8080/assignment/services/services/"+userName+"/"+password);
System.out.println("URL-->"+url);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while(bufferedReader.readLine() != null){
result = bufferedReader.readLine();
}
// result = userService.login(userName, password);
System.out.println(result);
here is the error:
INFO: Reloading Context with name [/assignment] is completed
URL-->http://localhost:8080/assignment/services/test/test1
Jul 30, 2013 12:52:02 PM org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor processRequest
WARNING: No root resource matching request path /assignment/services/test/test1 has been found, Relative Path: /test/test1. Please enable FINE/TRACE log level for more details.
Jul 30, 2013 12:52:02 PM org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: javax.ws.rs.NotFoundException
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:172)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:100)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:223)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:203)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:137)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:158)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java
...
Jul 30, 2013 12:52:02 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [LoginServlet] in context with path [/assignment] threw exception
java.io.FileNotFoundException: http://localhost:8080/assignment/services/services/test/test1
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1623)
at com.viasat.test.login.servlet.LoginServlet.process(LoginServlet.java:77)
at com.viasat.test.login.servlet.LoginServlet.doPost(LoginServlet.java:52)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
Service class:
#Service
#Path("/services/")
public class UserServiceImpl implements UserService {
#GET
#Path("{userName}/{password}")
#Produces(MediaType.TEXT_XML)
public String login(#PathParam("userName")String username, #PathParam("password")String password)
throws JAXBException, PropertyException, FileNotFoundException {
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<display-name>LoginServlet</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.abc.test.login.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>
Update:
pom.xml:
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
Now Javax.ws.rs.NotFoundException gone, but, File not found exception still comes.

Solution-1
One of the solution is that version issue with CXF and Spring. I have made cxf version to 2.5.2 which avoids javax.ws.rs.NotFoundException.
Now I have updated to
<spring.version>3.2.2.RELEASE</spring.version>
<cxf.version>2.5.2</cxf.version>
I was using 2.7.5 cxf version.
Solution -2
In my service class I have made
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) instead of
#Produces(MediaType.TEXT_XML)

The URL you are using to fire the GET request has two services levels:
http://localhost:8080/assignment/services/services/"
but in your REST service class, there is only one 'services' level in Path. You may need to change the Path Param to like this:
#Service
#Path("/services/")
public class UserServiceImpl implements UserService {
#GET
#Path("services/{userName}/{password}")
#Produces(MediaType.TEXT_XML)
public String login(#PathParam("userName")String username, #PathParam("password")String password)
throws JAXBException, PropertyException, FileNotFoundException {

I think "services" is by default the path where CXF exposes the auto-generated WADLs and therefore cannot be used in a resource path.
Try either changing "services" to another word in your web.xml and Service class (#Path) or change the CXF servlet config like so (see the service-list-path param):
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<init-param>
<param-name>service-list-path</param-name>
<param-value>web-services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Reference: http://cxf.apache.org/docs/jaxrs-services-description.html (section Service listings and WADL queries almost at the end).
Note that you can override the location at which listings are provided
(in case you would like '/services' be available to your resources)
using 'service-list-path' CXFServlet parameter

one common reason for this error is that cxf cannot find a restful implementation for the restful service to match the request to the resource method later. the spec is ambiguious in this area but your jaxrs annotations in the interface must match implementation in cxf.
--eliani

As described in CXF project throws java.lang.NoClassDefFoundError: javax/ws/rs/NotFoundException the
Error can be solved by adding
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0-m10</version>
</dependency>

Related

Configure Jersey 2 web.xml for Swagger/ OpenAPI v3

I am running a Jersey 2.30.1 API and I want to upgrade the Swagger documentation to OpenAPI v3.
My new swagger dependencies in the pom.xml look like this:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.17.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
<version>2.0.2</version>
</dependency>
Previously (swagger 1.5 with swagger-ui 2.2.10-1), I had Swagger configured in my web.xml:
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>2.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>/api</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
I would like to do the same now, but I can't find a documentation, if and how that would be possible.
How can I define the swagger base path and API version in my web.xml with OpenAPI v3?
After playing around with this, my solution is basically like so.
pom.xml:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.52.1</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
<version>2.1.10</version>
</dependency>
web.xml:
The Jersey2Config servlet is completely removed from web.xml.
The servlet configuration needs to be changed for the parameter io.swagger.v3.jaxrs2.integration.resources
<servlet>
<servlet-name>my 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>my.package.to.scan, io.swagger.v3.jaxrs2.integration.resources</param-value>
</init-param>
</servlet>
Additional to web.xml a new file openapi.yaml has to be created under src/main/webapp/WEB-INF. This is responsible for creating the openapi.yaml/ openapi.json file which will be consumed by the swagger ui.
openapi.yaml:
prettyPrint: true
cacheTTL: 0
readAllResources: false /** Only show methods in swagger-ui that are annotated */
openAPI:
info:
version: '1.0'
title: 'my application'
servers:
- url: '/my-application'
swagger ui:
...
window.onload = function() {
const window.ui = SwaggerUIBundle({
url: 'https://my-domain.com/my-application/openapi.json',
dom_id: '#swagger-ui-container',
docExpansion: 'none',
defaultModelsExpandDepth: -1,
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
apisSorter: "alpha",
tagsSorter: "alpha",
operationsSorter: "alpha",
validatorUrl: null
});
}
...

Swagger configuration - 404 when accessing swagger.json

I'm new to swagger and looking to get it set up on my latest REST API project but am failing miserably. Everything seems to be configured correctly but I am unable to navigate to swagger.json without getting a 404. I can't see what is missing or wrong
pom.xml
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey-jaxrs</artifactId>
<version>1.5.0</version>
<exclusions>
<exclusion>
<artifactId>jersey-server</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
<exclusion>
<artifactId>jersey-multipart</artifactId>
<groupId>com.sun.jersey.contribs</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
<version>1.11.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.11.1</version>
</dependency>
Exclusions as the project uses version 1.11.1 and causes conflicts if 1.13 is imported from swagger
web.xml
<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>
io.swagger.jaxrs.json,
io.swagger.jaxrs.listing,
uk.package.test.myproject
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Jersey2Config</servlet-name>
<servlet-class>io.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
<init-param>
<param-name>api.version</param-name>
<param-value>1.0.0</param-value>
</init-param>
<init-param>
<param-name>swagger.api.basepath</param-name>
<param-value>http://localhost:8082/myproject/api</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Example annotations...
#ManagedBean
#Path("secure/cache")
#Restrict("ManageCache")
#Api(value = "secure/cache", description = "Rest api for do operations on admin", produces = MediaType.APPLICATION_JSON)
public class AdminApi {....
#GET
#Path("{name}")
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Get specific admin", httpMethod = "GET", notes = "Fetch the admin user details", response = Response.class)
#ApiResponses(value = { #ApiResponse(code = 200, message = "Given admin user found"),
#ApiResponse(code = 404, message = "Given admin user not found"),
#ApiResponse(code = 500, message = "Internal server error due to encoding the data"),
#ApiResponse(code = 400, message = "Bad request due to decoding the data"),
#ApiResponse(code = 412, message = "Pre condition failed due to required data not found") })
public List<String> getCacheKeys(.....
When the project is run the following is logged...
10:46:48,724 INFO [com.sun.jersey.api.core.PackagesResourceConfig] (MSC service thread 1-5) Scanning for root resource and provider classes in the packages:
io.swagger.jaxrs.json
io.swagger.jaxrs.listing
uk.package.test.myproject
10:46:48,771 INFO [com.sun.jersey.api.core.ScanningResourceConfig] (MSC service thread 1-5) Root resource classes found:
class uk.package.test.myproject.api.NotificationApi
class uk.package.test.myproject.api.UserApi
class uk.package.test.myproject.api.FlagsApi
class uk.package.test.myproject.api.UnitsByFunctionApi
class uk.package.test.myproject.api.CvDataApi
class uk.package.test.myproject.api.ImageApi
class uk.package.test.myproject.api.GazetteerApi
class uk.package.test.myproject.api.SearchApi
class uk.package.test.myproject.api.ViewApi
class uk.package.test.myproject.api.AdminApi
10:46:48,776 INFO [com.sun.jersey.api.core.ScanningResourceConfig] (MSC service thread 1-5) No provider classes found.
10:46:48,834 INFO [com.sun.jersey.server.impl.cdi.CDIComponentProviderFactoryInitializer] (MSC service thread 1-5) CDI support is enabled
10:46:48,842 INFO [com.sun.jersey.server.impl.application.WebApplicationImpl] (MSC service thread 1-5) Initiating Jersey application, version 'Jersey: 1.11.1 03/31/2012 06:49 PM'
Thank you in advance
Cheers
Martin
Just to let you know I have resolved this by using a custom Application rather than using package scanning :)
Thanks for your help
Martin
Your servlet mapping says that you should not be looking at the path you specified:
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
That typically means to look under the /api path. That means then, unless you're using a webapp called myproject, you should be looking under /api/swagger.json

Jersey: MessageBodyReader not found for media type=multipart/form-data

I have found a few questions like this on SO already but none of them seemed to address my particular problem, and I have been unable to find a solution on my own.
Here is the error I'm getting:
Caused by: org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=multipart/form-data; boundary=----WebKitFormBoundaryHWk1XUaeu7pEiDth, type=class org.glassfish.jersey.media.multipart.FormDataMultiPart, genericType=class org.glassfish.jersey.media.multipart.FormDataMultiPart.
I am sending this through a jQuery AJAX request that looks like this:
$('#upload-image-form').on('submit', function(e) {
e.preventDefault();
var data = new FormData(this);
$.ajax({
url: url,
method: 'POST',
contentType: false,
processData: false,
data: data,
}).done(function(data) {
console.log(data);
}).fail(function(res, status) {
onError(res, status, 'Image upload failed');
});
});
And this is my Java endpoint:
#POST
#Path("/{userId}")
#Consumes("multipart/form-data")
public Response createGraphic(
#PathParam("userId") int userId,
FormDataMultiPart multiPartFormData) { ... }
I have seen a few people have luck with changing the parameter of the endpoint method to use #FormDataParam instead of FormDataMultiPart (as seen here), but I cannot edit the Java class, so I must use it how it is above.
My pom.xml has the following dependencies:
<dependency>
<groupId>org.jvnet</groupId>
<artifactId>mimepull</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.12</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.12</version>
</dependency>
web.xml
<servlet>
<servlet-name>Jersey</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.package</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
The only other thing I was able to dig up was to register the MultiPartFeature using a ResourceConfig; however, the project I'm working with does not have any Application classes or any class that extends ResourceConfig (it's a WAR that's deployed to Tomcat, so no main class).
Is there any other configuration that needs to be done? I'm stumped as to why this is not working.
The MultiPartFeature has the required reader and writer. But you still need to register the feature. As you've mentioned, you will often see it's registration in an Application/ResourceConfig subclass. But in a web.xml, you can simply add it to the list of classes to add as provider. You can do that by adding an <init-param> to the servlet configuration, i.e.
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.media.multipart.MultiPartFeature,
some.other.Provider
</param-value>
</init-param>
As you can see in the example, if you need to register any other providers/features, you comma-delimit the class names.

Togglz is throwing an IllegalStateException error

I keep on receiving a IllegalStateException: Could not find the FeatureManager when installing togglz in a web app on maven. I've followed the instuctions exactly. In my maven application, I have the following settings in my pom.xml file:
<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-core</artifactId>
<version>2.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-console</artifactId>
<version>2.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-servlet</artifactId>
<version>2.1.0.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
As well as the following in the web.xml file:
<context-param>
<param-name>org.togglz.core.manager.TogglzConfig</param-name>
<param-value>com.test.test.ana.FeatureFlagConfiguration</param-value>
</context-param>
<servlet>
<servlet-name>TogglzConsoleServlet</servlet-name>
<servlet-class>org.togglz.console.TogglzConsoleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TogglzConsoleServlet</servlet-name>
<url-pattern>/togglz/*</url-pattern>
</servlet-mapping>
This sample maven app runs fine, but when I try to go to the togglz virtual directory, it throws IllegalStateException: Could not find the FeatureManager error, it doesn't give much more detail than that. Any suggestions as to what that error really means?
I'm just trying to get a sample project that uses togglz that works. I can't use spring or cdi, just servlets. (yes, i have servlet 3.0 configured)
Thanks in advance,
Edit: Here is the exact stack trace:
[ERROR ] SRVE0777E: Exception thrown by application class 'org.togglz.core.context.FeatureContext.getFeatureManager:49'
java.lang.IllegalStateException: Could not find the FeatureManager. For web applications please verify that the TogglzFilter starts up correctly. In other deployment scenarios you will typically have to implement a FeatureManagerProvider as described in the 'Advanced Configuration' chapter of the documentation.
at org.togglz.core.context.FeatureContext.getFeatureManager(FeatureContext.java:49)
at org.togglz.core.manager.LazyResolvingFeatureManager.getDelegate(LazyResolvingFeatureManager.java:24)
at org.togglz.core.manager.LazyResolvingFeatureManager.getCurrentFeatureUser(LazyResolvingFeatureManager.java:49)
at org.togglz.console.TogglzConsoleServlet.isFeatureAdmin(TogglzConsoleServlet.java:68)
at org.togglz.console.TogglzConsoleServlet.service(TogglzConsoleServlet.java:55)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
at [internal classes]
If you are in a plain Servlet environment, you will have to do the following things after adding the Maven dependencies:
Implement your feature enum
This typically looks like this:
public enum MyFeatures implements Feature {
#EnabledByDefault
#Label("First Feature")
FEATURE_ONE,
#Label("Second Feature")
FEATURE_TWO;
public boolean isActive() {
return FeatureContext.getFeatureManager().isActive(this);
}
}
Configure Togglz by implementing TogglzConfig
A typical example looks like this:
public class MyTogglzConfiguration implements TogglzConfig {
public Class<? extends Feature> getFeatureClass() {
return MyFeatures.class;
}
public StateRepository getStateRepository() {
return new FileBasedStateRepository(new File("/tmp/features.properties"));
}
public UserProvider getUserProvider() {
return new ServletUserProvider();
}
}
Register your configuration class in web.xml
In a plain Servlet environment you will now have to register your TogglzConfig implementation by adding something like this to your web.xml:
<context-param>
<param-name>org.togglz.core.manager.TogglzConfig</param-name>
<param-value>com.example.myapp.MyTogglzConfiguration</param-value>
</context-param>
You should also explicitly tell Togglz that you do not want it to lookup the FeatureManager from Spring or CDI but to create and manage an instance itself:
<context-param>
<param-name>org.togglz.FEATURE_MANAGER_PROVIDED</param-name>
<param-value>true</param-value>
</context-param>
In Servlet 3.0 environments, the TogglzFilter is typically picked up automatically. However, you can also register it manually:
<filter>
<filter-name>TogglzFilter</filter-name>
<filter-class>org.togglz.servlet.TogglzFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TogglzFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I hope this help. If this still doesn't work, please include the full stacktrace in your question.

Spring's ResourceHttpRequestHandler returns 500 with NullPointerException

Short question: when asking for a static resource to my spring mvc application, I get a 500 error with a NullPointerException thrown at the end of the request processing at org.apache.coyote.Response.setContentType(Response.java:452)
Long question:
I'm using Spring 3.2.5 in a Maven project developed with Netbeans.
Here is my pom.xml
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
<groupId>net.pluce</groupId>
<artifactId>WorkTime</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>WorkTime</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<build>
... build infos
</build>
I configured my application to get Restfuls urls, so my web.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_0.xsd"
version="3.0">
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified #Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>net.pluce.worktime.config.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/JSP/*</url-pattern>
</servlet-mapping>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified #Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>net.pluce.worktime.config.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
I use the JspServlet trick because if I don't, the spring servlet try to handle my calls to view like "/WEB-INF/JSP/blabla.jsp"
My folder structure:
src
main
java
my/packages/to/config.MvcConfig
my/packages/to/config.AppConfig
webapp
META-INF
context.xml
WEB-INF
JSP
index.jsp
web.xml
assets
css
myassets.css
js
jquery.js
resources
log4j.properties
test
This is my AppConfig class:
#Configuration
public class AppConfig {
private String mongoUrl = "localhost";
private String mongoDb = "worktime";
public #Bean MongoFactoryBean mongo() {
MongoFactoryBean mongo = new MongoFactoryBean();
mongo.setHost(mongoUrl);
return mongo;
}
public #Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo().getObject(), mongoDb);
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
And my MvcConfig class:
#Configuration
#EnableWebMvc
#ComponentScan({"net.pluce.worktime"})
public class MvcConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/JSP/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
}
}
I've a controller which maps to the root and serves jsp correctly:
#Controller
public class IndexCtrl {
#Autowired
private MongoOperations ops;
#RequestMapping("/")
public String renderIndex(Model mav){
return "index";
}
}
And when I try to get my assets: GET http://localhost:8080/MyContextPath/assets/js/jquery.js, I get a 500 error:
exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:948)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
cause mère
java.lang.NullPointerException
org.apache.coyote.Response.setContentType(Response.java:452)
org.apache.catalina.connector.Response.setContentType(Response.java:806)
org.apache.catalina.connector.ResponseFacade.setContentType(ResponseFacade.java:245)
org.springframework.web.servlet.resource.ResourceHttpRequestHandler.setHeaders(ResourceHttpRequestHandler.java:240)
org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:146)
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:49)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
Reading the (relevant part of the) log:
17:15:00,652 DEBUG DispatcherServlet:823 - DispatcherServlet with name 'dispatcher' processing GET request for [/WorkTime/assets/js/jquery.js]
17:15:00,657 TRACE DispatcherServlet:1088 - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#4bbc3c6] in DispatcherServlet with name 'dispatcher'
17:15:00,658 DEBUG RequestMappingHandlerMapping:220 - Looking up handler method for path /assets/js/jquery.js
17:15:00,659 DEBUG RequestMappingHandlerMapping:230 - Did not find handler method for [/assets/js/jquery.js]
17:15:00,660 TRACE DispatcherServlet:1088 - Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping#4331fe97] in DispatcherServlet with name 'dispatcher'
17:15:00,660 TRACE BeanNameUrlHandlerMapping:127 - No handler mapping found for [/assets/js/jquery.js]
17:15:00,660 TRACE DispatcherServlet:1088 - Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#7418df8] in DispatcherServlet with name 'dispatcher'
17:15:00,660 DEBUG SimpleUrlHandlerMapping:169 - Matching patterns for request [/assets/js/jquery.js] are [/assets/**]
17:15:00,661 DEBUG SimpleUrlHandlerMapping:194 - URI Template variables for request [/assets/js/jquery.js] are {}
17:15:00,661 DEBUG SimpleUrlHandlerMapping:124 - Mapping [/assets/js/jquery.js] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler#60cf9880] and 1 interceptor
17:15:00,662 TRACE DispatcherServlet:1122 - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#5d252d27]
17:15:00,662 TRACE DispatcherServlet:1122 - Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter#33b78b37]
17:15:00,662 DEBUG DispatcherServlet:912 - Last-Modified value for [/WorkTime/assets/js/jquery.js] is: -1
17:15:00,663 DEBUG ResourceHttpRequestHandler:173 - Trying relative path [js/jquery.js] against base location: ServletContext resource [/assets/]
17:15:00,674 DEBUG ResourceHttpRequestHandler:178 - Found matching resource: ServletContext resource [/assets/js/jquery.js]
17:15:00,674 DEBUG ResourceHttpRequestHandler:132 - Determined media type 'application/javascript' for ServletContext resource [/assets/js/jquery.js]
17:15:00,675 DEBUG ResponseStatusExceptionResolver:132 - Resolving exception from handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler#60cf9880]: java.lang.NullPointerException
17:15:00,676 DEBUG DefaultHandlerExceptionResolver:132 - Resolving exception from handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler#60cf9880]: java.lang.NullPointerException
17:15:00,676 TRACE DispatcherServlet:1028 - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#16fd089a
17:15:00,677 DEBUG DispatcherServlet:959 - Could not complete request
java.lang.NullPointerException
at org.apache.coyote.Response.setContentType(Response.java:452)
at org.apache.catalina.connector.Response.setContentType(Response.java:806)
at org.apache.catalina.connector.ResponseFacade.setContentType(ResponseFacade.java:245)
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.setHeaders(ResourceHttpRequestHandler.java:240)
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:146)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:49)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
17:15:00,680 TRACE AnnotationConfigWebApplicationContext:332 - Publishing event in WebApplicationContext for namespace 'dispatcher-servlet': ServletRequestHandledEvent: url=[/WorkTime/assets/js/jquery.js]; client=[127.0.0.1]; method=[GET]; servlet=[dispatcher]; session=[C2D001FA38DB36BD6286C598E46652D2]; user=[null]; time=[38ms]; status=[failed: java.lang.NullPointerException]
17:15:00,681 TRACE AnnotationConfigWebApplicationContext:332 - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/WorkTime/assets/js/jquery.js]; client=[127.0.0.1]; method=[GET]; servlet=[dispatcher]; session=[C2D001FA38DB36BD6286C598E46652D2]; user=[null]; time=[38ms]; status=[failed: java.lang.NullPointerException]
What I read:
- My request is processed by Spring dispatcher servlet
- the request is mapped to ResourceHttpRequestHandler
- ResourceHttpRequestHandler finds the matching resource in my files
- it determines the good media type "application/javascript"
- a NullPointerException is thrown when the Response is being written.
I had a look to the Response.setContentType() method and found nothing worth a NullPointerException.
Thanks in advance

Categories