Lessons from developing Message Broker
II spent 3 weeks developing a pub/sub message broker whose transport layer is a ReSTful webservice layer. The documentation at https://jersey.github.io/ is very good, but there are a few gotchas that don't really stick out when you examine the examples or read the documentation. In this page I outline the things that threw me and left me banging my head for hours and days.
Issue | Remedy |
---|---|
Using Jackson library <groupId>com.fasterxml.jackson.core</groupId>, <artifactId>jersey-hk2</artifactId>, and <artifactId>jersey-media-json-binding</artifactId> does not marshall and unmarshall java objects correctly | You must also add the following <dependency> <groupId>org.glassfish.jersey.media</groupId> </dependency> You must also register the jackson marshalling object with Jersey Client client = ClientBuilder.newClient().register(JacksonFeature.class); |
If you use the Jackson 2.9xx fasterxml libraries to marshall and unmarshall java objects to and from Strings and the Java object is a composite object (so you would end up with nested json objects), the translation works fine, but sending that string across the wire will cause a HTTP 400 error. | Only use simple Java objects that do not contain other objects, Strings are allowed. e.g. public static ObjectMapper getGlobalObjectMapper() if( itsMapper == null ) itsMapper = new ObjectMapper(); } return itsMapper; } // In some other method later that is going to make a ReSTful call objectMapper mapper = GlobalConfigs.getGlobalObjectMapper(); String jsonRequest = mapper.writeValueAsString( <java object> ); Response response = resource.addSubscriber( jsonRequest ); |
Consider the following ReSTful endpoint definition @Path("/services") @GET @GET @POST @GET } The two @Path("/subscribe") will cause a conflict with the web server. The conflict is caused by the method names and the @Produces and @Consumes values are the same. It will result in a HTTP 500 error. | The solution is to make the @Path() values slightly different @POST |
@Path("/services") } | The interface isn't actually needed, you can place all of the methods directly on a class that don't implement any interface and it works just fine. The interface is only needed if you want to perform RPC between applications that are going to use ReSTful services for inter processes communications. |
Marshalling of Java objects fail if they are not full Java Beans e.g. public class SecurityKey private String key; this.key = key; } return key; } } Objects of this class will transmit but unmarshalling will fail because there is no setter for the key attribute. If you don't have a default constructor, you will get a HTTP 500 error during unmarshalling as the default constructor cannot be found. | Each class should be written as public class SecurityKey private String key; this.key = key; } this.key = key; } public String getKey() return key; } } This is a full fledged javabean. |