Skip to content

Commit 2d44ab0

Browse files
committed
Merge branch '2.18' into 2.19
2 parents 309c428 + a09c137 commit 2d44ab0

File tree

5 files changed

+114
-34
lines changed

5 files changed

+114
-34
lines changed

src/main/java/com/fasterxml/jackson/databind/AnnotationIntrospector.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,14 +1399,14 @@ public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated
13991399

14001400
/**
14011401
* Method called to check if introspector can find a Creator it considers
1402-
* the "Default Creator": Creator to use as the primary, when no Creator has
1402+
* the "Primary Creator": Creator to use as the primary one, when no Creator has
14031403
* explicit annotation ({@link #findCreatorAnnotation} returns {@code null}).
14041404
* Examples of default creators include the canonical constructor defined by
14051405
* Java Records; "Data" classes by frameworks
14061406
* like Lombok and JVM languages like Kotlin and Scala (case classes) also have
14071407
* similar concepts.
14081408
* If introspector can determine that one of given {@link PotentialCreator}s should
1409-
* be considered the default, it should return it; if not, should return {@code null}.
1409+
* be considered the primary, it should return it; if not, should return {@code null}.
14101410
* Note that core databind functionality may call this method even in the presence of
14111411
* explicitly annotated creators; and may or may not use Creator returned depending
14121412
* on other criteria.
@@ -1416,6 +1416,11 @@ public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated
14161416
*<p>
14171417
* NOTE: method is NOT called for Java Record types; selection of the canonical constructor
14181418
* as the Primary creator is handled directly by {@link POJOPropertiesCollector}
1419+
*<p>
1420+
* NOTE: naming of this method is unfortunately inconsistent in that "default Creator"
1421+
* has other meanings than "primary Creator" -- in other places Jackson code
1422+
* refers to no-arguments Constructors as "default Creators". So this method
1423+
* ought to have been named {@code findPrimaryCreator()}.
14191424
*
14201425
* @param config Configuration settings in effect (for deserialization)
14211426
* @param valueClass Class being instantiated; defines Creators passed

src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,7 @@ public ValueInstantiator constructValueInstantiator(DeserializationContext ctxt)
122122
* it with data. Default creator is only used if no other creators are
123123
* indicated.
124124
*
125-
* @param creator
126-
* Creator method; no-arguments constructor or static factory
127-
* method.
125+
* @param creator Creator method; no-arguments constructor or factory method.
128126
*/
129127
public void setDefaultCreator(AnnotatedWithParams creator) {
130128
_creators[C_DEFAULT] = _fixAccess(creator);

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationIntrospectorPair.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,13 +739,13 @@ public PotentialCreator findDefaultCreator(MapperConfig<?> config,
739739
AnnotatedClass valueClass,
740740
List<PotentialCreator> declaredConstructors,
741741
List<PotentialCreator> declaredFactories) {
742-
PotentialCreator defCtor = _primary.findDefaultCreator(config,
742+
PotentialCreator primaryCtor = _primary.findDefaultCreator(config,
743743
valueClass, declaredConstructors, declaredFactories);
744-
if (defCtor == null) {
745-
defCtor = _secondary.findDefaultCreator(config,
744+
if (primaryCtor == null) {
745+
primaryCtor = _secondary.findDefaultCreator(config,
746746
valueClass, declaredConstructors, declaredFactories);
747747
}
748-
return defCtor;
748+
return primaryCtor;
749749
}
750750

751751
/*

src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -656,22 +656,25 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
656656
List<PotentialCreator> constructors = _collectCreators(_classDef.getConstructors());
657657
List<PotentialCreator> factories = _collectCreators(_classDef.getFactoryMethods());
658658

659-
// Then find what is the Default Constructor (if one exists for type):
659+
// Then find what is the Primary Constructor (if one exists for type):
660660
// for Java Records and potentially other types too ("data classes"):
661661
// Needs to be done early to get implicit names populated
662-
final PotentialCreator defaultCreator;
662+
final PotentialCreator primaryCreator;
663663
if (_isRecordType) {
664-
defaultCreator = JDK14Util.findCanonicalRecordConstructor(_config, _classDef, constructors);
664+
primaryCreator = JDK14Util.findCanonicalRecordConstructor(_config, _classDef, constructors);
665665
} else {
666-
defaultCreator = _annotationIntrospector.findDefaultCreator(_config, _classDef,
666+
// 02-Nov-2024, tatu: Alas, naming here is confusing: method properly
667+
// should have been "findPrimaryCreator()" so as not to confused with
668+
// 0-args default Creators...
669+
primaryCreator = _annotationIntrospector.findDefaultCreator(_config, _classDef,
667670
constructors, factories);
668671
}
669672
// Next: remove creators marked as explicitly disabled
670673
_removeDisabledCreators(constructors);
671674
_removeDisabledCreators(factories);
672675

673676
// And then remove non-annotated static methods that do not look like factories
674-
_removeNonFactoryStaticMethods(factories, defaultCreator);
677+
_removeNonFactoryStaticMethods(factories, primaryCreator);
675678

676679
// and use annotations to find explicitly chosen Creators
677680
if (_useAnnotations) { // can't have explicit ones without Annotation introspection
@@ -682,30 +685,30 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
682685
creators.hasPropertiesBased());
683686
}
684687

685-
// If no Explicitly annotated creators (or Default one) found, look
688+
// If no Explicitly annotated creators (or Primary one) found, look
686689
// for ones with explicitly-named ({@code @JsonProperty}) parameters
687690
if (!creators.hasPropertiesBased()) {
688691
// only discover constructor Creators?
689-
_addCreatorsWithAnnotatedNames(creators, constructors, defaultCreator);
692+
_addCreatorsWithAnnotatedNames(creators, constructors, primaryCreator);
690693
}
691694

692-
// But if no annotation-based Creators found, find/use Default Creator
695+
// But if no annotation-based Creators found, find/use Primary Creator
693696
// detected earlier, if any
694-
if (defaultCreator != null) {
697+
if (primaryCreator != null) {
695698
// ... but only process if still included as a candidate
696-
if (constructors.remove(defaultCreator)
697-
|| factories.remove(defaultCreator)) {
699+
if (constructors.remove(primaryCreator)
700+
|| factories.remove(primaryCreator)) {
698701
// and then consider delegating- vs properties-based
699-
if (_isDelegatingConstructor(defaultCreator)) {
702+
if (_isDelegatingConstructor(primaryCreator)) {
700703
// 08-Oct-2024, tatu: [databind#4724] Only add if no explicit
701704
// candidates added
702705
if (!creators.hasDelegating()) {
703706
// ... not technically explicit but simpler this way
704-
creators.addExplicitDelegating(defaultCreator);
707+
creators.addExplicitDelegating(primaryCreator);
705708
}
706-
} else { // default creator is properties-based
709+
} else { // primary creator is properties-based
707710
if (!creators.hasPropertiesBased()) {
708-
creators.setPropertiesBased(_config, defaultCreator, "Primary");
711+
creators.setPropertiesBased(_config, primaryCreator, "Primary");
709712
}
710713
}
711714
}
@@ -717,7 +720,7 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
717720
final ConstructorDetector ctorDetector = _config.getConstructorDetector();
718721
if (!creators.hasPropertiesBasedOrDelegating()
719722
&& !ctorDetector.requireCtorAnnotation()) {
720-
// But only if no default constructor available OR if we are configured
723+
// But only if no Default (0-args) constructor available OR if we are configured
721724
// to prefer properties-based Creators
722725
if ((_classDef.getDefaultConstructor() == null)
723726
|| ctorDetector.singleArgCreatorDefaultsToProperties()) {
@@ -753,7 +756,7 @@ private boolean _isDelegatingConstructor(PotentialCreator ctor)
753756
case DISABLED:
754757
case PROPERTIES:
755758
return false;
756-
default: // case DEFAULT:
759+
default:
757760
}
758761

759762
// Only consider single-arg case, for now
@@ -804,7 +807,7 @@ private void _removeNonVisibleCreators(List<PotentialCreator> ctors)
804807
}
805808

806809
private void _removeNonFactoryStaticMethods(List<PotentialCreator> ctors,
807-
PotentialCreator defaultCreator)
810+
PotentialCreator primaryCreator)
808811
{
809812
final Class<?> rawType = _type.getRawClass();
810813
Iterator<PotentialCreator> it = ctors.iterator();
@@ -814,8 +817,8 @@ private void _removeNonFactoryStaticMethods(List<PotentialCreator> ctors,
814817
if (ctor.isAnnotated()) {
815818
continue;
816819
}
817-
// Do not trim canonical either
818-
if (defaultCreator == ctor) {
820+
// Do not trim Primary creator either
821+
if (primaryCreator == ctor) {
819822
continue;
820823
}
821824
// Copied from `BasicBeanDescription.isFactoryMethod()`
@@ -932,14 +935,14 @@ private boolean _isExplicitlyAnnotatedCreatorPropsBased(PotentialCreator ctor,
932935
}
933936

934937
private void _addCreatorsWithAnnotatedNames(PotentialCreators collector,
935-
List<PotentialCreator> ctors, PotentialCreator defaultCtor)
938+
List<PotentialCreator> ctors, PotentialCreator primaryCtor)
936939
{
937940
final List<PotentialCreator> found = _findCreatorsWithAnnotatedNames(ctors);
938-
// 16-Jul-2024, tatu: [databind#4620] If Default Creator found, it
941+
// 16-Jul-2024, tatu: [databind#4620] If Primary Creator found, it
939942
// will be used to resolve candidate to use, if any
940-
if (defaultCtor != null) {
941-
if (found.contains(defaultCtor)) {
942-
collector.setPropertiesBased(_config, defaultCtor, "implicit");
943+
if (primaryCtor != null) {
944+
if (found.contains(primaryCtor)) {
945+
collector.setPropertiesBased(_config, primaryCtor, "implicit");
943946
return;
944947
}
945948
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.fasterxml.jackson.databind.tofix;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
import com.fasterxml.jackson.annotation.JsonCreator;
7+
import com.fasterxml.jackson.databind.*;
8+
import com.fasterxml.jackson.databind.deser.*;
9+
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
10+
import com.fasterxml.jackson.databind.json.JsonMapper;
11+
import com.fasterxml.jackson.databind.module.SimpleModule;
12+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
13+
14+
public class AaaCreator4777Test extends DatabindTestUtil
15+
{
16+
static class Foo {
17+
String whoMadeWho;
18+
19+
protected Foo() { whoMadeWho = "creator"; }
20+
21+
@JsonCreator
22+
static Foo create() {
23+
Foo foo = new Foo();
24+
foo.whoMadeWho = "factory";
25+
return foo;
26+
}
27+
}
28+
29+
@SuppressWarnings("serial")
30+
static class Instantiator extends StdValueInstantiator {
31+
public Instantiator(StdValueInstantiator src) {
32+
super(src);
33+
}
34+
}
35+
36+
static class Instantiators implements ValueInstantiators {
37+
Instantiator last = null;
38+
39+
@Override
40+
public ValueInstantiator findValueInstantiator(
41+
DeserializationConfig config,
42+
BeanDescription beanDesc,
43+
ValueInstantiator defaultInstantiator
44+
) {
45+
if (defaultInstantiator instanceof StdValueInstantiator) {
46+
Instantiator instantiator = new Instantiator((StdValueInstantiator) defaultInstantiator);
47+
last = instantiator;
48+
return instantiator;
49+
} else {
50+
return defaultInstantiator;
51+
}
52+
}
53+
}
54+
55+
@Test
56+
public void test() throws Exception {
57+
Instantiators i = new Instantiators();
58+
59+
SimpleModule sm = new SimpleModule() {
60+
@Override
61+
public void setupModule(SetupContext context) {
62+
super.setupModule(context);
63+
context.addValueInstantiators(i);
64+
}
65+
};
66+
ObjectMapper mapper = JsonMapper.builder().addModule(sm).build();
67+
68+
Foo result = mapper.readValue("{}", Foo.class);
69+
70+
Assertions.assertEquals("factory", result.whoMadeWho);
71+
72+
Assertions.assertNull(i.last.getWithArgsCreator());
73+
}
74+
}

0 commit comments

Comments
 (0)