Skip to content

Commit e33f7c4

Browse files
authored
Fix #4835: simplify Record detection, metadata access (#4839)
1 parent 7f30c9b commit e33f7c4

File tree

7 files changed

+77
-200
lines changed

7 files changed

+77
-200
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Versions: 3.x (for earlier see VERSION-2.x)
8080
(contributed by Joo-Hyuk K)
8181
#4818: Rename `AnnotationIntrospector.findDefaultCreator()` as `findPreferredCreator()`
8282
#4820: Change JDK baseline for Jackson 3.0 from Java 8 to Java 17
83+
#4835: Remove dynamic work-arounds wrt accessing `Record` definition
8384
#4840: Increase minimum Android SDK required to 34 for Jackson 3.0
8485
- Remove `MappingJsonFactory`
8586
- Add context parameter for `TypeSerializer` contextualization (`forProperty()`)

src/main/java/tools/jackson/databind/introspect/DefaultAccessorNamingStrategy.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import tools.jackson.databind.MapperFeature;
1313
import tools.jackson.databind.annotation.JsonPOJOBuilder;
1414
import tools.jackson.databind.cfg.MapperConfig;
15-
import tools.jackson.databind.jdk14.JDK14Util;
15+
import tools.jackson.databind.util.RecordUtil;
1616

1717
/**
1818
* Default {@link AccessorNamingStrategy} used by Jackson: to be used either as-is,
@@ -502,7 +502,7 @@ public RecordNaming(MapperConfig<?> config, AnnotatedClass forClass) {
502502
// trickier: regular fields are ok (handled differently), but should
503503
// we also allow getter discovery? For now let's do so
504504
"get", "is", null);
505-
String[] recordFieldNames = JDK14Util.getRecordFieldNames(forClass.getRawType());
505+
String[] recordFieldNames = RecordUtil.getRecordFieldNames(forClass.getRawType());
506506
// 01-May-2022, tatu: Due to [databind#3417] may return null when no info available
507507
_fieldNames = recordFieldNames == null ?
508508
Collections.emptySet() :

src/main/java/tools/jackson/databind/introspect/POJOPropertiesCollector.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import tools.jackson.databind.cfg.HandlerInstantiator;
1313
import tools.jackson.databind.cfg.MapperConfig;
1414
import tools.jackson.databind.deser.impl.UnwrappedPropertyHandler;
15-
import tools.jackson.databind.jdk14.JDK14Util;
1615
import tools.jackson.databind.util.ClassUtil;
16+
import tools.jackson.databind.util.RecordUtil;
1717

1818
/**
1919
* Helper class used for aggregating information about all possible
@@ -605,7 +605,7 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
605605
// Needs to be done early to get implicit names populated
606606
final PotentialCreator primaryCreator;
607607
if (_isRecordType) {
608-
primaryCreator = JDK14Util.findCanonicalRecordConstructor(_config, _classDef, constructors);
608+
primaryCreator = RecordUtil.findCanonicalRecordConstructor(_config, _classDef, constructors);
609609
} else {
610610
// 02-Nov-2024, tatu: Alas, naming here is confusing: method properly
611611
// should have been "findPrimaryCreator()" so as not to confused with

src/main/java/tools/jackson/databind/jdk14/JDK14Util.java

-187
This file was deleted.

src/main/java/tools/jackson/databind/jdk14/package-info.java

-6
This file was deleted.

src/main/java/tools/jackson/databind/util/ClassUtil.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,10 @@ public static boolean isBogusClass(Class<?> cls) {
219219
}
220220

221221
/**
222-
* Helper method for detecting Java14-added new {@code Record} types
222+
* Helper method for detecting Java14-added {@code Record} types
223223
*/
224224
public static boolean isRecordType(Class<?> cls) {
225-
Class<?> parent = cls.getSuperclass();
226-
return (parent != null) && "java.lang.Record".equals(parent.getName());
225+
return cls.isRecord();
227226
}
228227

229228
public static boolean isObjectOrPrimitive(Class<?> cls) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package tools.jackson.databind.util;
2+
3+
import java.lang.reflect.RecordComponent;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
7+
import tools.jackson.databind.PropertyName;
8+
import tools.jackson.databind.cfg.MapperConfig;
9+
import tools.jackson.databind.introspect.AnnotatedClass;
10+
import tools.jackson.databind.introspect.AnnotatedConstructor;
11+
import tools.jackson.databind.introspect.PotentialCreator;
12+
13+
/**
14+
* Helper class for finding so-called canonical constructor
15+
* of Record types.
16+
*/
17+
public class RecordUtil
18+
{
19+
public static String[] getRecordFieldNames(Class<?> recordType) {
20+
final RecordComponent[] components = recordType.getRecordComponents();
21+
if (components == null) {
22+
// not a record, or no reflective access on native image
23+
return null;
24+
}
25+
return Arrays.stream(components).map(RecordComponent::getName).toArray(String[]::new);
26+
}
27+
28+
public static PotentialCreator findCanonicalRecordConstructor(MapperConfig<?> config,
29+
AnnotatedClass recordClass,
30+
List<PotentialCreator> constructors)
31+
{
32+
final RecordComponent[] components = recordClass.getRawType().getRecordComponents();
33+
if (components == null) {
34+
// not a record, or no reflective access on native image
35+
return null;
36+
}
37+
38+
// And then locate the canonical constructor
39+
final int argCount = components.length;
40+
// One special case: zero-arg constructor not included in candidate List
41+
if (argCount == 0) {
42+
// Bit hacky but has to do: create new PotentialCreator let caller deal
43+
AnnotatedConstructor defCtor = recordClass.getDefaultConstructor();
44+
if (defCtor != null) {
45+
return new PotentialCreator(defCtor, null);
46+
}
47+
}
48+
49+
main_loop:
50+
for (PotentialCreator ctor : constructors) {
51+
if (ctor.paramCount() != argCount) {
52+
continue;
53+
}
54+
for (int i = 0; i < argCount; ++i) {
55+
if (!ctor.creator().getRawParameterType(i).equals(components[i].getType())) {
56+
continue main_loop;
57+
}
58+
}
59+
// Found it! One more thing; get implicit Record field names:
60+
final PropertyName[] implicits = new PropertyName[argCount];
61+
for (int i = 0; i < argCount; ++i) {
62+
implicits[i] = PropertyName.construct(components[i].getName());
63+
}
64+
return ctor.introspectParamNames(config, implicits);
65+
}
66+
67+
throw new IllegalArgumentException("Failed to find the canonical Record constructor of type "
68+
+ClassUtil.getTypeDescription(recordClass.getType()));
69+
}
70+
}

0 commit comments

Comments
 (0)