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 7272de05d1..ec7e0bae12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java @@ -86,6 +86,15 @@ public final class AnnotatedClass */ protected final boolean _collectAnnotations; + /** + * Flag that indicates whether member (Field, Method, Constructor} + * detection should occur: starting with 2.19 is disabled for core JDK + * types {@link ClassUtil#isJDKCoreClass(Class)}). + * + * @since 2.20 + */ + protected final boolean _collectMembers; + /* /********************************************************** /* Gathered information @@ -152,6 +161,19 @@ public final class AnnotatedClass _mixInResolver = mir; _typeFactory = tf; _collectAnnotations = collectAnnotations; + // But need to collect for some JDK types: + // + // - Throwables + _collectMembers = (type != null) + && (!ClassUtil.isJDKCoreClass(rawType) + || type.hasRawClass(Optional.class) + || type.hasRawClass(StackTraceElement.class) + || Throwable.class.isAssignableFrom(rawType) + || type.hasRawClass(Thread.class) + || type.hasRawClass(ThreadGroup.class) + ); + +System.out.println(" AnnotatedClass("+_type+"), coll anno? "+collectAnnotations+" coll mem? "+_collectMembers); } /** @@ -171,6 +193,7 @@ public final class AnnotatedClass _mixInResolver = null; _typeFactory = null; _collectAnnotations = false; + _collectMembers = false; } /** @@ -327,9 +350,12 @@ private final List _fields() { List f = _fields; if (f == null) { // 09-Jun-2017, tatu: _type only null for primordial, placeholder array types. - if (_type == null) { + // 26-Apr-2025, tatu: [databind#4907] Less introspection, skip for core JDK types + if (_type == null || !_collectMembers) { +System.out.println("SKIP Collecting _fields() for "+_type); f = Collections.emptyList(); } else { +System.out.println("Collecting _fields() for "+_type); f = AnnotatedFieldCollector.collectFields(_annotationIntrospector, this, _mixInResolver, _typeFactory, _type, _collectAnnotations); } @@ -343,9 +369,11 @@ private final AnnotatedMethodMap _methods() { if (m == null) { // 09-Jun-2017, tatu: _type only null for primordial, placeholder array types. // NOTE: would be great to have light-weight shareable maps; no such impl exists for now - if (_type == null) { + if (_type == null) { // || !_collectMembers) { +System.out.println("SKIP Collecting _methods() for: "+_type); m = new AnnotatedMethodMap(); } else { +System.out.println("Collecting _methods() for "+_type); m = AnnotatedMethodCollector.collectMethods(_annotationIntrospector, this, _mixInResolver, _typeFactory, @@ -359,9 +387,12 @@ private final AnnotatedMethodMap _methods() { private final Creators _creators() { Creators c = _creators; if (c == null) { - if (_type == null) { + // 26-Apr-2025, tatu: [databind#4907] Less introspection, skip for core JDK types + if (_type == null || !_collectMembers) { +System.out.println("SKIP Collecting _creators() for: "+_type); c = NO_CREATORS; } else { +System.out.println("Collecting _creators() for "+_type); c = AnnotatedCreatorCollector.collectCreators(_annotationIntrospector, _typeFactory, this, _type, _primaryMixIn, _collectAnnotations); diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClassResolver.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClassResolver.java index 55acc9f209..8ee68f7a50 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClassResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClassResolver.java @@ -132,6 +132,8 @@ static AnnotatedClass createArrayType(MapperConfig config, Class raw) { } AnnotatedClass resolveFully() { +System.out.println(" AnnotatedClassResolver.resolveFully() for "+_type); + List superTypes = new ArrayList<>(8); if (!_type.hasRawClass(Object.class)) { if (_type.isInterface()) { diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java index 7927c39909..450dc54529 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java @@ -83,6 +83,7 @@ public BasicBeanDescription forSerialization(SerializationConfig config, // structured types as well desc = _findStdJdkCollectionDesc(config, type); if (desc == null) { +System.out.println("BasicBeanDescription.forSerialization() for "+type); desc = BasicBeanDescription.forSerialization(collectProperties(config, type, r, true)); } @@ -101,6 +102,7 @@ public BasicBeanDescription forDeserialization(DeserializationConfig config, // structured types as well desc = _findStdJdkCollectionDesc(config, type); if (desc == null) { +System.out.println("BasicBeanDescription.forDeserialization() for "+type); desc = BasicBeanDescription.forDeserialization(collectProperties(config, type, r, false)); } @@ -127,6 +129,7 @@ public BasicBeanDescription forCreation(DeserializationConfig config, // structured types as well desc = _findStdJdkCollectionDesc(config, type); if (desc == null) { +System.out.println("BasicBeanDescription.forCreation() for "+type); desc = BasicBeanDescription.forDeserialization( collectProperties(config, type, r, false)); } @@ -170,6 +173,7 @@ public BasicBeanDescription forDirectClassAnnotations(MapperConfig config, protected POJOPropertiesCollector collectProperties(MapperConfig config, JavaType type, MixInResolver r, boolean forSerialization) { +System.out.println(" collectProperties() for "+type); final AnnotatedClass classDef = _resolveAnnotatedClass(config, type, r); final AccessorNamingStrategy accNaming = type.isRecordType() ? config.getAccessorNaming().forRecord(config, classDef) diff --git a/src/test/java/com/fasterxml/jackson/databind/misc/Reflection4907Test.java b/src/test/java/com/fasterxml/jackson/databind/misc/Reflection4907Test.java new file mode 100644 index 0000000000..fd690b5884 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/misc/Reflection4907Test.java @@ -0,0 +1,58 @@ +package com.fasterxml.jackson.databind.misc; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.testutil.DatabindTestUtil; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class Reflection4907Test 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); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java index c41228d5f5..057c7621e0 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/JDKTypeSerializationTest.java @@ -241,8 +241,8 @@ public void testNonStandardProperties() throws Exception public void testThreadSerialization() throws Exception { final Thread input = Thread.currentThread(); -// String json = MAPPER.writerWithDefaultPrettyPrinter() -// .writeValueAsString(input); +// System.err.println("Thread -> "+MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(input)); + Map asMap = MAPPER.convertValue(input, Map.class); // System.err.println("PROPS -> "+asMap.keySet());