Search code examples
javarestjax-rsavro

Apache AVRO with Rest


I am evaluating using Apache AVRO for my Jersey REST services. I am using Springboot with Jersey REST.

Currently I am accepting JSON as input which are converted to Java Pojos using the Jackson object mapper.

I have looked in different places but I cannot find any example that is using Apache AVRO with a Jersey end point.

I have found this Github repository (https://github.com/FasterXML/jackson-dataformats-binary/) which has Apache AVRO plugin.

I still cannot find any good example as how to integrate this. Has anyone used Apache AVRO with Jersey? If yes, is there any example I can use?


Solution

  • To start , two things need to happen:

    1. You need to develop a custom ObjectMapper after the fashion of the Avro schema format
    2. You need to supply that custom ObjectMapper to Jersey.

    That should look something like this:

    @Provider
    public class AvroMapperProvider implements ContextResolver<ObjectMapper> {
    
        final AvroMapper avroMapper = new AvroMapper();
    
        @Override
        public ObjectMapper getContext(Class<?> type) {
            return avroMapper;
        }
    }
    

    Configure your application to use Jackson as the message handler:

    public class MyApplication extends ResourceConfig {
        public MyApplication() {
             super(JacksonFeature.class,AvroMapperProvider.class);
        }
    }
    

    Alternatively, you can implement a custom MessageBodyReader and MessageBodyWriter that allows you to directly process the payloads on the way in and out:

    public class AvroMessageReader implements MessageBodyReader<Person> {
    
        AvroSchema schema;
    
        final AvroMapper avroMapper = new AvroMapper();
    
        public AvroMessageReader(){
            schema = avroMapper.schemaFor(Person.class); //generates an Avro schema from the POJO class.
        }
    
        @Override
        public boolean isReadable(Class<?> type, Type type1, Annotation[] antns, MediaType mt) {
            return type == Person.class; //determines that this reader can handle the Person class.
        }
    
        @Override
        public Person readFrom(Class<Person> type, Type type1, Annotation[] antns, MediaType mt, MultivaluedMap<String, String> mm, InputStream in) throws IOException, WebApplicationException {
            return avroMapper.reader(schema).readValue(in);
        }
    
    }
    

    Here, we generate an avro schema from a hypothetical Person class. The JAX-RS runtime will select this reader based on the response from isReadable.

    You can then inject the MessageBodyWorkers component into your service implementation class:

    @Path("app")
    public static class BodyReaderTest{
    
        @Context
        private MessageBodyWorkers workers;
    
        @POST
        @Produces("avro/binary")
        @Consumes("avro/binary")
        public String processMessage() {
    
            workers.getMessageBodyReader(Person.class, Person.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE);
        }
     }
    

    To answer your last comment: Setting the mime type on your handler to the recommended avro/binary ought to do it.