diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index e0524ad7bd..a39175279f 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -10,6 +10,7 @@ Project: jackson-databind (reported by sunchezz89@github) #2336: `MapDeserializer` can not merge `Map`s with polymorphic values (reported by Robert G) +#2349: Add option `DefaultTyping.EVERYTHING` to support Kotlin data classes #2390: `Iterable` serialization breaks when adding `@JsonFilter` annotation (reported by Chris M) #2392: `BeanDeserializerModifier.modifyDeserializer()` not applied to custom bean deserializers diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index c70f78eb58..6a3f4e6b6b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -184,7 +184,23 @@ public enum DefaultTyping { *

* Since 2.4, this does NOT apply to {@link TreeNode} and its subtypes. */ - NON_FINAL + NON_FINAL, + + /** + * Value that means that default typing will be used for + * all non-final types, with exception of small number of + * "natural" types (String, Boolean, Integer, Double) that + * can be correctly inferred from JSON, and primitives (which + * can not be polymorphic either). Typing is also enabled for + * all array types. + *

+ * Note that the only known use case for this setting is for serialization + * when passing instances of final class, and base type is not + * separately specified. + * + * @since 2.10 + */ + EVERYTHING } /** @@ -299,8 +315,12 @@ public boolean useForType(JavaType t) } // [databind#88] Should not apply to JSON tree models: return !t.isFinal() && !TreeNode.class.isAssignableFrom(t.getRawClass()); + case EVERYTHING: + // So, excluding primitives (handled earlier) and "Natural types" (handled + // before this method is called), applied to everything + return true; default: - //case JAVA_LANG_OBJECT: + case JAVA_LANG_OBJECT: return t.isJavaLangObject(); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForObject.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForObject.java index 9942e4901e..2054db7ba8 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForObject.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/deftyping/TestDefaultForObject.java @@ -22,6 +22,11 @@ static class StringBean extends AbstractBean { // ha, punny! protected StringBean(String n) { name = n; } } + final static class FinalStringBean extends StringBean { + protected FinalStringBean() { this(null); } + public FinalStringBean(String n) { super(n); } + } + enum Choice { YES, NO; } /** @@ -377,7 +382,26 @@ public void testNoGoWithExternalProperty() throws Exception verifyException(e, "Cannot use includeAs of EXTERNAL_PROPERTY"); } } - + + // [databind#2349] + public void testWithFinalClass() throws Exception + { + // First: type info NOT included + ObjectMapper mapper = JsonMapper.builder() + .activateDefaultTyping(NoCheckSubTypeValidator.instance, + ObjectMapper.DefaultTyping.NON_FINAL) + .build(); + assertEquals(aposToQuotes("{'name':'abc'}"), + mapper.writeValueAsString(new FinalStringBean("abc"))); + + mapper = JsonMapper.builder() + .activateDefaultTyping(NoCheckSubTypeValidator.instance, + ObjectMapper.DefaultTyping.EVERYTHING) + .build(); + assertEquals(aposToQuotes("['"+FinalStringBean.class.getName()+"',{'name':'abc'}]"), + mapper.writeValueAsString(new FinalStringBean("abc"))); + } + /* /********************************************************** /* Helper methods