From cdd743049dbb61ae8c8e27c268c247b0c61d8c0b Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 1 Nov 2020 09:58:28 -0800 Subject: [PATCH] Last cleanup wrt #2909 --- .../databind/ser/BasicSerializerFactory.java | 15 ++- .../databind/ser/std/JsonValueSerializer.java | 95 +++++++++++++------ 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java index e8f36bed71..c7ce10ce78 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java @@ -237,7 +237,8 @@ public JsonSerializer createKeySerializer(SerializerProvider ctxt, ClassUtil.checkAndFixAccess(am.getMember(), config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); } - ser = new JsonValueSerializer(am, delegate); + // null -> no TypeSerializer for key-serializer use case + ser = new JsonValueSerializer(am, null, delegate); } else { ser = StdKeySerializers.getFallbackKeySerializer(config, keyType.getRawClass()); } @@ -400,8 +401,16 @@ protected final JsonSerializer findSerializerByAnnotations(SerializerProvider ClassUtil.checkAndFixAccess(valueAccessor.getMember(), prov.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); } - JsonSerializer ser = findSerializerFromAnnotation(prov, valueAccessor); - return new JsonValueSerializer(valueAccessor, ser); + final JavaType valueType = valueAccessor.getType(); + JsonSerializer valueSerializer = findSerializerFromAnnotation(prov, valueAccessor); + if (valueSerializer == null) { + valueSerializer = valueType.getValueHandler(); + } + TypeSerializer typeSerializer = valueType.getTypeHandler(); + if (typeSerializer == null) { + typeSerializer = createTypeSerializer(prov.getConfig(), valueType); + } + return new JsonValueSerializer(valueAccessor, typeSerializer, valueSerializer); } // No well-known annotations... return null; diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java index 10ccc97e8c..9201cca43d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java @@ -48,6 +48,11 @@ public class JsonValueSerializer */ protected final AnnotatedMember _accessor; + /** + * @since 2.12 + */ + protected final TypeSerializer _valueTypeSerializer; + protected final JsonSerializer _valueSerializer; protected final BeanProperty _property; @@ -86,29 +91,40 @@ public class JsonValueSerializer * occurs if and only if the "value method" was annotated with * {@link com.fasterxml.jackson.databind.annotation.JsonSerialize#using}), otherwise * null - * - * @since 2.8 Earlier method took "raw" Method, but that does not work with access - * to information we need + * + * @since 2.12 added {@link TypeSerializer} since 2.11 */ @SuppressWarnings("unchecked") - public JsonValueSerializer(AnnotatedMember accessor, JsonSerializer ser) + public JsonValueSerializer(AnnotatedMember accessor, + TypeSerializer vts, JsonSerializer ser) { super(accessor.getType()); _accessor = accessor; _valueType = accessor.getType(); + _valueTypeSerializer = vts; _valueSerializer = (JsonSerializer) ser; _property = null; _forceTypeInformation = true; // gets reconsidered when we are contextualized _dynamicSerializers = PropertySerializerMap.emptyForProperties(); } + /** + * @deprecated Since 2.12 + */ + @Deprecated + public JsonValueSerializer(AnnotatedMember accessor, JsonSerializer ser) { + this(accessor, null, ser); + } + + // @since 2.12 @SuppressWarnings("unchecked") public JsonValueSerializer(JsonValueSerializer src, BeanProperty property, - JsonSerializer ser, boolean forceTypeInfo) + TypeSerializer vts, JsonSerializer ser, boolean forceTypeInfo) { super(_notNullClass(src.handledType())); _accessor = src._accessor; _valueType = src._valueType; + _valueTypeSerializer = vts; _valueSerializer = (JsonSerializer) ser; _property = property; _forceTypeInformation = forceTypeInfo; @@ -120,14 +136,15 @@ private final static Class _notNullClass(Class cls) { return (cls == null) ? Object.class : (Class) cls; } - public JsonValueSerializer withResolved(BeanProperty property, - JsonSerializer ser, boolean forceTypeInfo) + protected JsonValueSerializer withResolved(BeanProperty property, + TypeSerializer vts, JsonSerializer ser, boolean forceTypeInfo) { - if (_property == property && _valueSerializer == ser - && forceTypeInfo == _forceTypeInformation) { + if ((_property == property) + && (_valueTypeSerializer == vts) && (_valueSerializer == ser) + && (forceTypeInfo == _forceTypeInformation)) { return this; } - return new JsonValueSerializer(this, property, ser, forceTypeInfo); + return new JsonValueSerializer(this, property, vts, ser, forceTypeInfo); } /* @@ -147,7 +164,7 @@ public boolean isEmpty(SerializerProvider ctxt, Object bean) JsonSerializer ser = _valueSerializer; if (ser == null) { try { - ser = _findDynamicSerializer(ctxt, referenced); + ser = _findDynamicSerializer(ctxt, referenced.getClass()); } catch (JsonMappingException e) { throw new RuntimeJsonMappingException(e); } @@ -170,6 +187,10 @@ public JsonSerializer createContextual(SerializerProvider ctxt, BeanProperty property) throws JsonMappingException { + TypeSerializer typeSer = _valueTypeSerializer; + if (typeSer != null) { + typeSer = typeSer.forProperty(property); + } JsonSerializer ser = _valueSerializer; if (ser == null) { // Can only assign serializer statically if the declared type is final: @@ -188,16 +209,16 @@ public JsonSerializer createContextual(SerializerProvider ctxt, * using standard serializer */ boolean forceTypeInformation = isNaturalTypeWithStdHandling(_valueType.getRawClass(), ser); - return withResolved(property, ser, forceTypeInformation); + return withResolved(property, typeSer, ser, forceTypeInformation); } // [databind#2822]: better hold on to "property", regardless if (property != _property) { - return withResolved(property, ser, _forceTypeInformation); + return withResolved(property, typeSer, ser, _forceTypeInformation); } } else { // 05-Sep-2013, tatu: I _think_ this can be considered a primary property... ser = ctxt.handlePrimaryContextualization(ser, property); - return withResolved(property, ser, _forceTypeInformation); + return withResolved(property, typeSer, ser, _forceTypeInformation); } return this; } @@ -221,13 +242,17 @@ public void serialize(Object bean, JsonGenerator gen, SerializerProvider ctxt) t if (value == null) { ctxt.defaultSerializeNull(gen); - return; - } - JsonSerializer ser = _valueSerializer; - if (ser == null) { - ser = _findDynamicSerializer(ctxt, value); + } else { + JsonSerializer ser = _valueSerializer; + if (ser == null) { + ser = _findDynamicSerializer(ctxt, value.getClass()); + } + if (_valueTypeSerializer != null) { + ser.serializeWithType(value, gen, ctxt, _valueTypeSerializer); + } else { + ser.serialize(value, gen, ctxt); + } } - ser.serialize(value, gen, ctxt); } @Override @@ -250,7 +275,7 @@ public void serializeWithType(Object bean, JsonGenerator gen, SerializerProvider } JsonSerializer ser = _valueSerializer; if (ser == null) { // no serializer yet? Need to fetch - ser = _findDynamicSerializer(ctxt, value); + ser = _findDynamicSerializer(ctxt, value.getClass()); } else { // 09-Dec-2010, tatu: To work around natural type's refusal to add type info, we do // this (note: type is for the wrapper type, not enclosed value!) @@ -379,15 +404,26 @@ protected boolean isNaturalTypeWithStdHandling(Class rawType, JsonSerializer< // @since 2.12 protected JsonSerializer _findDynamicSerializer(SerializerProvider ctxt, - Object value) throws JsonMappingException + Class valueClass) throws JsonMappingException { - Class cc = value.getClass(); - JsonSerializer serializer = _dynamicSerializers.serializerFor(cc); - if (serializer != null) { - return serializer; + JsonSerializer serializer = _dynamicSerializers.serializerFor(valueClass); + if (serializer == null) { + if (_valueType.hasGenericTypes()) { + final JavaType fullType = ctxt.constructSpecializedType(_valueType, valueClass); + serializer = ctxt.findPrimaryPropertySerializer(fullType, _property); + PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(fullType, serializer); + _dynamicSerializers = result.map; + } else { + serializer = ctxt.findPrimaryPropertySerializer(valueClass, _property); + PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(valueClass, serializer); + _dynamicSerializers = result.map; + } } + return serializer; + + /* if (_valueType.hasGenericTypes()) { - JavaType fullType = ctxt.constructSpecializedType(_valueType, cc); + JavaType fullType = ctxt.constructSpecializedType(_valueType, valueClass); // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do: serializer = ctxt.findTypedValueSerializer(fullType, false, _property); PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(fullType, serializer); @@ -396,12 +432,13 @@ protected JsonSerializer _findDynamicSerializer(SerializerProvider ctxt, return serializer; } else { // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do: - serializer = ctxt.findTypedValueSerializer(cc, false, _property); - PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(cc, serializer); + serializer = ctxt.findTypedValueSerializer(valueClass, false, _property); + PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(valueClass, serializer); // did we get a new map of serializers? If so, start using it _dynamicSerializers = result.map; return serializer; } + */ } /*