diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java b/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java index 17d955a159..f60dfc640d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java @@ -871,7 +871,7 @@ public void writeValue(JsonGenerator gen, Object value) _serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType, _prefetch.valueSerializer); } else if (_prefetch.typeSerializer != null) { - _serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer); + _serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.rootType, _prefetch.typeSerializer); } else { _serializerProvider(_config).serializeValue(gen, value); } @@ -1078,7 +1078,7 @@ protected final void _configAndWriteValue(JsonGenerator gen, Object value) throw _serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType, _prefetch.valueSerializer); } else if (_prefetch.typeSerializer != null) { - _serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer); + _serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.rootType, _prefetch.typeSerializer); } else { _serializerProvider(_config).serializeValue(gen, value); } @@ -1113,7 +1113,7 @@ private final void _writeCloseable(JsonGenerator gen, Object value, Serializatio _serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType, _prefetch.valueSerializer); } else if (_prefetch.typeSerializer != null) { - _serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer); + _serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.rootType, _prefetch.typeSerializer); } else { _serializerProvider(cfg).serializeValue(gen, value); } @@ -1157,7 +1157,7 @@ private final void _writeCloseableValue(JsonGenerator gen, Object value, Seriali _serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType, _prefetch.valueSerializer); } else if (_prefetch.typeSerializer != null) { - _serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer); + _serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.rootType, _prefetch.typeSerializer); } else { _serializerProvider(cfg).serializeValue(gen, value); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java index ff2f9bd856..678409d13e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java @@ -269,15 +269,28 @@ public void serializeValue(JsonGenerator gen, Object value, JavaType rootType, J * * @since 2.5 */ - public void serializePolymorphic(JsonGenerator gen, Object value, TypeSerializer typeSer) + public void serializePolymorphic(JsonGenerator gen, Object value, JavaType rootType, TypeSerializer typeSer) throws IOException { if (value == null) { _serializeNull(gen); return; } + + // Let's ensure types are compatible at this point + if ((rootType != null) && !rootType.getRawClass().isAssignableFrom(value.getClass())) { + _reportIncompatibleRootType(value, rootType); + } + + JsonSerializer ser = null; + final Class type = value.getClass(); - JsonSerializer ser = findValueSerializer(type, null); + if (rootType.isMapLikeType()) { + // Ensure custom key serializers are used for map types when using polymorphic serialization. + ser = findTypedValueSerializer(rootType, true, null); + } else { + ser = findValueSerializer(type, null); + } final boolean wrap; String rootName = _config.getRootName(); diff --git a/src/test/java/com/fasterxml/jackson/databind/seq/PolyMapWriterTest.java b/src/test/java/com/fasterxml/jackson/databind/seq/PolyMapWriterTest.java new file mode 100644 index 0000000000..5b92a6e6b7 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/seq/PolyMapWriterTest.java @@ -0,0 +1,60 @@ +package com.fasterxml.jackson.databind.seq; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.MapType; + +public class PolyMapWriterTest { + + static class CustomKey { + String a; + int b; + } + + public class CustomKeySerializer extends JsonSerializer { + @Override + public void serialize(CustomKey key, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + jsonGenerator.writeFieldName(key.a + "," + key.b); + } + } + + @Test + public void testPolyCustomKeySerializer() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); + mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); + mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + + SimpleModule module = new SimpleModule("keySerializerModule"); + module.addKeySerializer(CustomKey.class, new CustomKeySerializer()); + mapper.registerModule(module); + + Map map = new HashMap(); + CustomKey key = new CustomKey(); + key.a = "foo"; + key.b = 1; + map.put(key, "bar"); + + final MapType type = mapper.getTypeFactory().constructMapType( + Map.class, CustomKey.class, String.class); + final ObjectWriter writer = mapper.writerFor(type); + String json = writer.writeValueAsString(map); + + Assert.assertEquals("[\"java.util.HashMap\",{\"foo,1\":\"bar\"}]", json); + } + +}