ResponseBuilder is not working when used with entity object - java

I am trying to create a response with responsebuilder.
When I pass string in entity it works fine but when I pass some error class it doesnot works.
Here is code
1) Working fine
Response.status(400).entity("test").build();
2) Not working
Response.status(400).entity(new MyCustomExceptions(400,"My bad request")).build();
With above code I am getting error
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=text/plain
when I call this service with above code I am getting 500 error instead of 400.But in 1st case I am getting proper 400 error.
Just wanted to understand if I pass object to entity then do I need
to override some methods in class MyCustomExceptions?
How response is created from MyCustomExceptions object?
If I pass string to entity it works fine.Why?

Mapping exceptions to HTTP error responses
JAX-RS allows you to define a direct mapping of Java exceptions to HTTP error responses.
By extending WebApplicationException, you can create application specific exceptions that build a HTTP response with the status code and an optional message as the body of the response.
With that in mind, instead of returning a Response, you could throw a BadRequestException which extends WebApplicationException and will be mapped to a HTTP response with the status code 400:
throw new BadRequestException("My bad request");
For more details regarding error handling in JAX-RS, refer to this answer.
Subclasses of WebApplicationException
For convenience, the WebApplicationException is currently extended by the following exceptions (and they can be extended to create your own exceptions):
RedirectionException: 3xx status codes for Redirection errors
ClientErrorException: 4xx status codes for Client errors
BadRequestException: 400 Bad Request
ForbiddenException: 403 Forbidden
NotAcceptableException: 406 Not Acceptable
NotAllowedException: 405 Method Not Allowed
NotAuthorizedException: 401 Unauthorized
NotFoundException: 404 Not Found
NotSupportedException: 415 Unsupported Media Type
ServerErrorException: 5xx status codes for Server errors
InternalServerErrorException: 500 Internal Server Error
ServiceUnavailableException: 503 Service Unavailable

What is the value of accept parameter in HTTPHeader that you're passing? Looks like its text/plain and you're trying to return an Object.
Pass the accept value as application/json in the request. OR
Change your code in response to add type as Json/XML
Response.status(400).type(MediaType.APPLICATION_JSON).entity(new MyCustomExceptions(400,"My bad request")).build();

Related

Producing application/octet-stream and application/json

I have an endpoint that typically returns a document of type PDF, Word, etc. There is user input that goes along with this endpoint, however so I would like to validate it.
The trouble is, when I validate the input and want to return some sort of error JSON response, I end up getting errors similar to
Failed executing GET /foo/generateBar: NoMessageBodyWriterFoundFailure: Could not find MessageBodyWriter for response object of type: FooResponse of media type: application/octet-stream
What I am using on my endpoint is #Produces({"application/octet-stream", "application/json"})
Is there a way I can avoid this error by possibly returning both JSON and different file formats? My impression is that what the #Produces I was using was doing, however I'm probably thoroughly confused.
Additionally, I must note that I'm using window.open on the front-end side to call this endpoint.
In Java and in javax.ws.rs.core.Response, you should try something like this in you headers:
Response.status(response.getStatus())
.header("Accept", "application/json")
.header("Content-type", "application/json")
.entity(entity)
.build();
In order to solve this issue you have to consider the following aspects:
Exceptions mangement
Here you have to consider that each time you will have any exception you will throw custom exceptions and an exceptions handler will be implemented using #ControllerAdvice, or any other solution. This exceptions handler will return the response as a JSON.
Handling to return the application/octet-stream
To the endpoint, you need to mention that it will produce application/octet-stream. You can use: #GetMapping(produces = {MediaType.APPLICATION_OCTET_STREAM}).
Provide to the GET request, the proper headers
When you are calling the endpoint that produces the application/octet-stream you will add the Accept header with the value application/octet-stream, application/json. Now, in case of success, you'll receive the octet-stream and in case of any exception you'll receive the JSON response.
I hope this solution will help you!

ClientInterceptor - capturing 404 scenarios

I am using ClientInterceptor to intercept all the external soap calls made by my application and log the request and response. I am able to capture the request / response and fault scenarios. However when I see a 404 error due to endpoint being incorrectly configured , I am unable to capture this using the methods provided by this interface. Is there a way to capture 404 error using this interface? If not , can you please help in letting me know the alternative that I need to explore?
org.springframework.ws.client.support.interceptor.ClientInterceptor
The org.springframework.ws.client.support.interceptor.ClientInterceptor.handleFault() only suits for intercepting the processes of incoming response fault. That is the SOAP faults defined by specification. So the SOAP 1.1 and 1.2 specifications define a status codes which are returned in case of SOAP fauls (for example in case of malformed XML in the request message envelope). SOAP 1.1 specifies a 500 status code for faults and SOAP 1.2 specifies a 400 status code for sender faults, and 500 for all other faults. In case of faults the server returns SOAP message in the response containing a SOAP Fault element which then can be passed to the ClientInterceptor.handleFault() methods. But 404 status code indicates that it is not a SOAP failure but system error. So if you need to handle that case as well you need to overwrite the WebServiceTemplate.handleError() method instead.
This will do the trick
public class CustomWebServiceTemplate extends WebServiceTemplate{
#Override
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
log.info("Log the error case in here");
return super.handleError(connection, request);
}
}

Handling 400 Bad Requests

When sending parameters as form data parameters instead of x-www-form-urlencoded parameters, my API returns an http 500 error.
I want the API to return http 400 bad request error along with a error number and appropriate error message.
My API method has #Consumes({ MediaType.APPLICATION_FORM_URLENCODED }) annotation
So I wrote an exception mapper to handle NotSupportedException.
But during the execution https://jersey.java.net/project-info/2.6/jersey/jersey-server/xref/org/glassfish/jersey/server/internal/routing/MethodSelectingRouter.html is called before my mapper and it throws NotSupportedException. But I want to customize the error shown to the user.

ValidationError in Jersey Client?

I'm having trouble getting ValidationErrors from a jersey resource in jersey client. Let me explain.
A function in jersey resource:
#POST
#Produces({ MediaType.APPLICATION_JSON })
#Consumes(MediaType.APPLICATION_JSON)
public LoginInfo login(#NotNull #Valid Login login)
My clientconfig:
ClientConfig clientConfig = new ClientConfig();
clientConfig.register(JacksonFeature.class);
My jersey client:
ClientBuilder.newClient(getClientConfig())
And my function call:
getTarget("/login").request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(login), LoginInfo.class);
All works without problems as long i supply valid parameters, when i for example supply null as parameter i get exception:
HTTP 400 Bad Request
But i'm expecting a ValidationError response, because bean validation failed.
Bean validation and error response is working on server, for example with a simple html test, which shows validationerror structure:
<div class="validation-errors"><div class="validation-error"><span class="message">may not be null</span> (<span class="path"><strong>path</strong> = LoginResource.login.arg0</span>, <span class="invalid-value"><strong>invalidValue</strong> = null</span>)</div></div>
How do i get the ValidationError in my jersey client? Do i maybe have to configure it in a special way or maybe i should use a filter?
[edit]
I turned on tracing and when validation fails on server the server sends validationerrors, but it seems jersey client doesn't do anything with it, it converts it to BadRequestException.
6 < 400
6 < Content-Type: application/json
6 < Vary: Accept
[{"message":"may not be empty","messageTemplate":{org.hibernate.validator.constraints.NotBlank.message}","path":"RuleResource.add.arg0.description","invalidValue":""}]
Answering my own question ;-)
It seems jersey client doesn't support validationerrors, so i created a client filter and when status is 400 i get the entity and put the validation errors in a list. Next i create a validationexception which includes the validation errors and just throw it. A bit further up the chain i get a processingexception, in the stacktrace the validationexception can be found and also the validation errors. So i create a nice message from the validation errors and throw another exception, all the way up to my gui code which simply displays the exception message.
Works fine, thanks jersey for the flexibility of filters!

JAX-RS how to handle wrong content-type

I have a REST service with a #POST method which #Consumes("application/xml)".
However, if I make a POST request from my browser and I don't add
Content-Type: application/xml
header to the request, I get an exception in my jboss
Failed executing POST : org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type
How is my servlet supposed to handle such cases?
You can implement an ExceptionMapper for the UnsupportedMediaTypeException and choose to handle it however you wish. You're seeing this exception because you don't have a handler for it and resteasy is doing its out of the box handling.

Categories