Jersey Viewable with Json - java

The JAX-RS implementation Jersey supports MVC style web applications through the Viewable class, which is a container for a template name and a model object. It is used like this:
#GET
#Template
#Produces({MediaType.TEXT_HTML})
public Viewable get() {
JsonObject response = null;
try{
response = service.getDetails(id);
}
catch(Exception ex) {
log.error("failed to get details", ex);
throw ex;
}
return new Viewable("/test", response);
}
this is right way to send the json from Viewable? Is there a way to set a json object explicitly?

A few things: I don't have any experience using Viewable in particular, but I am familiar with JAX-RS and can probably throw a couple of pointers your way.
Exception Handlers
JAX-RS defines a feature for mapping exceptions to responses. This functionality is nice for removing those exception blocks from your resource code. Check out the Jersey docs on this topic for a tutorial on how to register these. A quick summary is: 1) implement ExceptionMapper and 2) register the class as a Provider.
For starters, I recommend creating a simple suite that maps to common HTTP codes. For example:
NotFoundException - returns a 404 response and is used when a single entity is requested but not found.
InvalidInputException - returns a 422 response and is used when a request does not pass validation (like trying to save an phone number in an email field).
BadRequestException - usually the framework will handle these situations for you, but if not, a Bad Request is one that is not formatted properly. So if a required header is missing, or if a client tries to save a collection when only a single entity is allowed.
Exception* - There is a star here because an unexpected exception is usually due to a server error, so 500 is an appropriate default response. A reason you may want to create a global uncaught exception handler is to prevent the stacktrace from being returned in the response body. That can be bad for security reasons.
View and Model
You should not need the #Template annotation if you are using the Viewable object. Also, Viewable is expecting a template as the first argument and a model (map) as the second argument. The model should have keys that match variables in your JSP. Right now your method will look for a file called test.jsp in the root of whatever your template config is set to in web.xml. If you take all of that into consideration, your method could look something like this:
#GET
#Produces(MediaType.TEXT_HTML)
public Viewable getMobileReport() {
return new Viewable("/test", service.getMobileReport(id));
}

Related

How do I change only the status code on a Spring MVC error with Boot?

I'm writing a Web application that makes downstream calls using RestTemplate. If the underlying service returns a 401 Unauthorized, I want to also return a 401 to the calling application; the default behavior is to return a 500. I want to keep the default Spring Boot error response as provided by BasicErrorController; the only change I want is to set the status code.
In custom exceptions, I'd just annotate the exception class with #ResponseStatus, but I can't do that here because HttpClientErrorException.Unauthorized is provided by Spring. I tried two approaches with #ControllerAdvice:
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void returnsEmptyBody(HttpClientErrorException.Unauthorized ex) {
}
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void doesNotUseBasicErrorController(HttpClientErrorException.Unauthorized ex) {
throw new RuntimeException(ex);
}
How can I configure MVC to continue to use all of the built-in Boot error handling except for explicitly overriding the status code?
The below code works for me -- in an app consisting of a #RestController whose one method consisted of throw new HttpClientException(HttpStatus.UNAUTHORIZED), running on an embedded Tomcat. If you're running on a non-embedded Tomcat (or, I suspect, on an embedded non-Tomcat) odds are you'll have to do something at least somewhat different, but I hope this answer is at least somewhat helpful anyway.
#ControllerAdvice
public class Advisor {
#ExceptionHandler(HttpClientException.class)
public String handleUnauthorizedFromApi(HttpClientException ex, HttpServletRequest req) {
if (/* ex instanceof HttpClientException.Unauthorized or whatever */) {
req.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 401);
}
return "forward:/error";
}
}
Explanation: when a HttpClientException is thrown while we're processing request X (in an embedded servlet), what normally happens is that it bubbles all the way up to some org.apache class. (I might fire the debugger up again and work out which one, but this is a pretty high-level explanation so it doesn't matter much.) That class then sends request X back to the application, except this time the request goes to "/error", not to wherever it was originally going. In a Spring Boot app (as long as you don't turn some autoconfiguration off), that means that request X is ultimately processed by some method in BasicErrorController.
OK, so why does this whole system send a 500 to the client unless we do something? Because that org.apache class mentioned above sets something on request X which says "processing this went wrong". It is right to do so: processing request X did, after all, result in an exception which the servlet container had to catch. As far as the container is concerned, the app messed up.
So we want to do a couple of things. First, we want the servlet container to not think we messed up. We achieve this by telling Spring to catch the exception before it reaches the container, ie by writing an #ExceptionHandler method. Second, we want the request to go to "/error" even though we caught the exception. We achieve this by the simple method of sending it there ourselves, via a forward. Third, we want the BasicErrorController to set the correct status and message on the response it sends. It turns out that BasicErrorController (working in tandem with its immediate superclass) looks at an attribute on the request to determine what status code to send to the client. (Figuring this out requires reading the class's source code, but that source code is on github and perfectly readable.) We therefore set that attribute.
EDIT: I got a bit carried away writing this and forgot to mention that I don't think using this code is good practice. It ties you to some implementation details of BasicErrorController, and it's just not the way that the Boot classes are expected to be used. Spring Boot generally assumes that you want it to handle your error completely or not at all; this is a reasonable assumption, too, since piecemeal error handling is generally not a great idea. My recommendation to you -- even if the code above (or something like it) does wind up working -- is to write an #ExceptionHandler that handles the error completely, meaning it sets both status and response body and doesn't forward to anything.
You can customize the error handler of the RestTemplate to throw your custom exception, and then handle that exception with the #ControllerAdvice as you mentioned.
Something like this:
#Configuration
public class RestConfig {
#Bean
public RestTemplate restTemplate(){
// Build rest template
RestTemplate res = new RestTemplate();
res.setErrorHandler(new MyResponseErrorHandler());
return res;
}
private class MyResponseErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
if (HttpStatus.UNAUTHORIZED.equals(response.getStatusCode())) {
// Throw your custom exception here
}
}
}
}

How can i preserve the request headers in error response prepared through JAX-RS ( Apache-CXF implementation) ExceptionMapper

I am implementing JAX-RS using apache CXF. I have created an ExceptionMapper to handle bad requests like this:
public class ClientErrorExceptionMapper implements ExceptionMapper<ClientErrorException> {
#Override
public Response toResponse(final ClientErrorException exception) {
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid request: Invalid URI.").build();
}
}
I am not sure how this works internally but i suppose that framework would throw an exception in case user is making an invalid request and this handler will prepare an error message to be send back. My problem is that i wish to preserve some custom headers that user sends in the request, so that i send that back with the response. But using this exception mapper, i cant see any option to get the original request headers. I can set any new header in the response, but i wish to preserve the request headers - like i do in a normal request.
So is there any way in JAX-RS where i can preserve or efficiently refer to the custom headers in current request ?
What we have resorted to is using a thread local variable to save the RequestContext when the request arrives and then in the ExceptionMapper we can obtain request specific information.
Ugly but it works. I think we have a generic filter in the filter list that catches all requests before dispatch.

How exactly works the #ResponseStatus Spring annotation for RESTful application?

I am studying for the Spring Core certification and I have some doubts about how Spring handles REST requests.
I know that with REST the resources are exposed as name and that the actions on these resources are the HTTP methods, such as GET, PUT, POST, and DELETE.
And I know that requests are handled by the use of #RequestMapping annotations over the method that handles the operation on the resource.
From what I have understood, both standard web applications and RESTful applications use some codes to communicate with their clients (the RESTful application have an expanded set of codes) that I think represent the status of the request (for example 200 is the request is a successful GET returning content, etc.).
Now the documentation shows the use of the #ResponseStatus annotation as in this example:
#RequestMapping(value="/orders", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED) // 201
public void createOrder(HttpServletRequest request, HttpServletResponse response) {
Order order = createOrder(request);
// determine full URI for newly created Order based on request
response.addHeader("Location",
getLocationForChildResource(request, order.getId()));
}
So looking at the previous method I know that it handles HttpRequest POST requests towards the resource named /orders (using REST the resource is seen as an URL, is that correct?).
But what exactly does the annotation below do:
#ResponseStatus(HttpStatus.CREATED) // 201
I know that the 201 status code means that a new resource was created on POST.
And looking at the official documentation I can read:
Marks a method or exception class with the status code and reason that
should be returned. The status code is applied to the HTTP response
when the handler method is invoked, or whenever said exception is
thrown.
So what exactly it means? I think that as is done in the previous example it sets the 201 status that says that the resource is correctly created by the POST request. If this is correct I have 2 questions:
The resource is the /orders URI. So what is created? a file named orders (I think that this assertion is false) or what?
Where the 201 status is put?
201 is an HTTP status code. It indicates that the
request has been fulfilled and resulted in a new resource being created.
So if your server is returning such a status code, then the client understands that some (conceptual) resource was created. What that resource is is your responsibility, you're the server.
A status code is part of the HTTP response status line.
Actually, the JavaDocs for the ResponseStatus annotation warn us not to use this annotation for REST APIs. This annotation will cause Spring to call the HttpServletResponse.sendError() method, which will result in an HTML Error page. You don't want that in a RESTful service. Here's what it says:
Warning: when using this annotation on an exception class, or when setting the reason attribute of this annotation, the HttpServletResponse.sendError method will be used.
With HttpServletResponse.sendError, the response is considered complete and should not be written to any further. Furthermore, the Servlet container will typically write an HTML error page therefore making the use of a reason unsuitable for REST APIs. For such cases it is preferable to use a ResponseEntity as a return type and avoid the use of #ResponseStatus altogether.

Design: ensuring clean separation of rendering of a response from a response

This is a design / patterns problem. I have a service which now also needs
to be exposed as a RESTful web service.
Within the existing code i have the concept of a Request, a suite
of possible ServiceOperations (strategies) and the return of any ServiceOperation is
a Response object. This approach decouples the inner workings of the
service from the presentation medium (Custom TCP Server, HTTP REST, HTTP
SOAP etc.).
I've now started to implement a MyServiceRESTfulServlet which looks something
like this:
public void doGet(HttpRequest httpRequest, HttpResponse httpResponse) throws ServletException, IOException {
try {
/* Wrap an http servlet request with an adapter which hides all
* the messy details of an HttpRequest and exposes a nice interface
* for working with MyService
*/
IRequest serviceRequest = new MyServiceRESTfulRequest(httpRequest);
/* There's nothing HTTP related in this part, it's the exact same
* code you'd find in other presentation formats. A Response has
* no idea about HTTP, TCP Servers or the like.
*/
Response serviceResponse = dispatchRequest(serviceRequest);
/* A static helper which knows the interface of a Response
* and can translate that into REST-speak for feeding back via
* an HttpServletResponse.
*/
renderRESTfulResponse(serviceResponse, httpResponse);
} catch (Exception e) {
throw new ServletExcetion(e); // Caught by a seperate
// RESTfulErrorServlet
// configured in web.xml
// Rendering an appropriate
// response.
}
}
My problem is a Response can be one of 2 kinds currently:
public enum ResponseKind() {
BINARY, METADATA;
}
For binary, my restful response helper will render one way, for metadata
it will need present the metadata appropriately - an HTML table, a JSON
blob, etc.
Figuring out what type is easy - a Response object exposes a
getOriginalRequest() which after appropriate checks can be cast to a
MyServiceRESTfulRequest which exposes a .getAcceptablePresentation() - an
enum:
public enum RESTPresentationKind() {
HTML, JSON, XML, PROTOBUF_MYSERV_0.1;
}
How best can i keep this rendering code decoupled from a Response object.
In future no doubt other kinds of response will be possible. As is,
renderRESTfulResponse() goes raiding through the Request object and builds
writes out the data appropriately. It's very tightly coupled to both the
Response interface (which i'm ok with) but it knows to go poking through
the Request object too.
I just don't feel i've done this bit in as clean and maintainable a way
as i have the rest of this service. I'm "special casing" for each of the
possible response types, and each of the possible response formats. Feels
uber-hacky.
Can you suggest any way to cleanly process rendering a RESTful response
given a presentation-agnostic Request object?
Why not implement the rendering on your RepsonseKind enum (enums are really classes) or dispense with ity entirely? When you find yourself trying to get rid of case/switch statements, the answer is usually either composition + overloading + Command pattern or the Visitor pattern.

How can I see if the request path matched but Accept did not in a catch-all handler?

Normally spring will return a 404 response for a request mapping where the path did not match, and return a 406 if the path did match but the "Accept" header did not match.
I have a default controller which acts as a "catch-all" which handles rest faults by returning faults in the Accepted format. Controller is of the form:
#Controller
public class DefaultController {
#RequestMapping("/**")
public void unmappedRequest(HtpServletRequest req) {
throw new ResourceNotFoundException();
}
}
Trouble is if I do get a match here, I can't tell if it matched elsewhere. I want to return the correct error to the client and tell them the Acceptable types they may retry with. Currently all I can do is throw a general ResourceNotFound exception.
Is this something I can do in a #Controller or am I going to need to resort to writing some sort of filter chain for this?
FWIW I'm using the ReST exception handling pattern demonstrated by Stormpath
I don't think a catch all controller is good way to handle "unmapped urls" at all.
I would suggest implementing a custom implementation of AbstractHandlerExceptionResolver, and not relying on the Default implementation provided by Spring. The doResolveException can be extended to do almost anything you want with the request and response.
If you want this custom ExceptionResolver to apply only to specific controllers (REST controllers), you can set mappedHandlerClasses on the exception resolver with a list of controllers you want. Also, you can set the order of the custom exception resolver such that it sits before the default resolver.
If you think I'm off topic here, please let me know.

Categories