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.
Asked
Active
Viewed 866 times
2
tarka
- 5,289
- 10
- 51
- 75
-
1Have 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 Answers
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
-
1Yes, 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