First lets look at the Resource class...
HelloPostResource.java
@Path("/hello")
@Produces({ "text/plain" })
public class HelloPostResource {
@POST
public String sayHello(Hello hello)
{
return "Hello " + hello.getName();
}
}
Quite straight forward. It's a resource that accepts POST requests on the /hello URI. The input is a Hello type object. The output is a String that ends up being something like "Hello {name}".
The Hello object is just as simple, it's a DTO that holds one value - the name...
Hello.java
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Getting back to the HelloPostResource code, you might be thinking that there aren't any parameter annotations on the Hello object in the sayHello() method. That is correct. The hello object is instead populated by a MessageBodyReader. Lets see how that is done...
MyMessageBodyReader.java
public class MyMessageBodyReader implements MessageBodyReader<Hello> {
@Override
public boolean isReadable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return (type == Hello.class);
}
@Override
public Hello readFrom(Class<Hello> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders,
InputStream inputStream)
throws IOException, WebApplicationException
{
try (BufferedReader br = new BufferedReader(
new InputStreamReader(inputStream))) {
String name = br.readLine();
Hello hello = new Hello();
hello.setName(name);
return hello;
}
}
}
There are two methods that the MessageBodyReader interface provides. The first - isReadable() - is used to determine whether that particular MessageBodyReader implementation is capable of handling the necessary data conversion. The second - readFrom() does the actual conversion from the POST message body to a Hello object.
When Jersey attempts to process the sayHello(Hello hello) method it invokes all registered MessageBodyReader implementations and the first that returns true from its isReadable() method will be called to process the POST body. In the case of MyMessageBodyReader, true is returned if the input type is equal to Hello.class. This is a very simple check but works in this case. It's possible to create more elaborate checks that take annotations and the media type into account by using the relevant parameters passed to isReadable().
The readFrom() method has all of the same parameters as isReadable() plus a map of HTTP headers and the input stream representing the POST body itself. In the case of MyMessageBodyReader, the only input parameter that is used is the input stream. The implementation in this case is very simplistic - the first line of the input stream is read and used as the 'name' attribute, any other lines are ignored. Then, the Hello object is instantiated, it's name is set and the object is returned. That is the object that gets passed along to the sayHello(Hello hello) method on the HelloPostResource class.
In a more complex implementation the input stream could be used together with a JSON or XML parser to read the body text and convert to Java objects for example.
Invoking the service using Postman renders these results...
It works as expected! A real implementation would of course be more involved, however the code shown in this article shows how to implement a custom message body reader that can be used as a template.
Don't forget to register() the MyMessageBodyReader class or add the @Provider annotation if you're using automatic feature discovery.
-i