· java

Jersey Client: com.sun.jersey.api.client.UniformInterfaceException

As I mentioned in a post a couple of weeks ago we’ve been doing some which involved calling the neo4j server’s HA URI to determine whether a machine was slave or master.

We started off with the following code using jersey-client:

public class HaSpike {
    public static void main(String[] args) {
        String response = client()
                .resource("http://localhost:7474/db/manage/server/ha/slave")
                .accept(MediaType.TEXT_PLAIN)
                .get(String.class);

        System.out.println("response = " + response);
    }

    private static Client client() {
        DefaultClientConfig defaultClientConfig = new DefaultClientConfig();
        defaultClientConfig.getClasses().add(JacksonJsonProvider.class);
        return Client.create(defaultClientConfig);
    }
}

which works fine when the server is actually a slave:

response = true

but blows up in style if the server is the master:

Exception in thread "main" com.sun.jersey.api.client.UniformInterfaceException: GET http://localhost:7474/db/manage/server/ha/slave returned a response status of 404 Not Found
	at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686)
	at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
	at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
	at HaSpike.main(HaSpike.java:10)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

We return a 404 status code from that URI if you’re not a slave because it simplifies things for upstream load balancers but I thought Jersey would just return the body of the response rather than throwing an exception.

A quick browse of the Jersey code showed a way around this:

    private <T> T handle(Class<T> c, ClientRequest ro) throws UniformInterfaceException, ClientHandlerException {
        setProperties(ro);
        ClientResponse r = getHeadHandler().handle(ro);

        if (c == ClientResponse.class) return c.cast(r);

        if (r.getStatus() < 300) return r.getEntity(c);

        throw new UniformInterfaceException(r,
                ro.getPropertyAsFeature(ClientConfig.PROPERTY_BUFFER_RESPONSE_ENTITY_ON_EXCEPTION, true));
    }

WebResource#handle gets called by WebResource#get and if we pass ClientResponse.class to it instead of String.class we can get around this because the code returns without checking the status of the response.

Our code needs to read like this:

public class HaSpike {
    public static void main(String[] args) {
        ClientResponse response = client()
                .resource("http://localhost:7474/db/manage/server/ha/slave")
                .accept(MediaType.TEXT_PLAIN)
                .get(ClientResponse.class);

        System.out.println("response = " + response.getEntity(String.class));
    }

    ...
}

And if we run it, this time we get the expected result:

response = false
  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket