In my REST application I use this class to send requests:
public final class Utility {
private static Client client = ClientBuilder.newClient();
private Utility(){
}
public static <T> Response sendRequest(String URI, String method, T payload){
Response response = null;
WebTarget target = client.target(URI);
switch(method){
case "GET":
response = target.request().header("Content-type", "application/json").get();
break;
case "POST":
response = target.request().header("Content-type", "application/json").post(Entity.json(payload));
break;
case "PUT":
response = target.request().header("Content-type", "application/json").put(Entity.json(payload));
break;
case "DELETE":
response = target.request().header("Content-type", "application/json").delete();
break;
default:
throw new NotAllowedException("Invalid method type was given "
+ "to the Utility.sendRequest() method");
}
if(response == null){
throw new UnavailableServerException("The server at (" + URI + ") did not respond.");
}
return response;
}
}
I have recently had the idea that I want to handle cases when I send a request to an endpoint, which cant respond. (I didn't start the grizzly http server for it). I learned that if I try to send a request to an endpoint like this, my general ExceptionMapper (which implements ExceptionMapper(Exception)) catches it, and the exception was a NullPointerException (NPE).
So I figured all I have to do is just outsource the Response to a variable, and check if it's == null before returning it. With printfs and debug mode, I saw the following behaviour:
- Even for the failed request,
response == null
is not true. - The failed request does get to the
return response
line, but the very next line in my resource method is not executed, exception happens. - I tried to catch the NPE (even with
catch(Exception e)
) with try-catch blocks inside the Utility class, and inside the resource method too, with no succes.
I've tried to find out what throws NPE in the javax.ws.rs.core.Response;
documentation -> no success. I'm out of ideas :/ (Btw UnavailableServerException
is my custom exception also.)
Also what's the proper way to check is the request was successful, since the null check obviously not a good solution.
EDIT: here is the stacktrace
javax.ws.rs.ProcessingException: Already connected
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:264)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
at org.glassfish.jersey.client.JerseyInvocation$Builder.put(JerseyInvocation.java:326)
at eu.arrowhead.common.Utility.sendRequest(Utility.java:32)
at eu.arrowhead.core.gatekeeper.GatekeeperResource.GSDPoll(GatekeeperResource.java:146)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:384)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: Already connected
at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(Unknown Source)
at org.glassfish.jersey.client.internal.HttpUrlConnector.setOutboundHeaders(HttpUrlConnector.java:421)
at org.glassfish.jersey.client.internal.HttpUrlConnector.access$100(HttpUrlConnector.java:96)
at org.glassfish.jersey.client.internal.HttpUrlConnector$4.getOutputStream(HttpUrlConnector.java:384)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:200)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commitStream(CommittingOutputStream.java:194)
at org.glassfish.jersey.message.internal.CommittingOutputStream.commit(CommittingOutputStream.java:262)
at org.glassfish.jersey.message.internal.OutboundMessageContext.commitStream(OutboundMessageContext.java:816)
at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:545)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:388)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:255)
... 37 more
EDIT2:
@Provider
public class GenericExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception ex) {
ErrorMessage errorMessage = new ErrorMessage("Class: " + ex.getClass().toString() +
" Message: " + ex.getMessage(), 500, "No documentation yet.");
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity(errorMessage)
.build();
}
}
Here is my generic exception mapper too, although I do think this is not part of the problem, rather than the fact that that in my example my request involves 3 servers. This request is sent to an online server, which sends something to a 2nd online server (using the same utility class method), which polls a 3rd, which is offline in my test. The 2nd server cathes the ProcessingException (which far as I know can be the okay response if the 3rd server is offline) and sends back my custom exception. but then at the 1st server somehow cant send this same exception back to my Postman client, and a generic NPE is thrown.
I'm gonna try to find the reason for that tomorrow though. I'll also update jersey from 2.22.1 to 2.23.1.