diff --git a/release-notes/VERSION b/release-notes/VERSION index ae7d1e3..1b69f7c 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -6,6 +6,8 @@ Project: jackson-datatype-guava 2.6.3 (not yet released) +#83: Generic type information for `Optional` wrapped generic type lost in visitor + (reported by vzx@github) #84: Class not found exception in OSGi (com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter) (reported by mjameson-se@github) diff --git a/src/main/java/com/fasterxml/jackson/datatype/guava/ser/GuavaOptionalSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/guava/ser/GuavaOptionalSerializer.java index 33493c9..0f1022c 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/guava/ser/GuavaOptionalSerializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/guava/ser/GuavaOptionalSerializer.java @@ -185,7 +185,9 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t { JsonSerializer ser = _valueSerializer; if (ser == null) { - ser = _findSerializer(visitor.getProvider(), _referredType.getRawClass()); + // 28-Sep-2015, tatu: as per [datatype-guava#83] need to ensure we don't + // accidentally drop parameterization + ser = _findSerializer(visitor.getProvider(), _referredType, _property); } ser.acceptJsonFormatVisitor(visitor, _referredType); } @@ -208,8 +210,8 @@ protected static JavaType _valueType(JavaType optionalType) { * Helper method that encapsulates logic of retrieving and caching required * serializer. */ - protected final JsonSerializer _findSerializer(SerializerProvider provider, Class type) - throws JsonMappingException + protected final JsonSerializer _findSerializer(SerializerProvider provider, + Class type) throws JsonMappingException { JsonSerializer ser = _dynamicSerializers.serializerFor(type); if (ser == null) { diff --git a/src/test/java/com/fasterxml/jackson/datatype/guava/OptionalSchema83Test.java b/src/test/java/com/fasterxml/jackson/datatype/guava/OptionalSchema83Test.java new file mode 100644 index 0000000..4706f68 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/datatype/guava/OptionalSchema83Test.java @@ -0,0 +1,130 @@ +package com.fasterxml.jackson.datatype.guava; + +import java.util.*; + +import com.google.common.base.Optional; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.jsonFormatVisitors.*; + +public class OptionalSchema83Test + extends ModuleTestBase +{ + static class TopLevel { + @JsonProperty("values") + public Optional> values; + } + + static class ValueHolder { + @JsonProperty("value") + public String value; + } + + static class CollectionHolder { + @JsonProperty("data") + public Collection data; + } + + static class VisitorWrapper implements JsonFormatVisitorWrapper { + private SerializerProvider serializerProvider; + private final String baseName; + private final Set traversedProperties; + + public VisitorWrapper(SerializerProvider serializerProvider, String baseName, Set traversedProperties) { + this.serializerProvider = serializerProvider; + this.baseName = baseName; + this.traversedProperties = traversedProperties; + } + + private VisitorWrapper createSubtraverser(String bn) { + return new VisitorWrapper(getProvider(), bn, traversedProperties); + } + + public Set getTraversedProperties() { + return traversedProperties; + } + + @Override + public JsonObjectFormatVisitor expectObjectFormat(JavaType type) throws JsonMappingException { + return new JsonObjectFormatVisitor.Base(serializerProvider) { + @Override + public void property(BeanProperty prop) throws JsonMappingException { + anyProperty(prop); + } + + @Override + public void optionalProperty(BeanProperty prop) throws JsonMappingException { + anyProperty(prop); + } + + private void anyProperty(BeanProperty prop) throws JsonMappingException { + final String propertyName = prop.getFullName().toString(); + traversedProperties.add(baseName + propertyName); + serializerProvider.findValueSerializer(prop.getType(), prop) + .acceptJsonFormatVisitor(createSubtraverser(baseName + propertyName + "."), prop.getType()); + } + }; + } + + @Override + public JsonArrayFormatVisitor expectArrayFormat(JavaType type) throws JsonMappingException { + serializerProvider.findValueSerializer(type.getContentType()) + .acceptJsonFormatVisitor(createSubtraverser(baseName), type.getContentType()); + return new JsonArrayFormatVisitor.Base(serializerProvider); + } + + @Override + public JsonStringFormatVisitor expectStringFormat(JavaType type) throws JsonMappingException { + return new JsonStringFormatVisitor.Base(); + } + + @Override + public JsonNumberFormatVisitor expectNumberFormat(JavaType type) throws JsonMappingException { + return new JsonNumberFormatVisitor.Base(); + } + + @Override + public JsonIntegerFormatVisitor expectIntegerFormat(JavaType type) throws JsonMappingException { + return new JsonIntegerFormatVisitor.Base(); + } + + @Override + public JsonBooleanFormatVisitor expectBooleanFormat(JavaType type) throws JsonMappingException { + return new JsonBooleanFormatVisitor.Base(); + } + + @Override + public JsonNullFormatVisitor expectNullFormat(JavaType type) throws JsonMappingException { + return new JsonNullFormatVisitor.Base(); + } + + @Override + public JsonAnyFormatVisitor expectAnyFormat(JavaType type) throws JsonMappingException { + return new JsonAnyFormatVisitor.Base(); + } + + @Override + public JsonMapFormatVisitor expectMapFormat(JavaType type) throws JsonMappingException { + return new JsonMapFormatVisitor.Base(serializerProvider); + } + + @Override + public SerializerProvider getProvider() { + return serializerProvider; + } + + @Override + public void setProvider(SerializerProvider provider) { + this.serializerProvider = provider; + } + } + + public void testOptionalTypeSchema83() throws Exception { + VisitorWrapper wrapper = new VisitorWrapper(null, "", new HashSet()); + mapperWithModule() + .acceptJsonFormatVisitor(TopLevel.class, wrapper); + Set properties = wrapper.getTraversedProperties(); + + assertTrue(properties.contains("values.data.value")); + } +}