Spring MVC Servlet being hit twice for a POST request - rest

I've got an estrange issue while using Spring MVC in order to implement RESTful services for my web application. Everything seems to work OK while performing GET requests, however, the behaviour I'm dealing with when doing POST requests puzzles me. Well, I've implemented this very basic controller code:
#Controller
#RequestMapping("/services")
public class RestService {
#RequestMapping(value = "/test/post", method = RequestMethod.POST)
public void postTest(#RequestBody String postString)
throws PersistenceException {
System.out.println(postString);
}
}
When I perform a POST request against it using Curl:
curl --data "Hello world" http://localhost:8080/SpringMVC-REST/services/test/post
First time my Controller is reached properly and the String is displayed. However, don't know why, the Spring MVC servlet is being called again after that, in this case with a wrong url request. The framework is not finding the matching service case, obviously:
Jun 02, 2014 4:06:21 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/SpringMVC-REST/services/test/services/test/post] in DispatcherServlet with name 'mvc-dispatcher'
Debugger's stack seems to be slightly different for the first and second cases:
It seems like second time the Spring MVC framework is trying to render the output, even I'm not interested in it, cause I'm not accesing it via web UI. The servlet configuration I use is the standard one:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC REST</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
That happens to me with Tomcat 6 and 7 and spring-web 3.2.8.RELEASE. Can anybody see the problem here?

use #ResponseBody before method return type..it should solve your problem.
so it should be like
#Controller
#RequestMapping("/services")
public class RestService {
#RequestMapping(value = "/test/post", method = RequestMethod.POST)
public #ResponseBody void postTest(#RequestBody String postString)
throws PersistenceException {
System.out.println(postString);
}
}

Related

Jersey tomcat and eclipse: error 404

I was following vogella "REST with Java (JAX-RS) using Jersey - Tutorial".
I created a new dynamic web project named "project" generating web.xml file.
I added all jar files from jaxrs-ri-2.23.1 in "eclipseWorkspace/project/WebContent/WEB-INF/lib"
I created a new class named Hello and copied the content from vogella tutorial:
package project;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
// Plain old Java Object it does not extend as class or implements
// an interface
// The class registers its methods for the HTTP GET request using the #GET annotation.
// Using the #Produces annotation, it defines that it can deliver several MIME types,
// text, XML and HTML.
// The browser requests per default the HTML MIME type.
//Sets the path to base URL + /hello
#Path("/hello")
public class Hello {
// This method is called if TEXT_PLAIN is request
#GET
#Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello() {
return "Hello Jersey";
}
// This method is called if XML is request
#GET
#Produces(MediaType.TEXT_XML)
public String sayXMLHello() {
return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";
}
// This method is called if HTML is request
#GET
#Produces(MediaType.TEXT_HTML)
public String sayHtmlHello() {
return "<html> " + "<title>" + "Hello Jersey" + "</title>"
+ "<body><h1>" + "Hello Jersey" + "</body></h1>" + "</html> ";
}
}
I modified web.xml in this way:
<?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" id="WebApp_ID" version="3.0">
<display-name>project</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Register resources and providers under com.vogella.jersey.first package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>project</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Right click on project name, run as, Run on server. Choosed the existing tomcat v7 server at localhost.
Restarted server.
When i go to:
http://localhost:8080/project/rest/hello
It shows 404 error:
HTTP Status 404 - Not Found
type Status report
message Not Found
description The requested resource is not available.
Apache Tomcat/7.0.70
Do you know how to solve this?
Solved unselecting the option "Build Automatically" in eclipse.
Then "Build project" and "Run on server" and it works.

Jersey REST service

Am using Jersey 1.19 for a REST service..
The URL pattern in web.xml is:
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
In the Java class am using a method which is doing a kind of redirect to another page saved in a web folder. It looks fine up to the point when I call a specific resource:
http://localhost:8084/userProfile/rest/user
This should redirect to:
http://localhost:8084/userProfile/signup/index.jsp
but it redirects to:
http://localhost:8084/userProfile/rest/signup/index.jsp
Which normally doesn't exist.
The method in the Java Class:
#Path("/user")
public class userProfile {
#GET
#Produces(MediaType.TEXT_HTML)
public Response returnForm() throws URISyntaxException {
URI uri = new URI("/signup/index.jsp");
return Response.temporaryRedirect(uri).build();
}
}
How can I avoid redirection to a URL including /rest/?
The solution is/was really simple... the Path should go one step back to
avoid the url-pattern /rest/*:
....
URI uri = new URI("../signup/index.jsp");
...
Thx!

No 'Access-Control-Allow-Origin' header is present on the requested resource - Resteasy

I am working on a webapplication comprises UI-Angular , Server-Java , RestEasy 3.0.9.Final for rest api calls
When i tried to access the rest service from another domain am getting below error
CANNOT LOAD Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
I configured my server side to respond with the cross domain calls and this is working with the GET Call but POST Call is creating ERROR
web.xml
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.test.sample.app.CorsFeature</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.sample.app.Application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
Service class
#GET
#Path("/getnameAtt")
#Produces(MediaType.APPLICATION_JSON)
public Response getHostnameAttributes() {
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(new TestImpl().getHostNameAttributes())
.build();
}
#POST
#Path("/getSeq")
#Produces(MediaType.APPLICATION_JSON)
public Response getCurrentSequence(String request) {
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(new TestImpl().getCurrentSeq(request))
.build();
}
Since i am new to resteasy not able to figure out why this was not working.
Any help would be greatly appreciated . Waiting for your response.
Thanks
Your resource methods won't get hit, so their headers will never get set. The reason is that there is what's called a preflight request before the actual request, which is an OPTIONS request. So the error comes from the fact that the preflight request doesn't produce the necessary headers.
For RESTeasy, you should use CorsFilter. You can see here for some example how to configure it. This filter will handle the preflight request. So you can remove all those headers you have in your resource methods.
See Also:
HTTP access control (CORS)
Seems your resource POSTmethod won't get hit as #peeskillet mention. Most probably your ~POST~ request won't work, because it may not be a simple request. The only simple requests are GET, HEAD or POST and request headers are simple(The only simple headers are Accept, Accept-Language, Content-Language, Content-Type= application/x-www-form-urlencoded, multipart/form-data, text/plain).
Since in you already add Access-Control-Allow-Origin headers to your Response, you can add new OPTIONS method to your resource class.
#OPTIONS
#Path("{path : .*}")
public Response options() {
return Response.ok("")
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "2000")
.build();
}
After facing a similar issue, below is what I did :
Created a class extending javax.ws.rs.core.Application and added a Cors Filter to it.
To the CORS filter, I added corsFilter.getAllowedOrigins().add("http://localhost:4200");.
Basically, you should add the URL which you want to allow Cross-Origin Resource Sharing. Ans you can also use "*" instead of any specific URL to allow any URL.
public class RestApplication
extends Application
{
private Set<Object> singletons = new HashSet<Object>();
public MessageApplication()
{
singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
CorsFilter corsFilter = new CorsFilter();
// To allow all origins for CORS add following, otherwise add only specific urls.
// corsFilter.getAllowedOrigins().add("*");
System.out.println("To only allow restrcited urls ");
corsFilter.getAllowedOrigins().add("http://localhost:4200");
singletons = new LinkedHashSet<Object>();
singletons.add(corsFilter);
}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
}
And here is my web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Restful Web Application</display-name>
<!-- Auto scan rest service -->
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
The most important code which I was missing when I was getting this issue was, I was not adding my class extending javax.ws.rs.Application i.e RestApplication to the init-param of <servlet-name>resteasy-servlet</servlet-name>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
And therefore my Filter was not able to execute and thus the application was not allowing CORS from the URL specified.

RESTEasy Asynchronous Job Service + Spring MVC?

I am using the RESTEasy integration with Spring MVC as described here in section "39.2. Spring MVC Integration"
http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html/RESTEasy_Spring_Integration.html
I'd like to experiment with RESTEasy's implementation of the "async job service" as described here:
http://docs.jboss.org/resteasy/docs/2.3.4.Final/userguide/html/async_job_service.html
Reading the doc, my assumption is that RESTEasy will intercept the request and respond with a HTTP 202 and do the job queueing and tracking and create the .../async/jobs endpoint. So I modified my web.xml as described in the documention. Here's what it looks like:
<web-app>
<context-param>
<param-name>resteasy.async.job.service.enabled</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.async.job.service.base.path</param-name>
<param-value>/asynch/jobs</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
I tried to test whether this works by making a call to one of my REST services like this (running under Tomcat 6):
POST http://localhost:8080/myservice?async=true
According to the documentation this service is supposed to return a HTTP 202 but it returned the normal HTTP 200 as if I had called without the async=true query param.
I didn't change anything else with my services. Am I missing something?
Btw, here's what the service annotation looks like:
#Controller
#Path("/")
public class MyServices {
#POST
#Produces({MediaType.APPLICATION_XML})
#Path("myservice")
public Response createMyResource(#Context UriInfo uri, myResource) {
// create the resource
// construct and return a OK Response
}
}
Has anyone tried this successfully? If not, do you have another easy to use alternative for making async calls to RESTEasy RESTful services (that also works with Spring running under tomcat)
Thanks.
Try with asynch=true not async=true

REST Service - #POST call works while #GET doesn't

I am very new in REST services and I am facing a problem during the last two weeks. I am using Jersey. I am trying to use a simple REST client in order to call a POST method, which accepts a JSON object as a parameter and stores it to a database. My approach didn't work, but I decided to go one step behind, so now I am using an even simpler client with a simpler provider, in order to just test my POST and GET methods. The strange thing is that while I am able to call the POST method:
#POST
#Path("/store")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.TEXT_PLAIN)
public String storeData(String str) throws SQLException {
String query = "insert into myDB.test (id, name) values ('1', '" + str + "')";
MyDB db = new MyDB();
db.runQuery(query);
return responseCode.toString();
}
This works just fine!
But in the same class, the #GET method is not working and returns a 404 error.
My code is as following:
#GET
#Path("/retrieve")
#Produces(MediaType.TEXT_PLAIN)
public String getResponse() {
return "Hello!";
}
I know that my question might be quite simple to many... but I'm trying to find out what I'm doing wrong so as to go on to my actual implementation...
Thanks a lot in advance.
Marina
here is my client-side code
public class TestClient {
public static void main(String[] args) {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("http://localhost:8080/server_classes/rest/server/retrieve");
System.out.println(webResource.accept(MediaType.TEXT_PLAIN).post(ClientResponse.class, "hello"));
}
}
And here is my web.xml:
<?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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>server_classes</display-name>
<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>server_classes</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
My package is named server_classes and the resource's path is #Path("/server")
I tried the vogella tutorial again, from the beginning, just changing the annotation paths and the methods (for not just giving a "Hello Jersey" response). But now, I am not able to run anything. There is only a 404 error!
O also deleted Tomcat's instance, then the whole tomcat installation and re-installed it, the problem still the same. I am working on Ubuntu 12.04 if this helps..
Thanks!
try to change your request from post to get, as your servlet-mapping expects:
webResource.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);