From 7eea4728774527a242e58bbc3ef9cf1290920b53 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Mon, 22 May 2023 23:26:00 +0900 Subject: [PATCH] Squashed commit of the following: commit 63a7b1d453a11c92d88206fc952e015dce1123ad Merge: 559cd04b8 3140bb749 Author: Tatu Saloranta Date: Thu May 18 16:47:22 2023 -0700 Merge branch '2.15' into 2.16 commit 3140bb749cea10e4a6e79d80b1eb5fe0f8c7cda2 Merge: 4e1c9be17 9f8046254 Author: Tatu Saloranta Date: Thu May 18 16:46:48 2023 -0700 Merge branch '2.15' of github.com:FasterXML/jackson-databind into 2.15 commit 559cd04b81696b15c87907fccbc56694dd42049d Merge: f083348b8 4e1c9be17 Author: Tatu Saloranta Date: Thu May 18 16:45:27 2023 -0700 Merge branch '2.15' into 2.16 commit 9f80462540bd0e0cce847a572dedd4040634ae4f Author: Tatu Saloranta Date: Thu May 18 16:44:56 2023 -0700 Fix #3938: do not skip Method-based setters on Records (#3939) commit 4e1c9be1748d8ec6ebb28dbf45b438a4bab02a3e Merge: 3168975b7 c524e6b63 Author: Tatu Saloranta Date: Thu May 18 15:54:01 2023 -0700 Merge branch '2.14' into 2.15 commit c524e6b6370ca5417b0fbe691fc98bfc4397c17f Author: Tatu Saloranta Date: Thu May 18 15:53:45 2023 -0700 Fix #3938 to repro actual issue commit 3168975b7de2ea817c93f4771addb0c6ecb3ecaa Merge: 3291911aa 04d7ae4a2 Author: Tatu Saloranta Date: Thu May 18 15:18:36 2023 -0700 Merge branch '2.14' into 2.15 commit 04d7ae4a272267b89aae9734028f8ec25a5ca7da Author: Tatu Saloranta Date: Thu May 18 15:13:41 2023 -0700 Add passing test (in 2.14) for #3938 commit f083348b875b94ecf44131853a829d3fc0f0e53c Merge: 6091c4b8d 3291911aa Author: Tatu Saloranta Date: Tue May 16 14:53:20 2023 -0700 Merge branch '2.15' into 2.16 commit 3291911aa2e6ea00880d789e3643a13962d214cf Author: Tatu Saloranta Date: Tue May 16 14:49:51 2023 -0700 Back to snapshot dep commit 05472aedffc71129ca34f204f9c431875b7c8ae5 Author: Tatu Saloranta Date: Tue May 16 14:47:37 2023 -0700 [maven-release-plugin] prepare for next development iteration commit 6e3732557c3fcd45687a9e2780165f5adaa2c41f Author: Tatu Saloranta Date: Tue May 16 14:47:34 2023 -0700 [maven-release-plugin] prepare release jackson-databind-2.15.1 commit 3d9dd34890ad46bb6e6089dac2895c13647ae9ac Author: Tatu Saloranta Date: Tue May 16 14:34:13 2023 -0700 2.15.1 release commit 6091c4b8db30a51b470b880756666e99144934ee Merge: d2ae3a2e2 55d87cfb2 Author: Tatu Saloranta Date: Tue May 16 12:38:57 2023 -0700 Merge branch '2.15' into 2.16 commit 55d87cfb2271ebe507bdf1286839b916bd0c1c80 Merge: a7e17adf0 c7b6c64da Author: Tatu Saloranta Date: Tue May 16 12:38:24 2023 -0700 Merge branch '2.14' into 2.15 commit c7b6c64da52761549e4585cf725e4cbf9d0464af Author: Tatu Saloranta Date: Tue May 16 12:35:44 2023 -0700 Fix #3882 (JsonNode.withArray() fail) commit d2ae3a2e271a7dc6d22d41ff1023f5981fa9b0bf Author: Tatu Saloranta Date: Mon May 15 21:06:11 2023 -0700 manual merge of pom.xml (test) change commit 7ddce076b458dca09bd69570ea734d68a6689905 Merge: a3bb1b90f a7e17adf0 Author: Tatu Saloranta Date: Mon May 15 21:02:46 2023 -0700 Merge branch '2.15' into 2.16 commit a7e17adf04c0bf2c548471c4b7679f3d9399e097 Author: Tatu Saloranta Date: Mon May 15 21:01:49 2023 -0700 Add Junit 5 test dependency commit a3bb1b90ff6753164b5c6c61f6842dc7d382d081 Merge: a3b231cdd 8a8ba5a1f Author: Tatu Saloranta Date: Mon May 15 18:13:22 2023 -0700 Merge branch '2.15' into 2.16 commit 8a8ba5a1f3ea91cf93d22f8623f451a628efc49e Author: Kim, Joo Hyuk Date: Tue May 16 10:13:07 2023 +0900 Update JavaDoc of JsonAppend. (#3933) commit a3b231cdd595a879bbb667f43ba7102056545d7f Author: Tatu Saloranta Date: Mon May 15 15:38:40 2023 -0700 Update release notes wrt #3928 commit 40c97391ba61773922c6d6f8ea21e5fe59c20cf6 Author: PJ Fanning Date: Mon May 15 23:32:27 2023 +0100 Json property affects Record field serialization order (#3929) commit 8fcf9efaa445cd2767887d1a78ec68058cd9de7b Merge: e9db4b355 e5bdcfb31 Author: Tatu Saloranta Date: Sun May 14 17:08:35 2023 -0700 Merge branch '2.15' into 2.16 commit e5bdcfb31771c1e35ed69b1fc49e84ab5d1ac023 Author: Kim, Joo Hyuk Date: Mon May 15 09:06:35 2023 +0900 Remove hard-coded `StreamReadConstraints` test variables to isolate change in `jackson-core` itself (#3930) commit e9db4b3556db3d19c6f6bd5ae1e877c399716d7d Author: Piotr Findeisen Date: Mon May 15 02:04:42 2023 +0200 Fix typo in USE_GETTERS_AS_SETTERS description (#3931) commit d8d4cb69e9046df937788c8edd765888562aaf64 Author: Tatu Saloranta Date: Sat May 13 20:15:45 2023 -0700 Sync tests wrt error messages commit c1b4aad3ff05db8312332e427c086ad0a4d40f20 Merge: 67103c288 6f81a4ed9 Author: Tatu Saloranta Date: Sat May 13 20:04:42 2023 -0700 Merge branch '2.15' into 2.16 commit 6f81a4ed9064a37fd518a1d310cf7509ae7a043f Author: Tatu Saloranta Date: Sat May 13 20:02:20 2023 -0700 Minor change to align with higher max string value length limit commit 67103c2881aa506ebceb25824becac5b80a4f86a Author: Tatu Saloranta Date: Sat May 6 09:44:18 2023 -0700 Clean up attic... commit cfe8e975f37bd182e9616fb4eb931ebebf8369f8 Author: Muhammad Khalikov <55890311+mukham12@users.noreply.github.com> Date: Sat May 6 12:43:35 2023 -0400 Fix a few typos in documentation (#3919) commit df541d3c74133496454dd9bfccc404b54a0faea6 Author: Kim, Joo Hyuk Date: Sat May 6 12:32:13 2023 +0900 Improve and fix JavaDocs for Jackson 2.15 (#3917) commit d44e014015914c4f721dd33e6c43e25c0c9625fc Merge: 924152d11 c8c7d395d Author: Tatu Saloranta Date: Fri May 5 09:36:27 2023 -0700 Merge branch '2.15' into 2.16 commit c8c7d395dddb07bb2e2d098c6232dd0ae35dd4a3 Merge: a7a8a8036 d47d1b642 Author: Tatu Saloranta Date: Fri May 5 09:36:21 2023 -0700 Merge branch '2.14' into 2.15 commit d47d1b642931246770ec67c4a98ad6aacc0f7d7d Author: Tatu Saloranta Date: Fri May 5 09:34:29 2023 -0700 Back to snapshot dep commit 6f3d20f8f3165a375eb5d44105c18285b4132faf Author: Tatu Saloranta Date: Fri May 5 09:31:43 2023 -0700 [maven-release-plugin] prepare for next development iteration commit 8cdba2177a411c9dfc8949bbf0f23b4fa8ef5d8d Author: Tatu Saloranta Date: Fri May 5 09:31:40 2023 -0700 [maven-release-plugin] prepare release jackson-databind-2.14.3 commit 2bd50de31a25a419e63b6f4350709999dbafe758 Author: Tatu Saloranta Date: Fri May 5 09:09:17 2023 -0700 Prepare for 2.14.3 release commit 924152d1112e594e8c6bb5644efd8ecd3b4dda91 Merge: 774ddb838 a7a8a8036 Author: Tatu Saloranta Date: Thu May 4 14:00:26 2023 -0700 Merge branch '2.15' into 2.16 commit a7a8a8036a843dd1b2022561bb1376575b180419 Author: Tatu Saloranta Date: Thu May 4 14:00:13 2023 -0700 ... commit 774ddb83872892f2442bc209d9b57036694cece2 Merge: f8477455d ad308b426 Author: Tatu Saloranta Date: Thu May 4 13:57:18 2023 -0700 Merge branch '2.15' into 2.16 commit ad308b426a253b0d3a8062b22abe1c2191f789c0 Author: Tatu Saloranta Date: Thu May 4 13:55:48 2023 -0700 Update release notes wrt #3897 commit 1fa2d861ecd8595f528db579075c1933cd38495b Author: Sim Yih Tsern Date: Fri May 5 04:52:30 2023 +0800 Record constructor with single write-only parameter should result in properties-based creator, to fix #3897. (#3910) commit f8477455d1e749791bb77c2f6ab455aae0f2f5af Merge: f3c60eddf ee3b89aed Author: Tatu Saloranta Date: Thu May 4 11:13:22 2023 -0700 Merge branch '2.16' of github.com:FasterXML/jackson-databind into 2.16 commit f3c60eddf7c0bbb690811cccbfb9313fd7f39aaf Merge: 23603ea11 75475913f Author: Tatu Saloranta Date: Thu May 4 11:13:15 2023 -0700 Merge branch '2.15' into 2.16 commit 75475913f0e49065652b3e52a2a8bff54d86fca5 Author: Tatu Saloranta Date: Thu May 4 11:12:53 2023 -0700 Mark #3895 as fixed (due to another PR/issue) commit ee3b89aed9b3fbba560a92e78bc58c53ab5c2962 Author: ChangYong Date: Fri May 5 02:09:33 2023 +0900 Fix incorrect comment (#3916) --- attic/MappingIteratorDeserializer.java | 47 --- attic/TypeBindings.java | 337 ------------------ pom.xml | 27 +- release-notes/CREDITS-2.x | 16 + release-notes/VERSION-2.x | 19 +- .../databind/AnnotationIntrospector.java | 4 +- .../jackson/databind/BeanDescription.java | 2 +- .../jackson/databind/MapperFeature.java | 9 +- .../jackson/databind/ObjectMapper.java | 2 +- .../jackson/databind/SerializerProvider.java | 18 +- .../databind/annotation/JsonAppend.java | 10 +- .../deser/BasicDeserializerFactory.java | 4 + .../databind/deser/BeanDeserializer.java | 4 +- .../deser/std/CollectionDeserializer.java | 4 +- .../databind/introspect/AnnotatedClass.java | 3 +- .../introspect/POJOPropertiesCollector.java | 11 +- .../jackson/databind/node/ArrayNode.java | 4 +- .../ser/DefaultSerializerProvider.java | 2 +- .../util/internal/PrivateMaxEntriesMap.java | 4 +- .../databind/records/RecordBasicsTest.java | 61 ++++ .../records/RecordFailingSetter3938Test.java | 42 +++ .../records/RecordSerializationOrderTest.java | 66 ++++ .../deser/dos/DeepJsonNodeDeser3397Test.java | 2 +- .../dos/DeepNestingUntypedDeserTest.java | 2 +- .../dos/StreamReadStringConstraintsTest.java | 19 +- .../TestPolymorphicDeserialization676.java | 2 +- .../jackson/databind/node/WithPathTest.java | 21 +- 27 files changed, 303 insertions(+), 439 deletions(-) delete mode 100644 attic/MappingIteratorDeserializer.java delete mode 100644 attic/TypeBindings.java create mode 100644 src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordFailingSetter3938Test.java create mode 100644 src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordSerializationOrderTest.java diff --git a/attic/MappingIteratorDeserializer.java b/attic/MappingIteratorDeserializer.java deleted file mode 100644 index fcb12db89f..0000000000 --- a/attic/MappingIteratorDeserializer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.fasterxml.jackson.databind.deser.std; - -import java.io.IOException; - -import com.fasterxml.jackson.core.*; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.deser.ContextualDeserializer; - -public class MappingIteratorDeserializer - extends StdDeserializer> - implements ContextualDeserializer -{ - private static final long serialVersionUID = 1L; - - protected final JavaType _valueType; - - protected final JsonDeserializer _valueDeserializer; - - public MappingIteratorDeserializer(JavaType valueType) { - this(valueType, null); - } - - protected MappingIteratorDeserializer(JavaType valueType, JsonDeserializer vdeser) { - super(MappingIterator.class); - _valueType = valueType; - _valueDeserializer = vdeser; - } - - @Override - public JsonDeserializer createContextual(DeserializationContext ctxt, - BeanProperty prop) throws JsonMappingException - { - JsonDeserializer deser = ctxt.findContextualValueDeserializer(_valueType, prop); - return (deser == _valueDeserializer) ? this - : new MappingIteratorDeserializer(_valueType, deser); - } - - @Override - public MappingIterator deserialize(JsonParser p, - DeserializationContext ctxt) throws IOException, - JsonProcessingException - { - MappingIterator mit = new MappingIterator(_valueType, p, ctxt, - _valueDeserializer, false, null); - return mit; - } -} diff --git a/attic/TypeBindings.java b/attic/TypeBindings.java deleted file mode 100644 index 7570cc2bd0..0000000000 --- a/attic/TypeBindings.java +++ /dev/null @@ -1,337 +0,0 @@ -package com.fasterxml.jackson.databind.type; - -import java.lang.reflect.*; -import java.util.*; - -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.util.ClassUtil; - -/** - * Helper class used for resolving type parameters for given class - */ -public class TypeBindings -{ - private final static JavaType[] NO_TYPES = new JavaType[0]; - - /** - * Marker to use for (temporarily) unbound references. - */ - public final static JavaType UNBOUND = new SimpleType(Object.class); - - /** - * Factory to use for constructing resolved related types. - */ - protected final TypeFactory _typeFactory; - - /** - * @since 2.7 - */ - protected final ClassStack _classStack; - - /** - * Context type used for resolving all types, if specified. May be null, - * in which case {@link #_contextClass} is used instead. - */ - protected final JavaType _contextType; - - /** - * Specific class to use for resolving all types, for methods and fields - * class and its superclasses and -interfaces contain. - */ - protected final Class _contextClass; - - /** - * Lazily-instantiated bindings of resolved type parameters - */ - protected Map _bindings; - - /** - * Also: we may temporarily want to mark certain named types - * as resolved (but without exact type); if so, we'll just store - * names here. - */ - protected HashSet _placeholders; - - /** - * Sometimes it is necessary to allow hierarchic resolution of types: specifically - * in cases where there are local bindings (for methods, constructors). If so, - * we'll just use simple delegation model. - */ - private final TypeBindings _parentBindings; - - /* - /********************************************************** - /* Construction - /********************************************************** - */ - - public TypeBindings(TypeFactory typeFactory, ClassStack stack, Class cc) - { - this(typeFactory, null, stack, cc, null); - } - - public TypeBindings(TypeFactory typeFactory, ClassStack stack, JavaType type) - { - this(typeFactory, null, stack, type.getRawClass(), type); - } - - /** - * Constructor used to create "child" instances; mostly to - * allow delegation from explicitly defined local overrides - * (local type variables for methods, constructors) to - * contextual (class-defined) ones. - */ - public TypeBindings childInstance() { - return new TypeBindings(_typeFactory, this, _classStack, _contextClass, _contextType); - } - - private TypeBindings(TypeFactory tf, TypeBindings parent, ClassStack stack, - Class cc, JavaType type) - { - _typeFactory = tf; - _parentBindings = parent; - _classStack = stack; - _contextClass = cc; - _contextType = type; - } - - /* - /********************************************************** - /* Pass-through type resolution methods - /********************************************************** - */ - - public JavaType resolveType(Class cls) { - return _typeFactory._constructType(_classStack, cls, this); - } - - public JavaType resolveType(Type type) { - return _typeFactory._constructType(_classStack, type, this); - } - - /* - /********************************************************** - /* Accesors - /********************************************************** - */ - - public JavaType findType(String name, boolean mustFind) - { - if (_bindings == null) { - _resolve(); - } - JavaType t = _bindings.get(name); - if (t != null) { - return t; - } - if (_placeholders != null && _placeholders.contains(name)) { - return UNBOUND; - } - if (_parentBindings != null) { - return _parentBindings.findType(name, mustFind); - } - // nothing found, so... - // Should we throw an exception or just return null? - - /* 18-Feb-2011, tatu: There are some tricky type bindings within - * java.util, such as HashMap$KeySet; so let's punt the problem - * (honestly not sure what to do -- they are unbound for good, I think) - */ - if (_contextClass != null) { - if (ClassUtil.getEnclosingClass(_contextClass) != null) { - // [JACKSON-572]: Actually, let's skip this for all non-static inner classes - // (which will also cover 'java.util' type cases... - if (!Modifier.isStatic(_contextClass.getModifiers())) { - return UNBOUND; - } - } - } - - if (!mustFind) { - return null; - } - - String className; - if (_contextClass != null) { - className = _contextClass.getName(); - } else if (_contextType != null) { - className = _contextType.toString(); - } else { - className = "UNKNOWN"; - } - throw new IllegalArgumentException("Type variable '"+name - +"' can not be resolved (with context of class "+className+")"); - //t = UNBOUND; - } - - public void addBinding(String name, JavaType type) - { - // note: emptyMap() is unmodifiable, hence second check is needed: - if (_bindings == null || _bindings.size() == 0) { - _bindings = new LinkedHashMap(); - } - _bindings.put(name, type); - } - - public JavaType[] typesAsArray() - { - if (_bindings == null) { - _resolve(); - } - if (_bindings.size() == 0) { - return NO_TYPES; - } - return _bindings.values().toArray(new JavaType[_bindings.size()]); - } - - /* - /********************************************************** - /* Internal methods - /********************************************************** - */ - - // Only for tests! - protected int getBindingCount() { - if (_bindings == null) { - _resolve(); - } - return _bindings.size(); - } - - protected void _resolve() - { - _resolveBindings(_contextClass); - - // finally: may have root level type info too - if (_contextType != null) { - int count = _contextType.containedTypeCount(); - if (count > 0) { - for (int i = 0; i < count; ++i) { - String name = _contextType.containedTypeName(i); - JavaType type = _contextType.containedType(i); - addBinding(name, type); - } - } - } - - // nothing bound? mark with empty map to prevent further calls - if (_bindings == null) { - _bindings = Collections.emptyMap(); - } - } - - public void _addPlaceholder(String name) { - if (_placeholders == null) { - _placeholders = new HashSet(); - } - _placeholders.add(name); - } - - protected void _resolveBindings(Type t) - { - if (t == null) return; - - Class raw; - if (t instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) t; - Type[] args = pt.getActualTypeArguments(); - if (args != null && args.length > 0) { - Class rawType = (Class) pt.getRawType(); - TypeVariable[] vars = rawType.getTypeParameters(); - if (vars.length != args.length) { - throw new IllegalArgumentException("Strange parametrized type (in class "+rawType.getName()+"): number of type arguments != number of type parameters ("+args.length+" vs "+vars.length+")"); - } - for (int i = 0, len = args.length; i < len; ++i) { - TypeVariable var = vars[i]; - String name = var.getName(); - if (_bindings == null) { - _bindings = new LinkedHashMap(); - } else { - // 24-Mar-2010, tatu: Better ensure that we do not overwrite something - // collected earlier (since we descend towards super-classes): - if (_bindings.containsKey(name)) continue; - } - // first: add a placeholder to prevent infinite loops - _addPlaceholder(name); - // then resolve type - _bindings.put(name, _typeFactory._constructType(_classStack, args[i], this)); - } - } - raw = (Class)pt.getRawType(); - } else if (t instanceof Class) { - raw = (Class) t; - /* [JACKSON-677]: If this is an inner class then the generics are defined on the - * enclosing class so we have to check there as well. We don't - * need to call getEnclosingClass since anonymous classes declare - * generics - */ - Class decl = ClassUtil.getDeclaringClass(raw); - /* 08-Feb-2013, tatu: Except that if context is also super-class, we must - * skip it; context will be checked anyway, and we'd get StackOverflow if - * we went there. - */ - if (decl != null && !decl.isAssignableFrom(raw)) { - _resolveBindings(decl); - } - - /* 24-Mar-2010, tatu: Can not have true generics definitions, but can - * have lower bounds ("") in declaration itself - */ - TypeVariable[] vars = raw.getTypeParameters(); - if (vars != null && vars.length > 0) { - JavaType[] typeParams = null; - - if (_contextType != null && raw.isAssignableFrom(_contextType.getRawClass())) { - typeParams = _typeFactory.findTypeParameters(_contextType, raw); - } - - for (int i = 0; i < vars.length; i++) { - TypeVariable var = vars[i]; - - String name = var.getName(); - Type varType = var.getBounds()[0]; - if (varType != null) { - if (_bindings == null) { - _bindings = new LinkedHashMap(); - } else { // and no overwriting... - if (_bindings.containsKey(name)) continue; - } - _addPlaceholder(name); // to prevent infinite loops - - if (typeParams != null && typeParams.length > i) { - _bindings.put(name, typeParams[i]); - } else { - _bindings.put(name, _typeFactory._constructType(_classStack, varType, this)); - } - } - } - } - } else { // probably can't be any of these... so let's skip for now - //if (type instanceof GenericArrayType) { - //if (type instanceof TypeVariable) { - // if (type instanceof WildcardType) { - return; - } - // but even if it's not a parameterized type, its super types may be: - _resolveBindings(ClassUtil.getGenericSuperclass(raw)); - for (Type intType : raw.getGenericInterfaces()) { - _resolveBindings(intType); - } - } - - @Override - public String toString() - { - if (_bindings == null) { - _resolve(); - } - StringBuilder sb = new StringBuilder("[TypeBindings for "); - if (_contextType != null) { - sb.append(_contextType.toString()); - } else { - sb.append(_contextClass.getName()); - } - sb.append(": ").append(_bindings).append("]"); - return sb.toString(); - } -} diff --git a/pom.xml b/pom.xml index dade30be71..3728c5cd96 100644 --- a/pom.xml +++ b/pom.xml @@ -88,10 +88,17 @@ ${jackson.version.core} - - + + + org.junit.vintage + junit-vintage-engine + test + + + org.junit.jupiter + junit-jupiter + test + org.powermock powermock-core @@ -144,6 +151,18 @@ + + + + org.junit + junit-bom + 5.9.2 + pom + import + + + + diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 73f5c66d1a..c7e9be5ba3 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -6,6 +6,8 @@ databind core component, version 2.x Tatu Saloranta, tatu.saloranta@iki.fi: author +---------------------------------------------------------------------------- + Pascal GĀŽlinas: * Contributed fixes to 'MappingIterator' handling (Pull#58 and Pull#59) (2.1.0) @@ -1495,6 +1497,7 @@ PJ Fanning (pjfanning@github) (2.14.0) * Contributed #3837: Set transformer factory attributes to improve protection against XXE (2.14.3) + * ... and countless more Igor Shymko (ancane@github) * Contributed #3500: Add optional explicit `JsonSubTypes` repeated names check @@ -1595,6 +1598,9 @@ Sim Yih Tsern (yihtsern@github) (2.15.0) * Contributed fix for #3894: Only avoid Records fields detection for deserialization (2.15.1) + * Contributed fix for #3897: 2.15.0 breaks deserialization when POJO/Record only has a + single field and is marked `Access.WRITE_ONLY` + (2.15.1) Ajay Siwach (Siwach16@github) * Contributed #3637: Add enum features into `@JsonFormat.Feature` @@ -1624,3 +1630,13 @@ Steve Storey (stevestorey@github) strict subtype Type Id handling (2.15.0) +Matteo Bertozzi (matteobertozzi@github) + * Reported #3895: 2.15.0 breaking behaviour change for records and Getter Visibility + (2.15.1) + +Antti Lampinen (arlampin@github) + * Reported #3897: 2.15.0 breaks deserialization when POJO/Record only has a single field + and is marked `Access.WRITE_ONLY` + (2.15.1) + + diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 9855754393..3a80213e88 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -6,12 +6,25 @@ Project: jackson-databind 2.16.0 (not yet released) -No changes since 2.15 +#3928: `@JsonProperty` on constructor parameter changes default field serialization order + (contributed by @pjfanning) + +2.15.2 (not yet released) -2.15.1 (not yet released) +#3938: Record setter not included from interface (2.15 regression) +2.15.1 (16-May-2023) + +#3882: Error in creating nested `ArrayNode`s with `JsonNode.withArray()` + (reported by @SaiKrishna369) #3894: Only avoid Records fields detection for deserialization (contributed by Sim Y-T) +#3895: 2.15.0 breaking behaviour change for records and Getter Visibility + (reported by Matteo B) +#3897: 2.15.0 breaks deserialization when POJO/Record only has a single field + and is marked `Access.WRITE_ONLY` + (reported by Antti L) + (fix contributed by Sim Y-T) #3913: Issue with deserialization when there are unexpected properties (due to null `StreamReadConstraints`) (reported by @sbertault) @@ -99,7 +112,7 @@ No changes since 2.15 #3876: `TypeFactory` cache performance degradation with `constructSpecializedType()` (contributed by Carter K) -2.14.3 (not yet released) +2.14.3 (05-May-2023) #3784: `PrimitiveArrayDeserializers$ByteDeser.deserialize` ignores `DeserializationProblemHandler` for invalid Base64 content diff --git a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java index 2905a9beac..53d5bc9838 100644 --- a/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java @@ -59,7 +59,7 @@ public enum Type { * Usually this can be defined by using * {@link com.fasterxml.jackson.annotation.JsonManagedReference} */ - MANAGED_REFERENCE + MANAGED_REFERENCE, /** * Reference property that Jackson manages by suppressing it during serialization, @@ -67,7 +67,7 @@ public enum Type { * Usually this can be defined by using * {@link com.fasterxml.jackson.annotation.JsonBackReference} */ - ,BACK_REFERENCE + BACK_REFERENCE ; } diff --git a/src/main/java/com/fasterxml/jackson/databind/BeanDescription.java b/src/main/java/com/fasterxml/jackson/databind/BeanDescription.java index 9170f68049..dc256d13b3 100644 --- a/src/main/java/com/fasterxml/jackson/databind/BeanDescription.java +++ b/src/main/java/com/fasterxml/jackson/databind/BeanDescription.java @@ -40,7 +40,7 @@ protected BeanDescription(JavaType type) { /* /********************************************************** - /* Simple accesors + /* Simple accessors /********************************************************** */ diff --git a/src/main/java/com/fasterxml/jackson/databind/MapperFeature.java b/src/main/java/com/fasterxml/jackson/databind/MapperFeature.java index 2ecf7ee450..830c5f6742 100644 --- a/src/main/java/com/fasterxml/jackson/databind/MapperFeature.java +++ b/src/main/java/com/fasterxml/jackson/databind/MapperFeature.java @@ -40,7 +40,7 @@ public enum MapperFeature implements ConfigFeature * and Map to modify the property, without requiring a setter * method. * This is similar to how JAXB framework sets Collections and - * Maps: no setter is involved, just setter. + * Maps: no setter is involved, just getter. *

* Note that such getters-as-setters methods have lower * precedence than setters, so they are only used if no @@ -322,7 +322,7 @@ public enum MapperFeature implements ConfigFeature * Feature is enabled by default which means that deserialization does * support deserializing types via builders with type parameters (generic types). *

- * See: https://github.com/FasterXML/jackson-databind/issues/921 + * See: databind#921 * * @since 2.12 */ @@ -401,6 +401,11 @@ public enum MapperFeature implements ConfigFeature *

* Note: does not apply to {@link java.util.Map} serialization (since * entries are not considered Bean/POJO properties. + *

+ * WARNING: Disabling it may have a negative impact on deserialization performance. + * When disabled, all properties before the last creator property in the input need to be buffered, + * since all creator properties are required to create the instance. + * Enabling this feature ensures that there is as little buffering as possible. *

* Feature is enabled by default. * diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 7c92f52dab..0ce19c8689 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -4623,7 +4623,7 @@ public T updateValue(T valueToUpdate, Object overrides) * @param t The class to generate schema for * @return Constructed JSON schema. * - * @deprecated Since 2.6 use external JSON Schema generator (https://github.com/FasterXML/jackson-module-jsonSchema) + * @deprecated Since 2.6 use external JSON Schema generator (jackson-module-jsonSchema) * (which under the hood calls {@link #acceptJsonFormatVisitor(JavaType, JsonFormatVisitorWrapper)}) */ @Deprecated diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java index c48639927f..7ad51f1b8c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java @@ -947,19 +947,15 @@ public JsonSerializer getDefaultNullValueSerializer() { } /** - * Method called to get the serializer to use for serializing - * Map keys that are nulls: this is needed since JSON does not allow - * any non-String value as key, including null. - *

- * Typically, returned serializer - * will either throw an exception, or use an empty String; but - * other behaviors are possible. - */ - /** - * Method called to find a serializer to use for null values for given - * declared type. Note that type is completely based on declared type, + * Method called to find a serializer to serializes Map keys that are nulls, + * as JSON does not allow any non-String value as a key, including null. + * Note that type is completely based on declared type, * since nulls in Java have no type and thus runtime type cannot be * determined. + * + * @return JsonSerializer that handles the serialization of null keys, + * usually by throwing an exception or using an empty String, + * but other behaviors are also possible. * * @since 2.0 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/annotation/JsonAppend.java b/src/main/java/com/fasterxml/jackson/databind/annotation/JsonAppend.java index 122f6a7d08..e77e76e714 100644 --- a/src/main/java/com/fasterxml/jackson/databind/annotation/JsonAppend.java +++ b/src/main/java/com/fasterxml/jackson/databind/annotation/JsonAppend.java @@ -9,10 +9,12 @@ import com.fasterxml.jackson.databind.ser.VirtualBeanPropertyWriter; /** - * Annotation that may be used to add "virtual" properties to be written - * after regular properties (although ordering may be changed using - * both standard @JsonPropertyOrder annotation, and - * properties of this annotation). + * Annotation used to add "virtual" properties that will be written + * after regular properties during serialization. + *

+ * Please note that the "virtual" properties added using this annotation + * do not obey any specific order, including the order defined + * by {@link com.fasterxml.jackson.annotation.JsonPropertyOrder}. * * @since 2.5 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index adbfcdc012..88b0da75ae 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -1031,6 +1031,10 @@ private boolean _checkIfCreatorPropertyBased(BeanDescription beanDesc, return true; } } + // [databind#3897]: Record canonical constructor will have implicitly named propDef + if (!propDef.isExplicitlyNamed() && beanDesc.isRecordType()) { + return true; + } } // in absence of everything else, default to delegating return false; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java index 16a219aac3..fa21406337 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java @@ -474,7 +474,9 @@ protected Object _deserializeUsingPropertyBased(final JsonParser p, final Deseri // weren't removed (to help in creating constructor-backed PropertyCreator) // so they ended up in _beanProperties, unlike POJO (whose ignored // props are removed) - if ((prop != null) && !_beanType.isRecordType()) { + if ((prop != null) && + // [databind#3938]: except if it's MethodProperty + (!_beanType.isRecordType() || (prop instanceof MethodProperty))) { try { buffer.bufferProperty(prop, _deserializeWithErrorWrapping(p, ctxt, prop)); } catch (UnresolvedForwardReference reference) { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java index 15175767d4..76c07a661f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java @@ -529,8 +529,8 @@ public void resolveForwardReference(Object id, Object value) throws IOException /** * Helper class to maintain processing order of value. The resolved - * object associated with {@link #_id} comes before the values in - * {@link #next}. + * object associated with {@code #id} parameter from {@link #handleResolvedForwardReference(Object, Object)} + * comes before the values in {@link #next}. */ private final static class CollectionReferring extends Referring { private final CollectionReferringAccumulator _parent; diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java index 24e850315b..c184c80701 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java @@ -202,8 +202,7 @@ public static AnnotatedClass construct(JavaType type, MapperConfig config, * Method similar to {@link #construct}, but that will NOT include * information from supertypes; only class itself and any direct * mix-ins it may have. - */ - /** + * * @deprecated Since 2.9, use methods in {@link AnnotatedClassResolver} instead. */ @Deprecated diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java index fabeb15cbb..40df20e693 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java @@ -91,7 +91,7 @@ public class POJOPropertiesCollector /** * A set of "field renamings" that have been discovered, indicating - * intended renaming of other accesors: key is the implicit original + * intended renaming of other accessors: key is the implicit original * name and value intended name to use instead. *

* Note that these renamings are applied earlier than "regular" (explicit) @@ -437,17 +437,18 @@ protected void collectAll() LinkedHashMap props = new LinkedHashMap(); // First: gather basic data - + final boolean isRecord = isRecordType(); // 15-Jan-2023, tatu: [databind#3736] Let's avoid detecting fields of Records // altogether (unless we find a good reason to detect them) // 17-Apr-2023: Need Records' fields for serialization for cases like [databind#3895] & [databind#3628] - if (!isRecordType() || _forSerialization) { + if (!isRecord || _forSerialization) { _addFields(props); // note: populates _fieldRenameMappings } _addMethods(props); // 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static // inner classes, see [databind#1502] - if (!_classDef.isNonStaticInnerClass()) { + // 13-May-2023, PJ: Need to avoid adding creators for Records when serializing [databind#3925] + if (!_classDef.isNonStaticInnerClass() && !(_forSerialization && isRecord)) { _addCreators(props); } @@ -761,7 +762,7 @@ protected void _addMethods(Map props) _addGetterMethod(props, m, _annotationIntrospector); } else if (argCount == 1) { // setters _addSetterMethod(props, m, _annotationIntrospector); - } else if (argCount == 2) { // any getter? + } else if (argCount == 2) { // any setter? if (Boolean.TRUE.equals(_annotationIntrospector.hasAnySetter(m))) { if (_anySetters == null) { _anySetters = new LinkedList(); diff --git a/src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java b/src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java index 0f1ac43b7e..06e2800e68 100644 --- a/src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java +++ b/src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java @@ -188,9 +188,9 @@ protected ArrayNode _withArrayAddTailElement(JsonPointer tail, boolean preferInd _withXxxSetArrayElement(index, next); return next._withArrayAddTailElement(tail, preferIndex); } - ArrayNode next = this.arrayNode(); + ObjectNode next = this.objectNode(); _withXxxSetArrayElement(index, next); - return next._withArrayAddTailElement(tail, preferIndex); + return next._withArrayAddTailProperty(tail, preferIndex); } protected void _withXxxSetArrayElement(int index, JsonNode 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 bca1f7d41e..2c9f0ac6f9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java @@ -233,7 +233,7 @@ protected Map _createObjectIdMap() /* /********************************************************** - /* Extended API: simple accesors + /* Extended API: simple accessors /********************************************************** */ diff --git a/src/main/java/com/fasterxml/jackson/databind/util/internal/PrivateMaxEntriesMap.java b/src/main/java/com/fasterxml/jackson/databind/util/internal/PrivateMaxEntriesMap.java index 4cd867afdd..d74b89aa0b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/internal/PrivateMaxEntriesMap.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/internal/PrivateMaxEntriesMap.java @@ -136,7 +136,7 @@ public final class PrivateMaxEntriesMap extends AbstractMap /** * The number of read buffers to use. - * The max of 4 was introduced due to https://github.com/FasterXML/jackson-databind/issues/3665. + * The max of 4 was introduced due to databind#3665. */ static final int NUMBER_OF_READ_BUFFERS = Math.min(4, ceilingNextPowerOfTwo(NCPU)); @@ -145,7 +145,7 @@ public final class PrivateMaxEntriesMap extends AbstractMap /** * The number of pending read operations before attempting to drain. - * The threshold of 4 was introduced due to https://github.com/FasterXML/jackson-databind/issues/3665. + * The threshold of 4 was introduced due to databind#3665. */ static final int READ_BUFFER_THRESHOLD = 4; diff --git a/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordBasicsTest.java b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordBasicsTest.java index f94231b526..c2dfb3261d 100644 --- a/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordBasicsTest.java +++ b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordBasicsTest.java @@ -40,6 +40,20 @@ record SnakeRecord(String myId, String myValue){} record RecordWithJsonDeserialize(int id, @JsonDeserialize(converter = StringTrimmer.class) String name) { } + record RecordSingleWriteOnly(@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) int id) { } + + record RecordSomeWriteOnly( + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) int id, + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) String name, + String email) { + } + + record RecordAllWriteOnly( + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) int id, + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) String name, + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) String email) { + } + private final ObjectMapper MAPPER = newJsonMapper(); /* @@ -204,6 +218,53 @@ public void testDeserializeJsonDeserializeRecord() throws Exception { assertEquals(new RecordWithJsonDeserialize(123, "Bob"), value); } + /* + /********************************************************************** + /* Test methods, JsonProperty(access=WRITE_ONLY) + /********************************************************************** + */ + + public void testSerialize_SingleWriteOnlyParameter() throws Exception { + String json = MAPPER.writeValueAsString(new RecordSingleWriteOnly(123)); + + assertEquals("{}", json); + } + + // [databind#3897] + public void testDeserialize_SingleWriteOnlyParameter() throws Exception { + RecordSingleWriteOnly value = MAPPER.readValue("{\"id\":123}", RecordSingleWriteOnly.class); + + assertEquals(new RecordSingleWriteOnly(123), value); + } + + public void testSerialize_SomeWriteOnlyParameter() throws Exception { + String json = MAPPER.writeValueAsString(new RecordSomeWriteOnly(123, "Bob", "bob@example.com")); + + assertEquals("{\"email\":\"bob@example.com\"}", json); + } + + public void testDeserialize_SomeWriteOnlyParameter() throws Exception { + RecordSomeWriteOnly value = MAPPER.readValue( + "{\"id\":123,\"name\":\"Bob\",\"email\":\"bob@example.com\"}", + RecordSomeWriteOnly.class); + + assertEquals(new RecordSomeWriteOnly(123, "Bob", "bob@example.com"), value); + } + + public void testSerialize_AllWriteOnlyParameter() throws Exception { + String json = MAPPER.writeValueAsString(new RecordAllWriteOnly(123, "Bob", "bob@example.com")); + + assertEquals("{}", json); + } + + public void testDeserialize_AllWriteOnlyParameter() throws Exception { + RecordAllWriteOnly value = MAPPER.readValue( + "{\"id\":123,\"name\":\"Bob\",\"email\":\"bob@example.com\"}", + RecordAllWriteOnly.class); + + assertEquals(new RecordAllWriteOnly(123, "Bob", "bob@example.com"), value); + } + /* /********************************************************************** /* Internal helper methods diff --git a/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordFailingSetter3938Test.java b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordFailingSetter3938Test.java new file mode 100644 index 0000000000..3fe8cfef18 --- /dev/null +++ b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordFailingSetter3938Test.java @@ -0,0 +1,42 @@ +package com.fasterxml.jackson.databind.records; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.*; + +public class RecordFailingSetter3938Test extends BaseMapTest +{ + private final static String ERROR_3938_PREFIX = "Non-null 'options' not allowed for "; + + // [databind#3938] + interface NoOptionsCommand { + @JsonProperty("options") + default void setOptions(JsonNode value) { + if (value.isNull()) { + return; + } + throw new IllegalArgumentException(ERROR_3938_PREFIX+getClass().getName()); + } + } + + public record Command3938(int id, String filter) implements NoOptionsCommand { } + + private final ObjectMapper MAPPER = newJsonMapper(); + + // [databind#3938]: Should detect and use setters too + public void testFailingSetter3939() throws Exception + { + final ObjectReader R = MAPPER.readerFor(Command3938.class); + + // First, missing value and `null` are fine, as long as we have all fields + assertNotNull(R.readValue(a2q("{'id':1, 'filter':'abc'}"))); + assertNotNull(R.readValue(a2q("{'id':2, 'filter':'abc', 'options':null}"))); + + // But then failure for non-empty Array (f.ex) + try { + R.readValue(a2q("{'id':2,'options':[123]}}")); + fail("Should not pass"); + } catch (DatabindException e) { + verifyException(e, ERROR_3938_PREFIX); + } + } +} diff --git a/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordSerializationOrderTest.java b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordSerializationOrderTest.java new file mode 100644 index 0000000000..494904c3e9 --- /dev/null +++ b/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordSerializationOrderTest.java @@ -0,0 +1,66 @@ +package com.fasterxml.jackson.databind.records; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RecordSerializationOrderTest extends BaseMapTest +{ + record NestedRecordOne(String id, String email, NestedRecordTwo nestedRecordTwo) {} + record NestedRecordOneWithJsonProperty(String id, String email, + @JsonProperty("nestedProperty") NestedRecordTwo nestedRecordTwo) {} + record NestedRecordOneWithJsonPropertyIndex(@JsonProperty(index = 2) String id, + @JsonProperty(index = 0) String email, + @JsonProperty(value = "nestedProperty", index = 1) NestedRecordTwo nestedRecordTwo) {} + + @JsonPropertyOrder({"email", "nestedProperty", "id"}) + record NestedRecordOneWithJsonPropertyOrder(String id, + String email, + @JsonProperty(value = "nestedProperty") NestedRecordTwo nestedRecordTwo) {} + + record NestedRecordTwo(String id, String passport) {} + + private final ObjectMapper MAPPER = newJsonMapper(); + + /* + /********************************************************************** + /* Test methods, alternate constructors + /********************************************************************** + */ + + public void testSerializationOrder() throws Exception { + NestedRecordTwo nestedRecordTwo = new NestedRecordTwo("2", "111110"); + NestedRecordOne nestedRecordOne = new NestedRecordOne("1", "test@records.com", nestedRecordTwo); + final String output = MAPPER.writeValueAsString(nestedRecordOne); + final String expected = "{\"id\":\"1\",\"email\":\"test@records.com\",\"nestedRecordTwo\":{\"id\":\"2\",\"passport\":\"111110\"}}"; + assertEquals(expected, output); + } + + public void testSerializationOrderWithJsonProperty() throws Exception { + NestedRecordTwo nestedRecordTwo = new NestedRecordTwo("2", "111110"); + NestedRecordOneWithJsonProperty nestedRecordOne = + new NestedRecordOneWithJsonProperty("1", "test@records.com", nestedRecordTwo); + final String output = MAPPER.writeValueAsString(nestedRecordOne); + final String expected = "{\"id\":\"1\",\"email\":\"test@records.com\",\"nestedProperty\":{\"id\":\"2\",\"passport\":\"111110\"}}"; + assertEquals(expected, output); + } + + public void testSerializationOrderWithJsonPropertyIndexes() throws Exception { + NestedRecordTwo nestedRecordTwo = new NestedRecordTwo("2", "111110"); + NestedRecordOneWithJsonPropertyIndex nestedRecordOne = + new NestedRecordOneWithJsonPropertyIndex("1", "test@records.com", nestedRecordTwo); + final String output = MAPPER.writeValueAsString(nestedRecordOne); + final String expected = "{\"email\":\"test@records.com\",\"nestedProperty\":{\"id\":\"2\",\"passport\":\"111110\"},\"id\":\"1\"}"; + assertEquals(expected, output); + } + + public void testSerializationOrderWithJsonPropertyOrder() throws Exception { + NestedRecordTwo nestedRecordTwo = new NestedRecordTwo("2", "111110"); + NestedRecordOneWithJsonPropertyOrder nestedRecordOne = + new NestedRecordOneWithJsonPropertyOrder("1", "test@records.com", nestedRecordTwo); + final String output = MAPPER.writeValueAsString(nestedRecordOne); + final String expected = "{\"email\":\"test@records.com\",\"nestedProperty\":{\"id\":\"2\",\"passport\":\"111110\"},\"id\":\"1\"}"; + assertEquals(expected, output); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepJsonNodeDeser3397Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepJsonNodeDeser3397Test.java index f846453282..adbf3e051d 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepJsonNodeDeser3397Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepJsonNodeDeser3397Test.java @@ -13,7 +13,7 @@ public class DeepJsonNodeDeser3397Test extends BaseMapTest // ... currently gets a bit slow at 1M but passes. // But test with 100k as practical limit, to guard against regression // private final static int TOO_DEEP_NESTING = 1_000_000; - private final static int TOO_DEEP_NESTING = 10_000; + private final static int TOO_DEEP_NESTING = StreamReadConstraints.DEFAULT_MAX_DEPTH * 10; private final JsonFactory jsonFactory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build()) diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepNestingUntypedDeserTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepNestingUntypedDeserTest.java index 963040b9af..6389da8841 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepNestingUntypedDeserTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/dos/DeepNestingUntypedDeserTest.java @@ -18,7 +18,7 @@ public class DeepNestingUntypedDeserTest extends BaseMapTest // 31-May-2022, tatu: But no more! Can handle much much larger // nesting levels, bounded by memory usage not stack. Tested with // 1 million (!) nesting levels, but to keep tests fast use 100k - private final static int TOO_DEEP_NESTING = 100_000; + private final static int TOO_DEEP_NESTING = StreamReadConstraints.DEFAULT_MAX_DEPTH * 100; private final JsonFactory jsonFactory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build()) diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/dos/StreamReadStringConstraintsTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/dos/StreamReadStringConstraintsTest.java index d7c26882b4..15c29eee2b 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/dos/StreamReadStringConstraintsTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/dos/StreamReadStringConstraintsTest.java @@ -9,7 +9,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; /** - * Tests for {@a href="https://github.com/FasterXML/jackson-core/issues/863"}. + * Tests for databind#863" */ public class StreamReadStringConstraintsTest extends BaseMapTest { @@ -32,6 +32,8 @@ void setString(String string) { /********************************************************************** */ + private final static int TOO_LONG_STRING_VALUE = StreamReadConstraints.DEFAULT_MAX_STRING_LEN + 100; + private final ObjectMapper MAPPER = newJsonMapper(); private ObjectMapper newJsonMapperWithUnlimitedStringSizeSupport() { @@ -44,31 +46,32 @@ private ObjectMapper newJsonMapperWithUnlimitedStringSizeSupport() { public void testBigString() throws Exception { try { - MAPPER.readValue(generateJson("string", 5001000), StringWrapper.class); - fail("expected JsonMappingException"); + MAPPER.readValue(generateJson("string", TOO_LONG_STRING_VALUE), StringWrapper.class); + fail("expected DatabindException"); } catch (DatabindException e) { - assertTrue("unexpected exception message: " + e.getMessage(), - e.getMessage().startsWith("String value length (5001000) exceeds the maximum allowed (5000000")); + final String message = e.getMessage(); + assertTrue("unexpected exception message: " + message, message.startsWith("String value length")); + assertTrue("unexpected exception message: " + message, message.contains("exceeds the maximum allowed (")); } } public void testBiggerString() throws Exception { try { - MAPPER.readValue(generateJson("string", 6_000_000), StringWrapper.class); + MAPPER.readValue(generateJson("string", TOO_LONG_STRING_VALUE), StringWrapper.class); fail("expected JsonMappingException"); } catch (DatabindException e) { final String message = e.getMessage(); // this test fails when the TextBuffer is being resized, so we don't yet know just how big the string is // so best not to assert that the String length value in the message is the full 6000000 value assertTrue("unexpected exception message: " + message, message.startsWith("String value length")); - assertTrue("unexpected exception message: " + message, message.contains("exceeds the maximum allowed (5000000")); + assertTrue("unexpected exception message: " + message, message.contains("exceeds the maximum allowed (")); } } public void testUnlimitedString() throws Exception { - final int len = 5_001_000; + final int len = TOO_LONG_STRING_VALUE; StringWrapper sw = newJsonMapperWithUnlimitedStringSizeSupport() .readValue(generateJson("string", len), StringWrapper.class); assertEquals(len, sw.string.length()); diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestPolymorphicDeserialization676.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestPolymorphicDeserialization676.java index d6b1bcc557..063e4bf594 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestPolymorphicDeserialization676.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestPolymorphicDeserialization676.java @@ -8,7 +8,7 @@ import java.util.*; /** - * Reproduction of [https://github.com/FasterXML/jackson-databind/issues/676] + * Reproduction of databind#676 *

* Deserialization of class with generic collection inside * depends on how is was deserialized first time. diff --git a/src/test/java/com/fasterxml/jackson/databind/node/WithPathTest.java b/src/test/java/com/fasterxml/jackson/databind/node/WithPathTest.java index f3e86cc986..73cbf1e1e2 100644 --- a/src/test/java/com/fasterxml/jackson/databind/node/WithPathTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/node/WithPathTest.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.JsonNode.OverwriteMode; -// for [databuind#1980] implementation +// for [databind#1980] implementation public class WithPathTest extends BaseMapTest { private final ObjectMapper MAPPER = sharedMapper(); @@ -296,4 +296,23 @@ private void _verifyArrayReplaceFail(JsonNode doc, JsonPointer ptr, OverwriteMod verifyException(e, "(mode `OverwriteMode."+mode.name()+"`)"); } } + + // [databind#3882] + public void testWithArray3882() throws Exception + { + ObjectNode root = MAPPER.createObjectNode(); + ArrayNode aN = root.withArray("/key/0/a", + JsonNode.OverwriteMode.ALL, true); + aN.add(123); + assertEquals(a2q("{'key':[{'a':[123]}]}"), + root.toString()); + + // And then the original case + root = MAPPER.createObjectNode(); + aN = root.withArray(JsonPointer.compile("/key1/array1/0/element1"), + JsonNode.OverwriteMode.ALL, true); + aN.add("v1"); + assertEquals(a2q("{'key1':{'array1':[{'element1':['v1']}]}}"), + root.toString()); + } }