2

Is it possible to register the jackson-datatype-jdk8 module in the Restlet org.restlet.ext.jackson extension package? I need to take advantage of the new Optional feature. My guess is that it should be accessible through the converter services (getConverterService()) but I can't find anything in the documentation that suggests exactly how setting a module is possible.

tarka
  • 5,289
  • 10
  • 51
  • 75
  • 1
    Have you checked this link that shows how to access the object mapper and register a module? http://stackoverflow.com/questions/28781737/restlet-complex-object-to-xml-serializaton – assylias May 18 '15 at 12:42

2 Answers2

5

I eventually pieced together from a variety of sources an answer that works with Restlet 2.3. My guess is that this will be refactored for Restlet 3 and it won't work for versions < 2.3 so be aware that this solution will most likely have a limited shelf life.

First step is to create a custom Jackson converter that implements any custom requirements you have:

public class CustomJacksonConverter extends JacksonConverter { 
    @Override 
    protected <T> JacksonRepresentation<T> create(MediaType mediaType, T source) { 
        ObjectMapper mapper = createMapper(); 
        JacksonRepresentation<T> jr = new JacksonRepresentation<T>(mediaType, source); 
        jr.setObjectMapper(mapper); 
        return jr; 
    } 

    @Override 
    protected <T> JacksonRepresentation<T> create(Representation source, Class<T> objectClass) { 
        ObjectMapper mapper = createMapper(); 
        JacksonRepresentation<T> jr = new JacksonRepresentation<T>(source, objectClass); 
        jr.setObjectMapper(mapper); 
        return jr; 
    } 


    private ObjectMapper createMapper() { 
        JsonFactory jsonFactory = new JsonFactory(); 
        jsonFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false); 
        ObjectMapper mapper = new ObjectMapper(jsonFactory); 
        mapper.registerModule(new Jdk8Module()); 
        return mapper; 
    } 

} 

You then need to create a way of replacing the default Jackson converter with a copy of your new one:

static void replaceConverter(
            Class<? extends ConverterHelper> converterClass,
            ConverterHelper newConverter) {

        ConverterHelper oldConverter = null;

        List<ConverterHelper> converters = Engine.getInstance().getRegisteredConverters();
        for (ConverterHelper converter : converters) {
            if (converter.getClass().equals(converterClass)) {
                converters.remove(converter);
                oldConverter = converter;
                break;
            }
        }

        converters.add(newConverter);
    }

You can now replace the converter in your inbound root:

replaceConverter(JacksonConverter.class, new CustomJacksonConverter());
tarka
  • 5,289
  • 10
  • 51
  • 75
  • 1
    Yes, you're right! With version 2.3, Jackson converter uses a new approach and instantiates its own `ObjectMapper`. – Thierry Templier May 18 '15 at 16:20
  • Why not passing the ObjectMapper in the constructor, so it can be set outside the converter ? An alternative solution is to provide method to register modules registerModule(Module module) – fellahst Sep 25 '15 at 18:19
1

Great start by @tarka, but gave me stream errors; i propose some [lower impact] refinements:

public class CustomJacksonConverter extends JacksonConverter {

    @Override
    protected <T> JacksonRepresentation<T> create(MediaType mediaType, T source) {
        return new CustomJacksonRepresentation<>(mediaType, source);
    }

    @Override
    protected <T> JacksonRepresentation<T> create(Representation source, Class<T> objectClass) {
        return new CustomJacksonRepresentation<>(source, objectClass);
    }

}

and then...

public class CustomJacksonRepresentation<T> extends JacksonRepresentation<T> {

    public CustomJacksonRepresentation(MediaType mediaType, T object) {
        super(mediaType, object);
    }

    public CustomJacksonRepresentation(Representation representation, Class<T> objectClass) {
        super(representation, objectClass);
    }

    public CustomJacksonRepresentation(T object) {
        super(object);
    }

    @Override
    protected ObjectMapper createObjectMapper() {
        ObjectMapper mapper = super.createObjectMapper();
        mapper.registerModule(new Jdk8Module());
        return mapper;
    }

}

and replace the converter in the same way @tarka does

Gilbert
  • 3,584
  • 2
  • 26
  • 30