We use Jersey 1.13. Not my choice, but we cannot update to higher version just yet.
Jersey allows user created java types to consume path parameters. The example given in its documentation is something like this:
Resource method:
#Path("paint/{color}")
#GET
public Response paint(#PathParam("color") ColorParam color) { ... }
Custom java type for path parameter {color}
public class ColorParam {
public ColorParam(String s) {
try {
... // implementation here
} catch (Exception e) {
throw new WebApplicationException("Something's wrong");
}
}
}
I need to localize my response error string - "Something's wrong". For that, I need "Accept-Language" header information.
Is there a way to obtain it inside my ColorParam class somehow?
If this were a resource class, I could have used "#Context HttpHeaders requestHeaders" injection. Can something similar be achieved in my custom class?
Here's the solution I came up with:
My custom class ColorParam throws a custom exception, say InvalidColorException extends WebApplicationException. All the information necessary to build a response except for Locale is stored in this custom exception (like unlocalized error message, HTTP response code etc).
I also created an exception mapper to map InvalidColorException to a desired response that performs localization as it has access to request headers, namely 'Accept-Language' header:
public class InvalidColorExceptionMapper implements ExceptionMapper
This way, creation of ColorParam is completely transparent to all resource classes (assume it's used in quite a few).
I don't think the request parameter class is the correct place to localize the response. This class is creating the parameter instance from the request, it does not create the response.
Check the color instance in paint and throw the WebApplicationException. There you can use all headers.
Related
I am new to Spring and I am trying to do the basic GET and POST method.
This is how I am trying to do the methods:
#RestController
public class DeskController {
#Autowired
private DeskDao dao;
#GetMapping("desks")
public List<Desk> getDesks() {
System.out.println(dao.findById(1L));
return dao.findAll();
}
#PostMapping("desks")
public Desk save(#RequestBody #Valid Desk desk) {
Desk deskObj = dao.save(desk);
System.out.println(deskObj);
return deskObj;
}
When I am calling the POST method like this I get the pring with the actual object that I had called it with so it is working fine, but I also get this error:
javax.ws.rs.ProcessingException: Content-Type is missing
And when trying to call GET it tells me that:
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
I am aware that I have not included the whole code, but I will add what is needed to resolve this error since there are a lot of classes.
My questions are, what do I do against the first error and why is GET method not supported?
Two things you need to change :
Use a / to indicate that for this path you will perform an
operation. For eg : (/desks)
Use the annotation #Consumes to
indicate that this method accepts the payload in particular format. For eg : #Consumes(MediaType.APPLICATION_JSON) annotated over your save() method.
Lets say we have a rest service defined as:
#GET
#Produces("application/json")
public Response getAllCategories(#QueryParam(value="startIndex") int startIndex, #QueryParam(value="size") int size)
{
logger.info("[SampleCategoryController][getAllCategories]");
List<YpCategory> categoryList = sampleCategoryService.getAllCategories(startIndex, size);
return Response.ok(categoryList).build();
}
and the service is defined as:
public class SampleCategoriesServiceImpl {
public List<YpCategory> getAllCategories(int startIndex, int size) {
...
//call some method that throws a runtime exception
...
}
}
And an Application Exception handler:
#Provider
#Component
public class ApplicationExceptionHandler implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable ex) {
String internalError = "There was a problem processing your request.";
return Response.serverError().entity(new ExceptionResponse(500, internalError)).build();
}
}
}
Exception response object: Let the exception bubble up to the ApplicationExceptionHandler and return the ExceptionResponse Object. This way seems cleaner because the service doesn't have to try to handle an exception that it can't really do anything with and the client will still receive a json response.
Response wrapper: The category object would extend some type of generic response wrapper object with information about error codes then I would always have to wrap the method that can throw a runtime exception in a try/catch block and set the error codes and message info in the catch block.
Is one of these ways preferred? Are there cons to using either one of these methods to handle errors?
I think you should use the ExceptionMapper in this case. It is cleaner to let exceptions be handled outside of your implementation.
Also your implementation should be as less possible aware of HTTP. The less your implementation knows about the other parts of your framework the more flexible it will become.
To give an example. Lets say that in the future there is support for a non-HTTP protocol and error messaging will go different then using HTTP status code. You can do the implementation at the level of ExceptionMapper without changing your implementation. Otherwise you have to refactor your application to be aware of the non-HTTP protocol.
Just to be clear, I don't say there is an other implementation available now. It is just a theory.
As I have noticed, in my CXF JaxRS service, if I throw an exception in say READ phase (IN interceptor) and do not provide any default FaultOutInterceptor, the XMLFaultOutInterceptor takes care of building the response as it should be returned (which is always an XML).
Now, I would like to be able to return a response in the format in which the service was requested : JSON or XML or otherwise.
I found something like this on the web:
public class JsonFaultOutHandlerInterceptor extends JAXRSOutInterceptor
{
public JsonFaultOutHandlerInterceptor() {
getBefore().add(LoggingOutInterceptor.class.getName());
}
#Override
public void handleMessage(Message message) {
...
message.getInterceptorChain().abort();
}
}
I have configured it in the outInterceptor, should I conditionally abort (if the request type was application/Json) or not abort(if the request type was application/xml) the interceptor chain? (I'm not sure if the request type information is already available. Also, somehow, aborting the chain doesn't seem very correct)
Had the response reached the JAXRS filters, using ExceptionMapper<T> I would have beautifully handled the response. But when the exception occurs in the INinterceptor, I am a little lost.
What would be a good way to be able to define a FaultOutInterceptor?
I currently have a RESTful webservice running Jersey. I recently added a filter that does some auth stuff, and it works in the happy-path case. However, when I need to throw an error from within this filter, instead of serializing the exception into a pretty json string it, it throws a 500 with the following error:
javax.ws.rs.WebApplicationException: com.sun.jersey.api.MessageException: A message
body writer for Java class myclass, and Java type class myclass, and MIME media type
application/octet-stream was not found
The thing is, I don't want to write anything to application/octet-stream. My service only uses application/json. This is not a problem in my actual Resource classes, where I can specify the#Produces annotation. Error responses thrown from the body of a resource will serialize properly.
My question, then, is: How do I control what MIME type is used for exceptions thrown while filtering?
You need to build an exceptionmapper to handle the exceptions and turn them in to JSON. Something like:
#Provider
public class UnexpectedExceptionMapper implements ExceptionMapper<Exception>
{
#Override
public Response toResponse(final Exception exception)
{
ResponseBuilder builder = Response.status(Status.BAD_REQUEST)
.entity(jsonError(exception))
.type(MediaType.APPLICATION_JSON);
return builder.build();
}
private String jsonError(final Exception exception)
{
return "{\"error\":\"" + exception.getMessage() + "\"}";
}
}
I am implementing a RESTful service and I would like to validate the XML against an XSD in an interceptor before passing it on the a CastorUnmarshaller.
Though, in the WebRequestInterceptor I have to read the request body which can only be read once so the unmarshaller cannot read it. Is there a way of doing it?
I know that I can do both the validation and the unmarshalling manually in the Controller, but I would like to use the #RequestBody <DomainObject> way to unmarhall it.
Alternatively, as another solution, is there a way to tell the CastorUnmarshaller to validate it against the xsd?
Quite a long time passed, but someone else might benefit from this:
You can define an #Around aspect and intercept the incoming requests and their respective bodies as follows:
#Aspect
#Component
public class RequestResponseLoggingAdvice {
private static final Logger logger = LoggerFactory.getLogger(RequestResponseLoggingAdvice.class);
#Pointcut("within(#org.springframework.web.bind.annotation.RestController*)")
public void restcontroller() {}
#Pointcut("#annotation(org.springframework.web.bind.annotation.PostMapping)")
public void postmapping() {}
#Around("restcontroller() && postmapping() && args(.., #RequestBody body, request)")
public Object logPostMethods(ProceedingJoinPoint joinPoint, Object body, HttpServletRequest request) throws Throwable {
logger.debug(request.toString()); // You may log request parameters here.
logger.debug(body.toString()); // You may do some reflection here
Object result;
try {
result = joinPoint.proceed();
logger.debug(result.toString());
} catch(Throwable t) {}
}
}
Please note that your REST controller methods have to have suitable signatures for the above aspect can hook in. A sample one could be as follows:
#PostMapping
public SampleDTO saveSample(#RequestBody Sample sample, HttpServletRequest request) {
//.....
}
You can probably attach a #Before aspect (spring AOP). There you can get the same request body parameter as passed to the controller method.
Another option is to wrap the request into one that supports reading the body multiple times (by caching it the first time)
A filter can also be used to validate the XML passed.
org.springframework.oxm.castor.CastorMarshaller has a validating property to enable validation on in- and out-going documents.
But enabling it in Spring-MVC's default marshaller must be solved.