Tomcat trying to resolve JSP files in RESTful Spring MVC Service - java

I am using Spring MVC to create a RESTful service, using the #Controller and #RequestMapping annotations to control responses. I am also using Maven as a dependency management system.
In one function, I use a URI template in my #RequestMapping to retrieve a variable from the GET request. This function returns JSON when it is complete.
Due to problems with the JSTL libraries as a result of using URI templates (essentially I was getting 500 status codes because of a ClassNotFoundException with a JSTL class), I had to add the following dependencies to my Maven POM file (these come from our private repository, but you should be able to understand what they are):
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2-rev-1</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.2</version>
</dependency>
However, as a result of adding these, I now get 404 errors, because Tomcat (which is handling the requests under Spring) is trying to resolve my URI, which is usually
localhost:9095/DiagnosticToolService/demo-object/1/json (the 1 being my GET variable, of course)
to a file, specifically
localhost:9095/DiagnosticToolService/WEB-INF/jsp/demo-object/1/json.jsp
Of course, this file does not exist. How do I turn off this automatic JSP resolution in Tomcat so that it can work properly? Also, are those the dependencies I needed to add to fix the 500 error? The 500 error and the 404 error are shown below:
The 500 error
The 404 error

Are you using #ResponseBody on your controller method that produces JSON? from the description of the problem it looks like the request is not making it to your controller or the return value from the controller is interpreted as a view name.
Can you post the mapping you are using on the controller just the method signature?

Related

Unable to display index.html in jax rs with spring boot

I am trying to create a simple app with jax rs, springboot, angular.
I have placed the index.html in static folder, but while hitting the url localhost:8080/index.html or localhost:8080 it's throwing 404 not found error through the custom exception handler. I have added index.html as welcome-file-list.
I have a controller class but i have not written any specific method to handle it.
Also i want to display error specific page with message details.
Definitely i am missing something but not getting any pointer to find it out. Please help.
Do i need to configure web.xml explicitly for this?
Add
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
To your pom.xml file, spring boot auto configure all the rest.
I know this is older, but to expand on Itsik's answer I found this answer via this other answerto be very helpful in explaining this.
Summed up, if you want to be able to serve up resources/static/index.html AND use JAX-RS/jersey for api endpoints, include both spring-boot-start-web and spring-boot-starter-jersey. In your JerseyConfig add #ApplicationPath("/api") or whatever subpath you want all your jax-rs rest endpoints to live under. Then you will be able to have the best of both worlds.

Don't understand how Spring (Boot) Data REST is told to create API endpoints

I have currently have an application that is using Spring Boot and Spring Data. I have my domain objects that were reverse engineered from my database and I have several repositories (classes). Each repository is an interface that extends the CrudRepository.
import org.springframework.data.repository.CrudRepository
interface MyDomainClassRepository extends CrudRepository<MyDomainClass, Integer> {
private MyDomainClass findByName(String name);
}
At this point I would create a service that would implement these items. The service would then be called by a REST controller.
I wanted to be able to have Spring create my REST API automatically if possible and I found the Spring Data REST project. I found this http://spring.io/guides/gs/accessing-data-rest/ and I can follow that guide, but I don't understand what is enabling the "REST APIs" to be created "automatically". I could understand it if the #RepositoryRestResource annotation caused the API to be created but in that guide it explicitly says
RepositoryRestResource is not required for a repository to be exported. It is only used to change the export details, such as using /people instead of the default value of /persons.
Does including in my POM file and rebuilding "automatically" allow Spring Data to create the REST endpoints?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
What keyword, section am I missing that makes it so the API endpoint is created automatically?
Spring Boot is opinionated. It has opinions like using tomcat as your application server or logback as your logging utility. When you pull in
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
It has opinions that when it detects (by classpath scanning) interfaces/classes that extend/implement Repository it will assume that those classes should be served as RESTful resources. RestRepository allows you to customize this behavior by changing the endpoint or not serving the resource at all (exported = false).
Spring-Data-REST does automatically setup the resource to handle GET/POST/PUT/DELETE requests. Are you familiar with REST/HTTP? Those would not be discrete endpoints, GET/PUT/POST/DELETE are http verbs, so there wouldn't be a resource/1/delete endpoint.
Spring Data Rest implements six controllers, in the package org.springframework.data.rest.webmvc:
RepositoryController: handles /
RepositoryEntityController: handles /{repository}
RepositoryPropertyReferenceController: handles /{repository}/{id}/{property} and /{repository}/{id}/{property}/{propertyId}
RepositorySearchController: handles /{repository}/search and /{repository}/search/{repoFunctionName}
ProfileController: handles /profile
RepositorySchemaController: handles /profile/{repository}
They are essentially the same as Spring MVC Controllers, except they are designed to work with Spring Data repositories in a general way
So, if you do GET /foo where foo is the path of your fooRepository, then Spring Data Rest will call RepositoryEntityController.getCollectionResource(), and invoke fooRepository.findAll(...), wrap the result in some HATEOAS objects, then marshal to JSON, using Jackson

force json from jersey response

I am trying to implement this example. The first method in FileResource is supposed to return a json response, but the response is coming through as XML. I have never used jersey before. I tried adding #produces yielding this:
#GET #Produces("application/json")
#Path("/url")
public Response getCallbackUrl() {
String url = blobstoreService.createUploadUrl("/rest/file");
return Response.ok(new FileUrl(url)).build();
}
Now I'm getting
A message body writer for Java class FileUrl, and Java type class FileUrl, and MIME media type application/json was not found
How can I fix this? Thanks for any help. And if you need any more info let me know. I don't know much of the jersey terminology.
You need a few more dependencies in order to produce JSON output.
Take a look at: http://jersey.java.net/nonav/documentation/latest/chapter_deps.html
Scroll down to:
11.4.1.2. MOXy
Maven developers, using JSON serialization support of JAXB beans when using the MIME media type application/json require a dependency on the jersey-json module (explicit dependency on org.eclipse.persistence.moxy is required).
An alternative to "vanilla" Jersey that you might be interested in is Dropwizard. Their blurb is:
Dropwizard has out-of-the-box support for sophisticated configuration, application metrics, logging, operational tools, and much more, allowing you and your team to ship a production-quality HTTP+JSON web service in the shortest time possible.
Yep you'll need some jersey / json dependency here :
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.2</version>
</dependency>
with your version of jersey of course.

Spring Security with path variable parameters

I would like to create security rules based on custom url parameters (path variables).
In example. Let say I want to have user that has admin access for resources called Brand1 and Brand2 but has no access to resource called Brand3. We may edit resources using following links.
http://myapp/brand/edit/1
http://myapp/brand/edit/2
http://myapp/brand/edit/3
now in security context I would like to do something like that
<security:intercept-url pattern="/brand/edit/{brandId}"
access="hasRole('ROLE_ADMIN') or
#authorizationService.hasBrandPermission(
#brandId, principal.username)"/>
The only thing I get is username. BrandId is always null.
I used to do that with #PreAuthorize and it worked but now I would like to centralized security configuration in single xml file instead of spreading it across all controller classes. Moreover when I was using #PreAuthorize my access-denied-handler did not redirect me into denied page but display ugly AccessDeniedException insead.
I would really aprecieate any ideas.
Change the Spring Security version in your pom.xml to 4.1.0.RELEASE:
<spring-security.version>4.1.0.RELEASE</spring-security.version>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
You may need to clean your maven project after that.
(I know, it's an old question. Nonetheless, I faced same issue 3 years later).
you can try using regular expression.
you will need to add the attribute path-type="regex" in your http element or request-matcher="regex" if your using spring security 3.1
see the documentation for more details

Forwarding request to a JSP

I discovered Guice last week... I'm trying some easy tricks with it. However, I'm currently blocked...
I'm trying to forward a request to a JSP in a Servlet served by an url-pattern which contains a " * ". But I receive "Error 404" all the time :(
Step by Step :
ServletModule :
serve("/test/*").with(TestServlet.class);
TestServlet :
public void doGet(HttpServletRequest req, HttpServletResponse resp)
{
System.err.println("Start");
try
{
req.getRequestDispatcher("/WEB-INF/layout/test.jsp").forward(req, resp);
}
catch (Exception e)
{
e.printStackTrace();
}
}
I get this error :
HTTP ERROR 404
Problem accessing /WEB-INF/layout/test.jsp. Reason:
/WEB-INF/layout/test.jsp
I tested with "serve("/test").with(TestServlet.class);" and it worked
I tested without Guice (by defining servlet in the web.xml) and it worked...
What did I do wrong?
Thank for reading!
Client can't access resources from Web-INF directly (by url). So forwarding doesn't work in this case. But your servlets can. So just use include instead of forward.
There's a good chance you didn't do anything wrong at all. There is a bug in Guice, arising from their mishandling of Include and Forward attributes against servlet standards, as described here...
http://code.google.com/p/google-guice/issues/detail?id=647
The upshot is that the receiving servlet is misinformed about the path, and hence requests to load resources do not find their proper target even if they are specified correctly and even if the same code works when using web.xml (which is interpreted by your servlet engine and not by Guice).
I'm endlessly puzzled why this doesn't act as a dead-end for many many projects in Guice, so perhaps there's something in the behaviour of other servlet engine configurations which masks this error. I'm using Jetty launched explicitly in Java using Server#start(); and it is a deal-breaker for a lot of server logic.
However, the Guice team seems to have been studiously ignoring the bug for a long time, even when a patch was provided to them against v2.0. What they need is a test-case written against their SVN build but I've never succeeded given all the work needed to create stubs which emulate the servlet engine and so on.
The problem has been partially fixed in guice and guice servlet 3.1.1 with one problem still taking place:
When mapping a servlet using the asterisk pattern '/*' as below:
serve("/myservlet/*").with(MyServlet.class);
And have MyServlet.java forward to a jsp page, then the forward() will only work if the jsp page has no underscores (So, myservlet.jsp will work, my_servlet.jsp wont work).
// This WORKS
req.getRequestDispatcher("/myservlet.jsp").forward(req,resp);
// These DONT WORK (any file having _ or - characetsrs wont work)
req.getRequestDispatcher("/my_servlet.jsp").forward(req,resp);
req.getRequestDispatcher("/my-servlet.jsp").forward(req,resp);
req.getRequestDispatcher("/WEB-INF/myservlet.jsp").forward(req,resp);
Now this explains why WEB-INF forwarding does not work for a servlet mapped with /*. The reason is that WEB-INF contains a dash character which for some reason is creating a problem for guice servlet.
When trying the example above, make sure to rename the file myservlet.jsp to my_servlet.jsp when trying the cases to verify the case above.
I have no idea why this weird case is taking place.
NOTE: I'm using Tomcat 6.0.35
To have Guice 3.1.1 add these to your pom.xml
<dependency>
<groupId>org.sonatype.sisu</groupId>
<artifactId>sisu-guice</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.sonatype.sisu.inject</groupId>
<artifactId>guice-servlet</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.sonatype.sisu.inject</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
Or you can download the jars from:
Guice Servlet Jar
http://repo1.maven.org/maven2/org/sonatype/sisu/inject/guice-servlet/3.1.1/
Guice Jar
http://repo1.maven.org/maven2/org/sonatype/sisu/sisu-guice/3.1.1/

Categories