From 0b769e24a6882907ceca1b023f22e8729538979c Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 2 May 2025 17:52:04 -0700 Subject: [PATCH 1/6] Work towards #4907: reduce introspection for "java.*" classes (and maybe others too) --- .../jackson/databind/BeanDescription.java | 15 +++-- .../jackson/databind/DatabindContext.java | 19 ++++-- .../databind/DeserializationContext.java | 27 +++++++-- .../databind/SerializationContext.java | 4 +- .../introspect/BasicClassIntrospector.java | 18 +++--- .../introspect/ClassIntrospector.java | 9 ++- .../misc/Reflection4907Jackson3Test.java | 58 +++++++++++++++++++ 7 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java diff --git a/src/main/java/tools/jackson/databind/BeanDescription.java b/src/main/java/tools/jackson/databind/BeanDescription.java index 881516ed78..7d15029870 100644 --- a/src/main/java/tools/jackson/databind/BeanDescription.java +++ b/src/main/java/tools/jackson/databind/BeanDescription.java @@ -331,6 +331,8 @@ public static abstract class LazySupplier implements Supplier { protected final JavaType _type; + protected transient AnnotatedClass _classDesc; + protected transient BeanDescription _beanDesc; protected LazySupplier(JavaType type) { @@ -352,23 +354,28 @@ protected LazySupplier(JavaType type) { @Override public Annotations getClassAnnotations() { - return get().getClassAnnotations(); + return getClassInfo().getAnnotations(); } @Override public AnnotatedClass getClassInfo() { - return get().getClassInfo(); + if (_classDesc == null) { + + } + return _classDesc; } @Override public BeanDescription get() { if (_beanDesc == null) { - _beanDesc = _construct(_type); + _beanDesc = _construct(_type, getClassInfo()); } return _beanDesc; } - protected abstract BeanDescription _construct(JavaType forType); + protected abstract AnnotatedClass _introspect(JavaType forType); + + protected abstract BeanDescription _construct(JavaType forType, AnnotatedClass ac); } /** diff --git a/src/main/java/tools/jackson/databind/DatabindContext.java b/src/main/java/tools/jackson/databind/DatabindContext.java index b2d7364384..28f5227a45 100644 --- a/src/main/java/tools/jackson/databind/DatabindContext.java +++ b/src/main/java/tools/jackson/databind/DatabindContext.java @@ -307,18 +307,29 @@ protected abstract DatabindException invalidTypeIdException(JavaType baseType, S */ /** - * Convenience method for doing full "for serialization" introspection of specified - * type; results may be cached during lifespan of this context as well. + * Convenience method for doing full "for serialization or deserialization" + * introspection of specified type; results may be cached for duration (lifespan) + * of this context as well. */ - public abstract BeanDescription introspectBeanDescription(JavaType type); + public final BeanDescription introspectBeanDescription(JavaType type) { + return introspectBeanDescription(type, introspectClassAnnotations(type)); + } + + public abstract BeanDescription introspectBeanDescription(JavaType type, + AnnotatedClass classDef); public BeanDescription.Supplier lazyIntrospectBeanDescription(JavaType type) { return new BeanDescription.LazySupplier(type) { @Override - public BeanDescription _construct(JavaType forType) { + protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) { // System.out.println("lazyIntrospectBeanDescription("+forType+")"); return introspectBeanDescription(forType); } + + @Override + protected AnnotatedClass _introspect(JavaType forType) { + return introspectClassAnnotations(forType); + } }; } diff --git a/src/main/java/tools/jackson/databind/DeserializationContext.java b/src/main/java/tools/jackson/databind/DeserializationContext.java index baa0f0420b..55fe980039 100644 --- a/src/main/java/tools/jackson/databind/DeserializationContext.java +++ b/src/main/java/tools/jackson/databind/DeserializationContext.java @@ -528,19 +528,29 @@ protected ClassIntrospector classIntrospector() { } @Override - public BeanDescription introspectBeanDescription(JavaType type) { - return classIntrospector().introspectForDeserialization(type); + public BeanDescription introspectBeanDescription(JavaType type, AnnotatedClass ac) { + return classIntrospector().introspectForDeserialization(type, ac); } public BeanDescription introspectBeanDescriptionForCreation(JavaType type) { - return classIntrospector().introspectForCreation(type); + return introspectBeanDescriptionForCreation(type, + classIntrospector().introspectClassAnnotations(type)); + } + + public BeanDescription introspectBeanDescriptionForCreation(JavaType type, AnnotatedClass ac) { + return classIntrospector().introspectForCreation(type, ac); } public BeanDescription.Supplier lazyIntrospectBeanDescriptionForCreation(JavaType type) { return new BeanDescription.LazySupplier(type) { @Override - public BeanDescription _construct(JavaType forType) { - return introspectBeanDescriptionForCreation(forType); + protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) { + return introspectBeanDescriptionForCreation(forType, ac); + } + + @Override + protected AnnotatedClass _introspect(JavaType forType) { + return introspectClassAnnotations(forType); } }; } @@ -555,9 +565,14 @@ public BeanDescription.Supplier lazyIntrospectBeanDescriptionForBuilder(final Ja final BeanDescription valueTypeDesc) { return new BeanDescription.LazySupplier(builderType) { @Override - public BeanDescription _construct(JavaType forType) { + protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) { return introspectBeanDescriptionForBuilder(forType, valueTypeDesc); } + + @Override + protected AnnotatedClass _introspect(JavaType forType) { + return introspectClassAnnotations(forType); + } }; } diff --git a/src/main/java/tools/jackson/databind/SerializationContext.java b/src/main/java/tools/jackson/databind/SerializationContext.java index d9f06043e0..d5b36eb15b 100644 --- a/src/main/java/tools/jackson/databind/SerializationContext.java +++ b/src/main/java/tools/jackson/databind/SerializationContext.java @@ -421,8 +421,8 @@ protected ClassIntrospector classIntrospector() { } @Override - public BeanDescription introspectBeanDescription(JavaType type) { - return classIntrospector().introspectForSerialization(type); + public BeanDescription introspectBeanDescription(JavaType type, AnnotatedClass ac) { + return classIntrospector().introspectForSerialization(type, ac); } /* diff --git a/src/main/java/tools/jackson/databind/introspect/BasicClassIntrospector.java b/src/main/java/tools/jackson/databind/introspect/BasicClassIntrospector.java index 2f929cef78..c3a6cfec0d 100644 --- a/src/main/java/tools/jackson/databind/introspect/BasicClassIntrospector.java +++ b/src/main/java/tools/jackson/databind/introspect/BasicClassIntrospector.java @@ -147,7 +147,8 @@ protected AnnotatedClass _resolveAnnotatedWithoutSuperTypes(JavaType type) { */ @Override - public BasicBeanDescription introspectForSerialization(JavaType type) + public BasicBeanDescription introspectForSerialization(JavaType type, + AnnotatedClass classDef) { // minor optimization: for some JDK types do minimal introspection BasicBeanDescription desc = _findStdTypeDesc(type); @@ -165,8 +166,7 @@ public BasicBeanDescription introspectForSerialization(JavaType type) } } desc = BasicBeanDescription.forSerialization(collectProperties(type, - introspectClassAnnotations(type), - true, "set")); + classDef, true, "set")); _resolvedSerBeanDescs.put(type, desc); } } @@ -174,7 +174,8 @@ public BasicBeanDescription introspectForSerialization(JavaType type) } @Override - public BasicBeanDescription introspectForDeserialization(JavaType type) + public BasicBeanDescription introspectForDeserialization(JavaType type, + AnnotatedClass classDef) { // minor optimization: for some JDK types do minimal introspection BasicBeanDescription desc = _findStdTypeDesc(type); @@ -192,8 +193,7 @@ public BasicBeanDescription introspectForDeserialization(JavaType type) } } desc = BasicBeanDescription.forDeserialization(collectProperties(type, - introspectClassAnnotations(type), - false, "set")); + classDef, false, "set")); _resolvedDeserBeanDescs.put(type, desc); } } @@ -211,7 +211,8 @@ public BasicBeanDescription introspectForDeserializationWithBuilder(JavaType typ } @Override - public BasicBeanDescription introspectForCreation(JavaType type) + public BasicBeanDescription introspectForCreation(JavaType type, + AnnotatedClass classDef) { BasicBeanDescription desc = _findStdTypeDesc(type); if (desc == null) { @@ -220,8 +221,7 @@ public BasicBeanDescription introspectForCreation(JavaType type) desc = _findStdJdkCollectionDesc(type); if (desc == null) { desc = BasicBeanDescription.forDeserialization(collectProperties(type, - introspectClassAnnotations(type), - false, "set")); + classDef, false, "set")); } } return desc; diff --git a/src/main/java/tools/jackson/databind/introspect/ClassIntrospector.java b/src/main/java/tools/jackson/databind/introspect/ClassIntrospector.java index c1ac657a3b..4f77d103cd 100644 --- a/src/main/java/tools/jackson/databind/introspect/ClassIntrospector.java +++ b/src/main/java/tools/jackson/databind/introspect/ClassIntrospector.java @@ -61,13 +61,15 @@ protected ClassIntrospector() { } * Factory method that constructs an introspector that has all * information needed for serialization purposes. */ - public abstract BeanDescription introspectForSerialization(JavaType type); + public abstract BeanDescription introspectForSerialization(JavaType type, + AnnotatedClass classDef); /** * Factory method that constructs an introspector that has all * information needed for deserialization purposes. */ - public abstract BeanDescription introspectForDeserialization(JavaType type); + public abstract BeanDescription introspectForDeserialization(JavaType type, + AnnotatedClass classDef); /** * Factory method that constructs an introspector that has all @@ -83,5 +85,6 @@ public abstract BeanDescription introspectForDeserializationWithBuilder(JavaType * class ("creator"), as well as class annotations, but * no information on member methods */ - public abstract BeanDescription introspectForCreation(JavaType type); + public abstract BeanDescription introspectForCreation(JavaType type, + AnnotatedClass classDef); } diff --git a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java new file mode 100644 index 0000000000..a41d764b72 --- /dev/null +++ b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java @@ -0,0 +1,58 @@ +package tools.jackson.databind.misc; + +import org.junit.jupiter.api.Test; + +import tools.jackson.databind.*; +import tools.jackson.databind.testutil.DatabindTestUtil; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class Reflection4907Jackson3Test extends DatabindTestUtil +{ + static class SqlDatePojo { + public String name; + public java.sql.Date date; + + public SqlDatePojo() { + } + + public SqlDatePojo(String name, java.sql.Date date) { + this.name = name; + this.date = date; + } + + public SqlDatePojo(java.sql.Date date) { + this.date = date; + } + + public java.sql.Date getDate() { + return date; + } + + public void setDate(java.sql.Date date) { + this.date = date; + } + } + + private final ObjectMapper MAPPER = newJsonMapper(); + + // [databind#4907] + @Test + public void test4907Read() throws Exception { +System.err.println(""); + SqlDatePojo pojo = MAPPER.readValue(a2q("{'date':'2000-01-01', 'name':'foo'}"), + SqlDatePojo.class); +System.err.println(""); + assertNotNull(pojo); + } + + // [databind#4907] + @Test + public void test4907Write() throws Exception { +System.err.println(""); + String json = MAPPER.writeValueAsString(new SqlDatePojo("foobar", + java.sql.Date.valueOf("2000-01-01"))); + System.err.println(""); + assertNotNull(json); + } +} From dd9e1ea5886d7ac7ad13bdb7bba90db1ef8b8f4c Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 2 May 2025 17:57:54 -0700 Subject: [PATCH 2/6] fix --- src/main/java/tools/jackson/databind/BeanDescription.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/tools/jackson/databind/BeanDescription.java b/src/main/java/tools/jackson/databind/BeanDescription.java index 7d15029870..ec1f1dd758 100644 --- a/src/main/java/tools/jackson/databind/BeanDescription.java +++ b/src/main/java/tools/jackson/databind/BeanDescription.java @@ -360,7 +360,7 @@ public Annotations getClassAnnotations() { @Override public AnnotatedClass getClassInfo() { if (_classDesc == null) { - + _classDesc = _introspect(_type); } return _classDesc; } From aa3bd024b0541f4f075e09a8a1e02483e19896a2 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sat, 3 May 2025 10:26:44 -0700 Subject: [PATCH 3/6] ... --- .../jackson/databind/BeanDescription.java | 3 ++- .../jackson/databind/DatabindContext.java | 3 ++- .../introspect/BasicBeanDescription.java | 4 +-- .../introspect/POJOPropertiesCollector.java | 1 + .../misc/Reflection4907Jackson3Test.java | 25 ++++++++++++++++--- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/java/tools/jackson/databind/BeanDescription.java b/src/main/java/tools/jackson/databind/BeanDescription.java index ec1f1dd758..30bf495e24 100644 --- a/src/main/java/tools/jackson/databind/BeanDescription.java +++ b/src/main/java/tools/jackson/databind/BeanDescription.java @@ -368,7 +368,8 @@ public AnnotatedClass getClassInfo() { @Override public BeanDescription get() { if (_beanDesc == null) { - _beanDesc = _construct(_type, getClassInfo()); +// _beanDesc = _construct(_type, getClassInfo()); + return _construct(_type, getClassInfo()); } return _beanDesc; } diff --git a/src/main/java/tools/jackson/databind/DatabindContext.java b/src/main/java/tools/jackson/databind/DatabindContext.java index 28f5227a45..6492a6ee2e 100644 --- a/src/main/java/tools/jackson/databind/DatabindContext.java +++ b/src/main/java/tools/jackson/databind/DatabindContext.java @@ -322,12 +322,13 @@ public BeanDescription.Supplier lazyIntrospectBeanDescription(JavaType type) { return new BeanDescription.LazySupplier(type) { @Override protected BeanDescription _construct(JavaType forType, AnnotatedClass ac) { -// System.out.println("lazyIntrospectBeanDescription("+forType+")"); + System.out.println("lazyIntrospectBeanDescription.beanDesc("+forType+")"); return introspectBeanDescription(forType); } @Override protected AnnotatedClass _introspect(JavaType forType) { + System.out.println("lazyIntrospectBeanDescription.annotatedClass("+forType+")"); return introspectClassAnnotations(forType); } }; diff --git a/src/main/java/tools/jackson/databind/introspect/BasicBeanDescription.java b/src/main/java/tools/jackson/databind/introspect/BasicBeanDescription.java index d83e955b64..de7135ab8b 100644 --- a/src/main/java/tools/jackson/databind/introspect/BasicBeanDescription.java +++ b/src/main/java/tools/jackson/databind/introspect/BasicBeanDescription.java @@ -99,9 +99,7 @@ protected BasicBeanDescription(POJOPropertiesCollector coll, super(type); _propCollector = coll; _config = Objects.requireNonNull(coll.getConfig()); - // NOTE: null config only for some pre-constructed types - _intr = (_config == null) ? NopAnnotationIntrospector.nopInstance() - : _config.getAnnotationIntrospector(); + _intr = _config.getAnnotationIntrospector(); _classInfo = classDef; } diff --git a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java index 7aa0ab937e..4934f51833 100644 --- a/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java +++ b/src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java @@ -379,6 +379,7 @@ public JsonFormat.Value getFormatOverrides() { */ protected void collectAll() { +System.out.println(" PojoPropsCollector.collectAll() for "+_classDef.getRawType().getName()); _potentialCreators = new PotentialCreators(); // First: gather basic accessors diff --git a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java index a41d764b72..2d065f6446 100644 --- a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java +++ b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java @@ -36,9 +36,9 @@ public void setDate(java.sql.Date date) { private final ObjectMapper MAPPER = newJsonMapper(); - // [databind#4907] + /* @Test - public void test4907Read() throws Exception { + public void test4907ReadPojo() throws Exception { System.err.println(""); SqlDatePojo pojo = MAPPER.readValue(a2q("{'date':'2000-01-01', 'name':'foo'}"), SqlDatePojo.class); @@ -46,13 +46,30 @@ public void test4907Read() throws Exception { assertNotNull(pojo); } - // [databind#4907] @Test - public void test4907Write() throws Exception { + public void test4907WritePojo() throws Exception { System.err.println(""); String json = MAPPER.writeValueAsString(new SqlDatePojo("foobar", java.sql.Date.valueOf("2000-01-01"))); System.err.println(""); assertNotNull(json); } + */ + + @Test + public void test4907ReadDate() throws Exception { +System.err.println(""); + java.sql.Date date = MAPPER.readValue(a2q("'2000-01-01'"), + java.sql.Date.class); +System.err.println(""); + assertNotNull(date); + } + + @Test + public void test4907WriteDate() throws Exception { +System.err.println(""); + String json = MAPPER.writeValueAsString(java.sql.Date.valueOf("2000-01-01")); + System.err.println(""); + assertNotNull(json); + } } From 1fe74d6b1f1f7bfb434e1bbe162a5c71177afa3a Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 20 May 2025 18:20:30 -0700 Subject: [PATCH 4/6] ... --- src/main/java/tools/jackson/databind/BeanDescription.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/tools/jackson/databind/BeanDescription.java b/src/main/java/tools/jackson/databind/BeanDescription.java index 25361112a3..7d549e7394 100644 --- a/src/main/java/tools/jackson/databind/BeanDescription.java +++ b/src/main/java/tools/jackson/databind/BeanDescription.java @@ -326,6 +326,7 @@ public AnnotatedClass getClassInfo() { @Override public BeanDescription get() { if (_beanDesc == null) { +//if (true) throw new Error("Gotcha!"); // To test without caching, uncomment: return _construct(_type, getClassInfo()); From 9531d02f65439e9a91dfcbf66f4af3c81c2ae3fc Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 21 May 2025 15:47:52 -0700 Subject: [PATCH 5/6] Minor addition to test --- .../misc/Reflection4907Jackson3Test.java | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java index 2d065f6446..0b598832b9 100644 --- a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java +++ b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java @@ -7,11 +7,15 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.Arrays; +import java.util.List; + public class Reflection4907Jackson3Test extends DatabindTestUtil { static class SqlDatePojo { public String name; public java.sql.Date date; + public List tags; public SqlDatePojo() { } @@ -32,6 +36,10 @@ public java.sql.Date getDate() { public void setDate(java.sql.Date date) { this.date = date; } + + public List getTags() { + return tags; + } } private final ObjectMapper MAPPER = newJsonMapper(); @@ -39,23 +47,41 @@ public void setDate(java.sql.Date date) { /* @Test public void test4907ReadPojo() throws Exception { -System.err.println(""); +System.err.println(""); SqlDatePojo pojo = MAPPER.readValue(a2q("{'date':'2000-01-01', 'name':'foo'}"), SqlDatePojo.class); -System.err.println(""); +System.err.println(""); assertNotNull(pojo); } @Test public void test4907WritePojo() throws Exception { -System.err.println(""); +System.err.println(""); String json = MAPPER.writeValueAsString(new SqlDatePojo("foobar", java.sql.Date.valueOf("2000-01-01"))); - System.err.println(""); + System.err.println(""); assertNotNull(json); } */ + @Test + public void test4907ReadTags() throws Exception { +System.err.println(""); + List tags = MAPPER.readValue(a2q("['abc', 'def']"), + List.class); +System.err.println(""); + assertNotNull(tags); + } + + @Test + public void test4907WriteTags() throws Exception { +System.err.println(""); + String json = MAPPER.writeValueAsString(Arrays.asList("abc", "def")); + System.err.println(""); + assertNotNull(json); + } + + /* @Test public void test4907ReadDate() throws Exception { System.err.println(""); @@ -72,4 +98,5 @@ public void test4907WriteDate() throws Exception { System.err.println(""); assertNotNull(json); } + */ } From 939701f95ece6c7af3537def2ea5dcf0c98e608a Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 21 May 2025 15:50:15 -0700 Subject: [PATCH 6/6] ... --- .../databind/misc/Reflection4907Jackson3Test.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java index 0b598832b9..4acd1ad5f4 100644 --- a/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java +++ b/src/test/java/tools/jackson/databind/misc/Reflection4907Jackson3Test.java @@ -20,9 +20,10 @@ static class SqlDatePojo { public SqlDatePojo() { } - public SqlDatePojo(String name, java.sql.Date date) { + public SqlDatePojo(String name, java.sql.Date date, String... tags) { this.name = name; this.date = date; + this.tags = Arrays.asList(tags); } public SqlDatePojo(java.sql.Date date) { @@ -44,7 +45,6 @@ public List getTags() { private final ObjectMapper MAPPER = newJsonMapper(); - /* @Test public void test4907ReadPojo() throws Exception { System.err.println(""); @@ -58,11 +58,11 @@ public void test4907ReadPojo() throws Exception { public void test4907WritePojo() throws Exception { System.err.println(""); String json = MAPPER.writeValueAsString(new SqlDatePojo("foobar", - java.sql.Date.valueOf("2000-01-01"))); + java.sql.Date.valueOf("2000-01-01"), "abc", "def")); System.err.println(""); assertNotNull(json); } - */ + /* @Test public void test4907ReadTags() throws Exception { @@ -80,6 +80,7 @@ public void test4907WriteTags() throws Exception { System.err.println(""); assertNotNull(json); } + */ /* @Test