JAX-RS Jersey - Howto force a Response ContentType? Overwrite content negotiation - jersey

Jersey identifies requests by looking at the accept header. I have a request which accepts only text/* - How can i force the response to be for example application/json?
#POST
#Path("/create")
#Produces(MediaType.APPLICATION_JSON)
public MyResponseObject create() {
return new MyResponseObject();
}
If a request is directed to create which only accepts text/* jersey will return a 500. Is there a way to workaround this issue? (I can't change the requests accept header).

Jersey also supports this via ResourceConfig property PROPERTY_MEDIA_TYPE_MAPPINGS that you could configure in your web.xml or programatically via Jersey APIs as shown below:
DefaultResourceConfig rc = new DefaultResourceConfig(MyResource.class);
rc.getMediaTypeMappings().put("json", MediaType.APPLICATION_JSON_TYPE);
rc.getMediaTypeMappings().put("xml", MediaType.APPLICATION_XML_TYPE);
SimpleServerFactory.create("http://localhost:9090", rc);
You can force content type negotiation by suffixing either .json or .xml to your URL.

I solved this by using a servlet filter:
http://www.zienit.nl/blog/2010/01/rest/control-jax-rs-content-negotiation-with-filters

Related

POX and SOAP on the same endpoint

I have a requirement where I need to expose the service for both SOAP and POX incoming requests.I included the following code snippet to switch from SOAP to POX and it worked fine
#Bean(name = MessageDispatcherServlet.DEFAULT_MESSAGE_FACTORY_BEAN_NAME)
public WebServiceMessageFactory messageFactory() {
return new DomPoxMessageFactory();
}
But to make the application accept SOAP requests I commented the above code.
Obviously,its not the desired solution and I need my application to accept both SOAP and POX without this code change.Can you please suggest a proper approach?

Spring Boot + Jersey type filter - Bad request 400 for service Consumes MULTIPART_FORM_DATA

I'm using Spring boot v1.5.10 + Jersey v2.25.1, configured jersey as filter to access static folder files. I'm getting HTTP response 400 Bad Request for a service consuming MULTIPART_FORM_DATA.
Props to configure Jersey as filter.
spring.jersey.type=filter
If I remove above property i.e., using Jersey as Servlet, the service is working, but I'm not able to access static folder.
Here is the controller,
#POST
#Path("/save")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public ResponseBean save(
#FormDataParam("fileToUpload") InputStream file,
#FormDataParam("fileToUpload") FormDataContentDisposition fileDisposition,
#FormDataParam("fromData") FormDataDto data) {
// stuff
}
EDIT:
GitHub link https://github.com/sundarabalajijk/boot-jersey
When you start the app, spring.jersey.type=filter
http://localhost:8080/ (works)
http://localhost:8080/hello.html (works)
http://localhost:8080/save (not working) - used postman.
When spring.jersey.type=servlet
http://localhost:8080/ (works)
http://localhost:8080/hello.html (not working)
http://localhost:8080/save (works)
After some research and finding related issues1, it seems that Spring's HiddenHttpMethodFilter reads the input stream, which leaves it empty for any other filters further down the filter chain. This is why we are getting a Bad Request in the Jersey filter; because the entity stream is empty. Here is the note from the Javadoc
NOTE: This filter needs to run after multipart processing in case of a multipart POST request, due to its inherent need for checking a POST body parameter.
So what we need to do is configure the Jersey filter to be called before this Spring filter2. Based on the Spring Boot docs, there is a property we can use to easily configure the order of this filter.
spring.jersey.filter.order
Doing a Github search in the Spring Boot repo for the HiddenHttpMethodFilter, we can see the subclass that is used OrderedHiddenHttpMethodFilter, where the order is set to -10000. So we want to set the order of our Jersey filter to less than that (higher precedence). So we can set the following value
spring.jersey.filter.order=-100000
If you test it now, it should now work.
One more thing we need to fix is the order of the Spring RequestContextFilter. This is originally configured to be ordered to be called right before the Jersey filter. When we set the order configuration above for the Jersey filter, the RequestContextFilter stays where it was originally at. So we need to change this. We can do this just by adding a bean to override the original one and set the order.
#Bean
public RequestContextFilter requestContextFilter() {
OrderedRequestContextFilter filter = new OrderedRequestContextFilter();
filter.setOrder(-100001);
return filter;
}
Now if we check the logs on startup, we should see the filer ordering we want.
Mapping filter: 'characterEncodingFilter' to: [/*]
Mapping filter: 'requestContextFilter' to: [/*]
Mapping filter: 'jerseyFilter' to urls: [/*]
Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
Mapping filter: 'httpPutFormContentFilter' to: [/*]
Aside
The reason you need to configure Jersey as a filter in your case is because of the static content. If you don't configure the root path for the Jersey app, then it defaults to /*, which will hog up all requests, included those to the static content. So Jersey will throw 404 errors when requests are made for the static content. We configure Jersey as a filter and tell it to forward request that it cannot find.
If we were to just configure the root path for Jersey, then we would not need to worry about this problem with the static content, and we would be able to just leave Jersey configured as a servlet by default.
To change the base path for the Jersey app, we can either add the #ApplicatuonPath annotation to our ResourceConfig or we can use the property spring.jersey.application-path
#Component
#ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {
...
}
or in your application.properties
spring.jersey.application-path=/api
See also
File upload along with other object in Jersey restful web service. This has some information on how you can accept JSON as a body part in the multipart request.
Footnotes
1. Some issues to look at [ 1, 2 ]
2. See Change order of RequestContextFilter in the filter chain
I guess the accepted answer is not up to date anymore. With Spring Boot 2 I did not have such problems. There was one issue though. I had a custom filter which was calling getParameterMap on the request object. Apparently getParameterMap implicitly reads the input stream of the request which then gets closed afterwards so that no other code can read the request body anymore.
Strangely with the setting spring.jersey.type=servlet I could get the request body even though getParameterMap was called beforehand, so I guess the implementation of ServletRequest is different depending on what you have configured for spring.jersey.type.

Spring cloud Feign:no suitable HttpMessageConverter found for response type [class org.springframework.web.servlet.ModelAndView]

I have a service which has a url that return ModelAndView Object.
In its own point, I can access the website. But when I use spring cloud feign to invoke that url, it comes out that no suitable HttpMessageConverter found for response type [class org.springframework.web.servlet.ModelAndView] and contentType text/html. Here is my feign client.
Please try to change empList() method in your ConsumerController class like below.
public String empList() {
return empService.empList();
}
ModelAndView is not the actual response of /emplist from EmpController. It will be handled by DispatchServlet and ViewResolver will resolve the actual view with your view name - emp. So, from the view of ConsumerController, The response will be String object.
Anyway, I'm not sure that it's a good idea that accessing another web page via feign client in your case. Because if the original html page contains additional resources like images that existing in your origin server, it will not be served.

How to send the send status code as response for 404 instead of 404.jsp as a html reponse in spring?

I created web application in spring and handled exception mappings for 404 and 500.If system doesn't find any resources for requested URL it redirects into custom 404.jsp instead of regular 404 page.Everything works fine till have decided to add a webservice in my app.I have included one more controller as a webservice there is no view for this controller and this needs to be invoke through curl command.
User may get into change the curl script.If they changed the URL it should show 404 status code.But it returns the custom 404.jsp as a html response instead of status code.Because dispatcher servlet will takes all urls with /*.
How I can solve this issue?
Please share your suggestions.
Spring 3.2 introduced the #ControllerAdvice, and as mentioned in the documentation:
It is typically used to define #ExceptionHandler
That means you can use the #ControllerAdvice to assist your #Controller like the following:
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.NOT_FOUND) // 404
#ExceptionHandler(Exception.class)
public void handleNoTFound() {
// Nothing to do
}
}
For further details please refer to this tutorial and this answer.

Spring Data REST CORS - how to handle preflight OPTIONS request?

I'm using Spring Data REST to build a RESTful API. Until now my HTML GUI for this RESTful service was served from the same Tomcat and I had no problems wit Cross Origin requests.
Now I want to serve the static files from a different server. This means the API is on another domain/port. Browsers will send the OPTIONS request to get the Access-Control headers from the server. Unfortunately Spring Data REST does not handle those OPTIONS requests and even returns a HTTP 500.
I tried creating a custom controller that handles all OPTIONS requests
#Controller
#RequestMapping(value = "/**", method = RequestMethod.OPTIONS)
public class OptionsController {
#RequestMapping
public ResponseEntity options() {
return new ResponseEntity<Void>(HttpStatus.OK);
}
}
Which worked for OPTIONS, but then all other requests (like GET) ceased to work.
OPTIONS requests are switched on via the dispatchOptionsRequest dispatcher servlet parameter.
tl;dr: currently Spring Data REST does not answer OPTIONS requests at all.
It might be worth opening a ticket in our JIRA.
Browsers will send the OPTIONS request to get the Access-Control headers from the server.
Is that specified somewhere? If so, it would be cool if the ticket description included a link to that spec.
A few comments regarding your approach for a workaround:
#RequestMapping on the controller method overrides the method attribute and expectedly now matches all HTTP methods, which is why you see all requests intercepted. So you need to define OPTIONS as HTTP method there, too (or maybe instead of in the class mapping).
You're not returning any Allow header which is the whole purpose of OPTIONS in the first place.
I wonder if the approach in general makes sense as it'll be hard to reason about the supported HTTP methods in general.
Just set the parameter dispatchOptionsRequest to true into the dispatcher to process the Options method calls, into the implementation of the WebApplicationInitializer.
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(applicationContext));
dispatcher.setInitParameter("dispatchOptionsRequest", "true");
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");

Resources