From 985ee587f56bdf6923b840b020e722b71c2b2f64 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 6 Aug 2019 22:24:33 -0700 Subject: [PATCH] Fix #2390 --- release-notes/CREDITS-2.x | 4 + release-notes/VERSION-2.x | 2 + .../databind/ser/BeanSerializerFactory.java | 75 ++++++++++++------- .../databind/jsontype/TestWithGenerics.java | 8 +- .../jackson/databind/ser/TestIterable.java | 14 +++- 5 files changed, 71 insertions(+), 32 deletions(-) diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index d26fe1c9ba..f44b2e7af1 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -896,3 +896,7 @@ Victor Noël (victornoel@github) (2.10.0) * Reported #2339: Suboptimal return type for `ObjectNode.set()` (2.10.0) + +Chris Mercer (cmercer@github) + * Reported #2331: `JsonMappingException` through nested getter with generic wildcard return type + (2.10.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index a5a3bda445..daac32e5d5 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -8,6 +8,8 @@ Project: jackson-databind #2331: `JsonMappingException` through nested getter with generic wildcard return type (reported by sunchezz89@github) +#2390: `Iterable` serialization breaks when adding `@JsonFilter` annotation + (reported by Chris M) #2392: `BeanDeserializerModifier.modifyDeserializer()` not applied to custom bean deserializers (reported by andreasbaus@github) #2393: `TreeTraversingParser.getLongValue()` incorrectly checks `canConvertToInt()` diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java index 7431509a4e..984dbeadca 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java @@ -228,16 +228,12 @@ protected JsonSerializer _createSerializer2(SerializerProvider prov, // And this is where this class comes in: if type is not a // known "primary JDK type", perhaps it's a bean? We can still // get a null, if we can't find a single suitable bean property. - ser = findBeanSerializer(prov, type, beanDesc); - // Finally: maybe we can still deal with it as an implementation of some basic JDK interface? + ser = findBeanOrAddOnSerializer(prov, type, beanDesc, staticTyping); + // 18-Sep-2014, tatu: Actually, as per [jackson-databind#539], need to get + // 'unknown' serializer assigned earlier, here, so that it gets properly + // post-processed if (ser == null) { - ser = findSerializerByAddonType(config, type, beanDesc, staticTyping); - // 18-Sep-2014, tatu: Actually, as per [jackson-databind#539], need to get - // 'unknown' serializer assigned earlier, here, so that it gets properly - // post-processed - if (ser == null) { - ser = prov.getUnknownTypeSerializer(beanDesc.getBeanClass()); - } + ser = prov.getUnknownTypeSerializer(beanDesc.getBeanClass()); } } } @@ -260,12 +256,23 @@ protected JsonSerializer _createSerializer2(SerializerProvider prov, /********************************************************** */ + @Deprecated // since 2.10 + public JsonSerializer findBeanSerializer(SerializerProvider prov, JavaType type, + BeanDescription beanDesc) + throws JsonMappingException + { + return findBeanOrAddOnSerializer(prov, type, beanDesc, prov.isEnabled(MapperFeature.USE_STATIC_TYPING)); + } + /** * Method that will try to construct a {@link BeanSerializer} for - * given class. Returns null if no properties are found. + * given class if at least one property is found, OR, if not, + * one of add-on types. + *

+ * NOTE: behavior changed a bit */ - public JsonSerializer findBeanSerializer(SerializerProvider prov, JavaType type, - BeanDescription beanDesc) + public JsonSerializer findBeanOrAddOnSerializer(SerializerProvider prov, JavaType type, + BeanDescription beanDesc, boolean staticTyping) throws JsonMappingException { // First things first: we know some types are not beans... @@ -276,7 +283,7 @@ public JsonSerializer findBeanSerializer(SerializerProvider prov, JavaTy return null; } } - return constructBeanSerializer(prov, beanDesc); + return constructBeanOrAddOnSerializer(prov, type, beanDesc, staticTyping); } /** @@ -344,14 +351,23 @@ public TypeSerializer findPropertyContentTypeSerializer(JavaType containerType, /********************************************************** */ + @Deprecated // since 2.10 + protected JsonSerializer constructBeanSerializer(SerializerProvider prov, + BeanDescription beanDesc) + throws JsonMappingException + { + return constructBeanOrAddOnSerializer(prov, beanDesc.getType(), beanDesc, prov.isEnabled(MapperFeature.USE_STATIC_TYPING)); + } + /** - * Method called to construct serializer for serializing specified bean type. + * Method called to construct serializer for serializing specified bean type if + * (but only if, as of 2.10), at least one property is found. * - * @since 2.1 + * @since 2.10 */ @SuppressWarnings("unchecked") - protected JsonSerializer constructBeanSerializer(SerializerProvider prov, - BeanDescription beanDesc) + protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvider prov, + JavaType type, BeanDescription beanDesc, boolean staticTyping) throws JsonMappingException { // 13-Oct-2010, tatu: quick sanity check: never try to create bean serializer for plain Object @@ -402,10 +418,9 @@ protected JsonSerializer constructBeanSerializer(SerializerProvider prov AnnotatedMember anyGetter = beanDesc.findAnyGetter(); if (anyGetter != null) { - JavaType type = anyGetter.getType(); + JavaType anyType = anyGetter.getType(); // copied from BasicSerializerFactory.buildMapSerializer(): - boolean staticTyping = config.isEnabled(MapperFeature.USE_STATIC_TYPING); - JavaType valueType = type.getContentType(); + JavaType valueType = anyType.getContentType(); TypeSerializer typeSer = createTypeSerializer(config, valueType); // last 2 nulls; don't know key, value serializers (yet) // 23-Feb-2015, tatu: As per [databind#705], need to support custom serializers @@ -413,7 +428,8 @@ protected JsonSerializer constructBeanSerializer(SerializerProvider prov if (anySer == null) { // TODO: support '@JsonIgnoreProperties' with any setter? anySer = MapSerializer.construct(/* ignored props*/ (Set) null, - type, staticTyping, typeSer, null, null, /*filterId*/ null); + anyType, config.isEnabled(MapperFeature.USE_STATIC_TYPING), + typeSer, null, null, /*filterId*/ null); } // TODO: can we find full PropertyName? PropertyName name = PropertyName.construct(anyGetter.getName()); @@ -435,15 +451,20 @@ protected JsonSerializer constructBeanSerializer(SerializerProvider prov try { ser = (JsonSerializer) builder.build(); } catch (RuntimeException e) { - prov.reportBadTypeDefinition(beanDesc, "Failed to construct BeanSerializer for %s: (%s) %s", + return prov.reportBadTypeDefinition(beanDesc, "Failed to construct BeanSerializer for %s: (%s) %s", beanDesc.getType(), e.getClass().getName(), e.getMessage()); } if (ser == null) { - // If we get this far, there were no properties found, so no regular BeanSerializer - // would be constructed. But, couple of exceptions. - // First: if there are known annotations, just create 'empty bean' serializer - if (beanDesc.hasKnownClassAnnotations()) { - return builder.createDummy(); + // 06-Aug-2019, tatu: As per [databind#2390], we need to check for add-ons here, + // before considering fallbacks + ser = (JsonSerializer) findSerializerByAddonType(config, type, beanDesc, staticTyping); + if (ser == null) { + // If we get this far, there were no properties found, so no regular BeanSerializer + // would be constructed. But, couple of exceptions. + // First: if there are known annotations, just create 'empty bean' serializer + if (beanDesc.hasKnownClassAnnotations()) { + return builder.createDummy(); + } } } return ser; diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java index 9f380fc86a..36c7398e2e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestWithGenerics.java @@ -109,15 +109,15 @@ protected static class CustomJsonSerializerFactory extends BeanSerializerFactory public CustomJsonSerializerFactory() { super(null); } @Override - protected JsonSerializer constructBeanSerializer(SerializerProvider prov, - BeanDescription beanDesc) + protected JsonSerializer constructBeanOrAddOnSerializer(SerializerProvider prov, + JavaType type, BeanDescription beanDesc, boolean staticTyping) throws JsonMappingException { - return new CustomJsonSerializer(super.constructBeanSerializer(prov, beanDesc) ); + return new CustomJsonSerializer(super.constructBeanOrAddOnSerializer(prov, type, beanDesc, staticTyping) ); } } - // [Issue#543] + // [databind#543] static class ContainerWithTwoAnimals extends ContainerWithField { public V otherAnimal; diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/TestIterable.java b/src/test/java/com/fasterxml/jackson/databind/ser/TestIterable.java index fdd7cd7774..7a5736f6ab 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/TestIterable.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/TestIterable.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.util.*; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; @@ -45,7 +46,7 @@ static class BeanWithIterator { public Iterator getValues() { return values.iterator(); } } - + static class IntIterable implements Iterable { @Override @@ -99,6 +100,10 @@ public void serialize(A a, JsonGenerator jsonGenerator, SerializerProvider provi } } + // [databind#2390] + @JsonFilter("default") + static class IntIterable2390 extends IntIterable { } + /* /********************************************************** /* Test methods @@ -156,4 +161,11 @@ public void testIterable358() throws Exception { String json = MAPPER.writeValueAsString(new B()); assertEquals("{\"list\":[[\"Hello world.\"]]}", json); } + + // [databind#2390] + public void testIterableWithAnnotation() throws Exception + { + assertEquals("[1,2,3]", + STATIC_MAPPER.writeValueAsString(new IntIterable2390())); + } }