Skip to content

Commit 7e59a33

Browse files
authored
Fix FasterXML#4620: check default Creator before implicitly named (FasterXML#4622)
1 parent ee2da1a commit 7e59a33

File tree

3 files changed

+58
-47
lines changed

3 files changed

+58
-47
lines changed

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -674,11 +674,11 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
674674
creators.hasPropertiesBased());
675675
}
676676

677-
// If no Explicitly annotated creators found, look
677+
// If no Explicitly annotated creators (or Default one) found, look
678678
// for ones with explicitly-named ({@code @JsonProperty}) parameters
679679
if (!creators.hasPropertiesBased()) {
680680
// only discover constructor Creators?
681-
_addCreatorsWithAnnotatedNames(creators, constructors);
681+
_addCreatorsWithAnnotatedNames(creators, constructors, primary);
682682
}
683683

684684
// But if no annotation-based Creators found, find/use Primary Creator
@@ -919,21 +919,40 @@ private boolean _isExplicitlyAnnotatedCreatorPropsBased(PotentialCreator ctor,
919919
}
920920

921921
private void _addCreatorsWithAnnotatedNames(PotentialCreators collector,
922-
List<PotentialCreator> ctors)
922+
List<PotentialCreator> ctors, PotentialCreator defaultCtor)
923923
{
924+
final List<PotentialCreator> found = _findCreatorsWithAnnotatedNames(ctors);
925+
// 16-Jul-2024, tatu: [databind#4620] If Default Creator found, it
926+
// will be used to resolve candidate to use, if any
927+
if (defaultCtor != null) {
928+
if (found.contains(defaultCtor)) {
929+
collector.setPropertiesBased(_config, defaultCtor, "implicit");
930+
return;
931+
}
932+
}
933+
for (PotentialCreator ctor : found) {
934+
collector.setPropertiesBased(_config, ctor, "implicit");
935+
}
936+
}
937+
938+
private List<PotentialCreator> _findCreatorsWithAnnotatedNames(List<PotentialCreator> ctors)
939+
{
940+
List<PotentialCreator> found = null;
924941
Iterator<PotentialCreator> it = ctors.iterator();
925942
while (it.hasNext()) {
926943
PotentialCreator ctor = it.next();
927-
928944
// Ok: existence of explicit (annotated) names infers properties-based:
929945
ctor.introspectParamNames(_config);
930946
if (!ctor.hasExplicitNames()) {
931947
continue;
932948
}
933949
it.remove();
934-
935-
collector.setPropertiesBased(_config, ctor, "implicit");
950+
if (found == null) {
951+
found = new ArrayList<>(4);
952+
}
953+
found.add(ctor);
936954
}
955+
return (found == null) ? Collections.emptyList() : found;
937956
}
938957

939958
private boolean _addImplicitConstructor(PotentialCreators collector,

src/test-jdk17/java/com/fasterxml/jackson/databind/records/RecordCreatorWithAnySetter562Test.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@
1010
import java.util.Map;
1111

1212
import static org.junit.jupiter.api.Assertions.assertEquals;
13-
import static org.junit.jupiter.api.Assertions.fail;
1413

1514
// [databind#562] Allow @JsonAnySetter on Creator constructors
1615
public class RecordCreatorWithAnySetter562Test
1716
extends DatabindTestUtil
1817
{
1918
record RecordWithAnySetterCtor(int id,
20-
Map<String, Integer> additionalProperties) {
19+
Map<String, Integer> additionalProperties) {
2120
@JsonCreator
2221
public RecordWithAnySetterCtor(@JsonProperty("regular") int id,
23-
@JsonAnySetter Map<String, Integer> additionalProperties
22+
@JsonAnySetter Map<String, Integer> additionalProperties
2423
) {
2524
this.id = id;
2625
this.additionalProperties = additionalProperties;
@@ -52,5 +51,4 @@ public void testRecordWithAnySetterCtor() throws Exception
5251
assertEquals(Integer.valueOf(-1), result.additionalProperties.get("extra"));
5352
assertEquals(2, result.additionalProperties.size());
5453
}
55-
5654
}

src/test/java/com/fasterxml/jackson/databind/introspect/DefaultCreatorResolution4620Test.java

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.fasterxml.jackson.databind.introspect;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
3+
import java.util.*;
54

65
import org.junit.jupiter.api.Test;
76

87
import com.fasterxml.jackson.annotation.JsonCreator;
9-
8+
import com.fasterxml.jackson.annotation.JsonProperty;
109
import com.fasterxml.jackson.databind.*;
1110
import com.fasterxml.jackson.databind.cfg.MapperConfig;
1211
import com.fasterxml.jackson.databind.json.JsonMapper;
@@ -19,54 +18,47 @@
1918
// @since 2.18
2019
public class DefaultCreatorResolution4620Test extends DatabindTestUtil
2120
{
22-
static class PrimaryCreatorFindingIntrospector extends ImplicitNameIntrospector
21+
static class POJO4620 {
22+
String value;
23+
24+
public POJO4620(@JsonProperty("int") int i) {
25+
throw new RuntimeException("Should not get called");
26+
}
27+
28+
public POJO4620(@JsonProperty("str") String str, @JsonProperty("int") int v) {
29+
value = str + "/" + v;
30+
}
31+
32+
public POJO4620(@JsonProperty("str") String str,
33+
@JsonProperty("int") int v,
34+
@JsonProperty("long") long l) {
35+
throw new RuntimeException("Should not get called");
36+
}
37+
}
38+
39+
static class PrimaryConstructorFindingIntrospector extends ImplicitNameIntrospector
2340
{
2441
private static final long serialVersionUID = 1L;
2542

2643
private final Class<?>[] _argTypes;
2744

28-
private JsonCreator.Mode _mode;
29-
30-
private final String _factoryName;
31-
32-
public PrimaryCreatorFindingIntrospector(JsonCreator.Mode mode,
33-
Class<?>... argTypes) {
34-
_mode = mode;
35-
_factoryName = null;
45+
public PrimaryConstructorFindingIntrospector(Class<?>... argTypes) {
3646
_argTypes = argTypes;
3747
}
3848

39-
public PrimaryCreatorFindingIntrospector(JsonCreator.Mode mode,
40-
String factoryName) {
41-
_mode = mode;
42-
_factoryName = factoryName;
43-
_argTypes = new Class<?>[0];
44-
}
45-
4649
@Override
4750
public PotentialCreator findDefaultCreator(MapperConfig<?> config,
4851
AnnotatedClass valueClass,
4952
List<PotentialCreator> declaredConstructors,
5053
List<PotentialCreator> declaredFactories)
5154
{
5255
// Apply to all test POJOs here but nothing else
53-
if (!valueClass.getRawType().toString().contains("4584")) {
56+
if (!valueClass.getRawType().toString().contains("4620")) {
5457
return null;
5558
}
5659

57-
if (_factoryName != null) {
58-
for (PotentialCreator ctor : declaredFactories) {
59-
if (ctor.creator().getName().equals(_factoryName)) {
60-
return ctor;
61-
}
62-
}
63-
return null;
64-
}
65-
66-
List<PotentialCreator> combo = new ArrayList<>(declaredConstructors);
67-
combo.addAll(declaredFactories);
6860
final int argCount = _argTypes.length;
69-
for (PotentialCreator ctor : combo) {
61+
for (PotentialCreator ctor : declaredConstructors) {
7062
if (ctor.paramCount() == argCount) {
7163
int i = 0;
7264
for (; i < argCount; ++i) {
@@ -75,7 +67,7 @@ public PotentialCreator findDefaultCreator(MapperConfig<?> config,
7567
}
7668
}
7769
if (i == argCount) {
78-
ctor.overrideMode(_mode);
70+
ctor.overrideMode(JsonCreator.Mode.PROPERTIES);
7971
return ctor;
8072
}
8173
}
@@ -93,7 +85,11 @@ public PotentialCreator findDefaultCreator(MapperConfig<?> config,
9385
@Test
9486
public void testCanonicalConstructor1ArgPropertiesCreator() throws Exception
9587
{
96-
// TODO
88+
// Select the "middle one"
89+
POJO4620 result = readerWith(new PrimaryConstructorFindingIntrospector(
90+
String.class, Integer.TYPE))
91+
.readValue(a2q("{'str':'value', 'int':42}"));
92+
assertEquals("value/42", result.value);
9793
}
9894

9995
/*
@@ -102,11 +98,9 @@ public void testCanonicalConstructor1ArgPropertiesCreator() throws Exception
10298
/**********************************************************************
10399
*/
104100

105-
/*
106101
private ObjectReader readerWith(AnnotationIntrospector intr) {
107-
return mapperWith(intr).readerFor(POJO4584.class);
102+
return mapperWith(intr).readerFor(POJO4620.class);
108103
}
109-
*/
110104

111105
private ObjectMapper mapperWith(AnnotationIntrospector intr) {
112106
return JsonMapper.builder()

0 commit comments

Comments
 (0)