Jersey Custom Exception Message - java

I've written a Jersey Server application and a Client application which is consuming the provided REST Services.
But I've problems to pass exception messages from server to client.
Currently I've implemented it like:
Server WS Method:
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public TestModel doTest(){
throw new NotImplementedException("[doTest] is not implemented yet");
}
NotImplementedException:
public class NotImplementedException extends WebApplicationException{
public NotImplementedException(){
super(Response.status(Response.Status.NOT_IMPLEMENTED)
.entity("The operation you've called is not implemented yet").type(MediaType.APPLICATION_JSON).build());
}
public NotImplementedException(String message){
super(Response.status(Response.Status.BAD_GATEWAY).entity(message).type(MediaType.APPLICATION_JSON).build());
}
}
Client:
public static TestModel doTest() throws Exception{
try {
Client client = getClient();
WebTarget webTarget = client.target("server..../");
WebTarget getGuTarget = webTarget.path("test");
Invocation.Builder ib = getGuTarget.request(MediaType.APPLICATION_JSON);
TestModel response = ib.get(TestModel.class); //here exception is thorwn
return response;
} catch (Exception e) {
throw e;
}
}
The exception caught on the Client looks like:
javax.ws.rs.ServerErrorException: HTTP 502 Bad Gateway
at org.glassfish.jersey.client.JerseyInvocation.createExceptionForFamily(JerseyInvocation.java:1029)
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1009)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:799)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:91)
Unfortunately I'm not able to receive the "[doTest] is not implemented yet" Message on the client. How I can get this message?
When I test the webservice I receive the correct message in the body. Unfortunately I don't know how I can access it via jersey?
Thanks.

You can use an ExceptionMapper for custom exceptions: https://jersey.java.net/apidocs/2.11/jersey/javax/ws/rs/ext/ExceptionMapper.html
Otherwise, Jersey tries to map exceptions as good as it can on its own.

Related

RestEasy client throwing exceptions

I have a REST service where in case of bad authorisation, I return 401 and some error message.
Example if I use postman or other rest client, the response status is 401 and payload:
{
"data": null,
"errors": [
{
"code": "REQUEST_NOT_AUTHORIZED",
"message": "Request not authorized"
}
]
}
If I use RestEasy client, then this exception is thrown automatically by the client:
EJB Invocation failed on component GatewayApi for method public com.example.AuthToken com.example.GatewayApi.authenticate(....): javax.ejb.EJBException: javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized
Caused by: javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized
If I try/catch the exception, then my payload is gone.
The way I am implementing is (for example):
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(UriBuilder.fromPath(SERVICE_URL));
proxy = target.proxy(GatewayApiInterface.class);
Later edit - auth method
public AuthToken authenticate(String id, String name, String password) {
try {
ResponseEnvelope<AuthToken> authTokenResponseEnvelope = proxy.authenticate(id, name, password);
return authTokenResponseEnvelope.getData();
} catch (javax.ws.rs.NotAuthorizedException wae) {
return null;
}
}
Is any way to stop RestEasy throwing exception every time status != 200?
Or some way to obtain my original payload from the Rest Server?
Fixed it :). This is a small test example that I used. Before I was not using Response (my bad)
Server Side
#GET
#Path("/test")
public Response test() {
return Response.status(Response.Status.UNAUTHORIZED)
.entity("TEST")
.build();
}
Client Side Proxy Class
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
Response test();
Client
Response response = proxy.test();
String test = response.readEntity(String.class);
System.out.println(test);
System.out.println(response.getStatus());
response.close();

How to get JAX-WS response HTTP status code

When calling a JAX-WS endpoint, how can I get the HTTP response code?
In the sample code bellow, when calling the web service at port.getCustomer(customerID); an Exception may be thrown, such as 401 or 500.
In such cases, how can I get the HTTP status code from the HTTP response?
#Stateless
public class CustomerWSClient {
#WebServiceRef(wsdlLocation = "/customer.wsdl")
private CustomerService service;
public void getCustomer(Integer customerID) throws Exception {
Customer port = service.getCustomerPort();
port.getCustomer(customerID); // how to get HTTP status
}
}
Completing #Praveen answer, you have to turn the port into a raw BindingProvider and then get the values from the context.
Don't forget that transaction will be marked for rollback if an exception occours in your managed web service client.
#Stateless
public class CustomerWSClient {
#WebServiceRef(wsdlLocation = "/customer.wsdl")
private CustomerService service;
public void getCustomer(Integer customerID) throws Exception {
Customer port = service.getCustomerPort();
try {
port.getCustomer(customerID);
} catch(Exception e) {
throw e;
} finally {
// Get the HTTP code here!
int responseCode = (Integer)((BindingProvider) port).getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
}
}
}
The below post is similar to your question. Hopefully it should work for you
https://stackoverflow.com/a/35914837/4896191

How to return HTTP Codes in web services

I've a SOAP web service built in Java.
If my method runs into an exception I want to return a "HTTP CODE 500".
Is it possible? If yes how?
(Web service is running on Tomcat 6)
maybe you should simply throw a qualified Exception yourself which then will be sent back to the client as a soap fault.
W3C tells us this:
In case of a SOAP error while processing the request, the SOAP HTTP
server MUST issue an HTTP 500 "Internal Server Error" response and
include a SOAP message in the response containing a SOAP Fault element
(see section 4.4) indicating the SOAP processing error.
http://www.w3.org/TR/2000/NOTE-SOAP-20000508/
Messing with http response codes could be dangerous as some other client might expect a different response. In your case you'd be lucky because you want exactly the the behaviour as specified by W3C. So throw an Exception ;)
How to do that? Take a look here:
How to throw a custom fault on a JAX-WS web service?
Greetings
Bastian
Since the JAX-WS is based on servlets, you can do it. You can try the next:
#WebService
public class Calculator {
#Resource
private WebServiceContext ctx;
public int division (int a, int b) {
try {
return a / b;
} catch (ArithmeticException e) {
sendError(500, "Service unavailable for you.");
return -1; // never send
}
}
private void sendError(int status, String msg) {
try {
MessageContext msgCtx = ctx.getMessageContext();
HttpServletResponse response =
(HttpServletResponse) msgCtx.get(MessageContext.SERVLET_RESPONSE);
response.sendError(status, msg);
} catch (IOException e) {
// Never happens or yes?
}
}
}
However, I prefer to use JAX-RS to do something similar.
#PUT
#Path("test")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response update( //
#FormParam("id") int id,
#FormParam("fname") String fname,
#FormParam("lname") String lname
) {
try {
// do something
return Response.ok("Successfully updated",
MediaType.TEXT_PLAIN_TYPE).build();
} catch (Exception e) {
LOG.error("An error occurred", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("An error occurred")
.type(MediaType.TEXT_PLAIN_TYPE).build();
}
}

How to mock Jersey REST client to throw HTTP 500 responses?

I am writing a Java class that uses Jersey under the hood to send an HTTP request to a RESTful API (3rd party).
I would also like to write a JUnit test that mocks the API sending back HTTP 500 responses. Being new to Jersey, it is tough for me to see what I have to do to mock these HTTP 500 responses.
So far here is my best attempt:
// The main class-under-test
public class MyJerseyAdaptor {
public void send() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
String uri = UriBuilder.fromUri("http://example.com/whatever").build();
WebResource service = client.resource(uri);
// I *believe* this is where Jersey actually makes the API call...
service.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
}
}
#Test
public void sendThrowsOnHttp500() {
// GIVEN
MyJerseyAdaptor adaptor = new MyJerseyAdaptor();
// WHEN
try {
adaptor.send();
// THEN - we should never get here since we have mocked the server to
// return an HTTP 500
org.junit.Assert.fail();
}
catch(RuntimeException rte) {
;
}
}
I am familiar with Mockito but have no preference in mocking library. Basically if someone could just tell me which classes/methods need to be mocked to throw a HTTP 500 response I can figure out how to actually implement the mocks.
Try this:
WebResource service = client.resource(uri);
WebResource serviceSpy = Mockito.spy(service);
Mockito.doThrow(new RuntimeException("500!")).when(serviceSpy).get(Mockito.any(String.class));
serviceSpy.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
I don't know jersey, but from my understanding, I think the actual call is done when get() method is invoked.
So you can just use a real WebResource object and replace the behavior of the get(String) method to throw the exception instead of actually execute the http call.
I'm writing a Jersey web application... and we throw WebApplicationException for HTTP error responses. You can simply pass the response code as the constructor-parameter. For example,
throw new WebApplicationException(500);
When this exception is thrown server-side, it shows up in my browser as a 500 HTTP response.
Not sure if this is what you want... but I thought the input might help! Best of luck.
I was able to simulate a 500 response with the following code:
#RunWith(MockitoJUnitRunner.class)
public class JerseyTest {
#Mock
private Client client;
#Mock
private WebResource resource;
#Mock
private WebResource.Builder resourceBuilder;
#InjectMocks
private Service service;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void jerseyWith500() throws Exception {
// Mock the client to return expected resource
when(client.resource(anyString())).thenReturn(resource);
// Mock the builder
when(resource.accept(MediaType.APPLICATION_JSON)).thenReturn(resourceBuilder);
// Mock the response object to throw an error that simulates a 500 response
ClientResponse c = new ClientResponse(500, null, null, null);
// The buffered response needs to be false or else we get an NPE
// when it tries to read the null entity above.
UniformInterfaceException uie = new UniformInterfaceException(c, false);
when(resourceBuilder.get(String.class)).thenThrow(uie);
try {
service.get("/my/test/path");
} catch (Exception e) {
// Your assert logic for what should happen here.
}
}
}

Can I wrap all JAX-RS requests with custom pre-dispatch, post-dispatch and error-handler code?

I have a number of classes exposed as JAX-RS request "handlers", using javax.ws.rs.Path annotations. I want to add certain actions before every request and after each request. Also, I need to create a global application-wide exception handler, which will catch everything thrown by these handlers and protocol.
Is it possible to achieve this with standard JAX-RS without creating of a custom class inherited from com.sun.jersey.spi.container.servlet.ServletContainer (I'm using Jersey).
You can also use ExceptionMappers. This mechanism which catch the exception thrown by your service and convert it to the appropriate Response:
#Provider
public class PersistenceMapper implements ExceptionMapper<PersistenceException> {
#Override
public Response toResponse(PersistenceException arg0) {
if(arg0.getCause() instanceof InvalidDataException) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
...
}
}
}
For more information see:
JAX-RS using exception mappers
You could create a proxy RESTful service and use this as the entry point to all your other RESTful services. This proxy can receive requests, do any pre-processing, call the RESTful service required, process the response and then return something to the caller.
I have a set up like this in a project I've been working on. The proxy performs functions like authentication, authorisation and audit logging. I can go into further details if you like.
Edit:
Here is an idea of how you might want to implement a proxy that supports GET requests;
#Path("/proxy")
public class Proxy
{
private Logger log = Logger.getLogger(Proxy.class);
#Context private UriInfo uriInfo;
#GET
#Path("/{webService}/{method}")
public Response doProxy(#Context HttpServletRequest req,
#PathParam("webService") String webService,
#PathParam("method") String method)
{
log.debug("log request details");
//implement this method to work out the URL of your end service
String url = constructURL(req, uriInfo, webService, method);
//Do any actions here before calling the end service
Client client = Client.create();
WebResource resource = client.resource(url);
try
{
ClientResponse response = resource.get(ClientResponse.class);
int status = response.getStatus();
String responseData = response.getEntity(String.class);
log.debug("log response details");
//Do any actions here after getting the response from the end service,
//but before you send the response back to the caller.
return Response.status(status).entity(responseData).build();
}
catch (Throwable t)
{
//Global exception handler here
//remember to return a Response of some kind.
}
}
You can use filters to read and modify all requests and responses.

Categories