jackson で JDK8 の Optional をうまく扱ってほしい
jackson では JDK8 の Optional にまだ対応していません。 Jackson 自体が JDK6 をサポートしているので、コアのデータバインディングに入ることはないのですが、それにしても JDK8 の Optional に対応していないのは不便ですね。まあ JDK8 はまだあれなので、しょうがないですが。。
しかしまあ、JDK8 使ってると Optional を返したいときはままあるので、はやく jackson-databind-jdk8 が出ることを願ってやみません。
取り急ぎ、https://github.com/FasterXML/jackson-databind/issues/494 この issue に書いてある方法で、対応は可能。これをコピペッペして、使えば動きます。
jersey でカスタマイズした ObjectMapper を使う方法についてはこちらを御覧ください。 https://jersey.java.net/documentation/latest/media.html#json.jackson
package me.geso.mobirc4j;
import java.io.IOException;
import java.util.Optional;
import javax.ws.rs.ext.ContextResolver;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
/**
* Module for JDK 1.8 types.
*
* <p>
* https://github.com/FasterXML/jackson-databind/issues/494
*
* @author Gili Tzabari
*/
final class Jdk18Module extends SimpleModule
{
private static final long serialVersionUID = 1L;
private static class OptionalSerializer extends StdSerializer<Optional<?>>
{
/**
* Create a new OptionalSerializer.
*/
OptionalSerializer()
{
super(Optional.class, true);
}
@Override
public void serialize(Optional<?> value, JsonGenerator generator,
SerializerProvider provider)
throws IOException
{
if (value.isPresent())
generator.writeObject(value.get());
else
generator.writeNull();
}
}
private static class OptionalDeserializer extends
StdDeserializer<Optional<?>>
implements ContextualDeserializer
{
private static final long serialVersionUID = 1L;
private Class<?> targetClass;
/**
* Creates a new OptionalDeserializer.
*/
OptionalDeserializer()
{
super(Optional.class);
}
@Override
public JsonDeserializer<?> createContextual(
DeserializationContext context,
BeanProperty property) throws JsonMappingException
{
if (property != null)
{
// See
// http://jackson-users.ning.com/forum/topics/deserialize-with-generic-type
JavaType type = property.getType();
JavaType ofType = type.containedType(0);
this.targetClass = ofType.getRawClass();
}
return this;
}
@Override
public Optional<?> deserialize(JsonParser parser,
DeserializationContext context)
throws IOException, JsonProcessingException
{
return Optional.of(parser.readValueAs(targetClass));
}
@Override
public Optional<?> getNullValue()
{
return Optional.empty();
}
}
/**
* Creates a new Jdk18Module.
*/
public Jdk18Module()
{
super("Jdk18Module", new Version(1, 0, 0, null,
"com.fasterxml.jackson.databind", "jdk18"));
addSerializer(new OptionalSerializer());
addDeserializer(Optional.class, new OptionalDeserializer());
}
}
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper objectMapper;
public MyObjectMapperProvider() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk18Module());
}
@Override
public ObjectMapper getContext(Class<?> type) {
return objectMapper;
}
}
としておいて、以下のようにリソースコンフィグに登録すればよいです。
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
resourceConfig.property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
resourceConfig.register(MyObjectMapperProvider.class);
resourceConfig.packages(ServerController.class.getPackage().getName());
resourceConfig.register(JacksonFeature.class);
ちなみに、こういう方法いれないと、単に OpionalLong#getLong()
とかをガッツリ呼んじゃって、例外があがって悲しみにくれることになります。
Published: 2014-11-28(Fri) 08:09