Skip to content

Commit 7d94c2f

Browse files
authored
Fix for #4860, ConstructorDetector with single arg constructor not working since 2.18 (#4861)
1 parent a9b9f91 commit 7d94c2f

File tree

5 files changed

+72
-5
lines changed

5 files changed

+72
-5
lines changed

release-notes/CREDITS-2.x

+5
Original file line numberDiff line numberDiff line change
@@ -1861,3 +1861,8 @@ Jonathan Mesny (@jmesny)
18611861
Stanislav Shcherbakov (@glorrian)
18621862
* Contributed #4844: Fix wrapped array hanlding wrt `null` by `StdDeserializer`
18631863
(2.18.3)
1864+
1865+
Tomáš Poledný (@Saljack)
1866+
* Reported #4860: `ConstructorDetector.USE_PROPERTIES_BASED` does not work with
1867+
multiple constructors since 2.18
1868+
(2.18.3)

release-notes/VERSION-2.x

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Project: jackson-databind
1212
(fix by Joo-Hyuk K)
1313
#4844: Fix wrapped array hanlding wrt `null` by `StdDeserializer`
1414
(fix by Stanislav S)
15+
#4860: `ConstructorDetector.USE_PROPERTIES_BASED` does not work with
16+
multiple constructors since 2.18
17+
(reported by Tomáš P)
18+
(fix by Joo-Hyuk K, @cowtowncoder)
1519

1620
2.18.2 (27-Nov-2024)
1721

src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ private void _addSelectedPropertiesBasedCreator(DeserializationContext ctxt,
548548
if ((name == null) && (injectId == null)) {
549549
ctxt.reportBadTypeDefinition(beanDesc,
550550
"Argument #%d of Creator %s has no property name (and is not Injectable): can not use as property-based Creator",
551-
i, candidate);
551+
i, candidate);
552552
}
553553
}
554554
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,7 @@ protected void _addCreators(Map<String, POJOPropertyBuilder> props)
715715
}
716716

717717
// One more thing: if neither explicit (constructor or factory) nor
718-
// canonical (constructor?), consider implicit Constructor with
719-
// all named.
718+
// canonical (constructor?), consider implicit Constructor with all named.
720719
final ConstructorDetector ctorDetector = _config.getConstructorDetector();
721720
if (!creators.hasPropertiesBasedOrDelegating()
722721
&& !ctorDetector.requireCtorAnnotation()) {
@@ -1013,10 +1012,17 @@ private boolean _addImplicitConstructor(PotentialCreators collector,
10131012
if (ctorDetector.singleArgCreatorDefaultsToDelegating()) {
10141013
return false;
10151014
}
1015+
// 20-Dec-2024, tatu: [databind#4860] Cannot detect as properties-based
1016+
// without implicit name (Injectable was checked earlier)
1017+
String implicitParamName = ctor.implicitNameSimple(0);
1018+
if (implicitParamName == null) {
1019+
return false;
1020+
}
1021+
10161022
// if not, prefer Properties-based if explicit preference OR
10171023
// property with same name with at least one visible accessor
10181024
if (!ctorDetector.singleArgCreatorDefaultsToProperties()) {
1019-
POJOPropertyBuilder prop = props.get(ctor.implicitNameSimple(0));
1025+
POJOPropertyBuilder prop = props.get(implicitParamName);
10201026
if ((prop == null) || !prop.anyVisible() || prop.anyIgnorals()) {
10211027
return false;
10221028
}

src/test/java/com/fasterxml/jackson/databind/deser/creators/ConstructorDetectorTest.java

+53-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.junit.jupiter.api.Test;
44

55
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
67
import com.fasterxml.jackson.annotation.JsonSetter;
78
import com.fasterxml.jackson.annotation.Nulls;
89

@@ -139,9 +140,24 @@ public Boolean field() {
139140
return field;
140141
}
141142
}
142-
143+
144+
// [databind#4860]
145+
@JsonPropertyOrder({ "id", "name "})
146+
static class Foo4860 {
147+
public String id;
148+
public String name;
149+
150+
public Foo4860() { }
151+
152+
public Foo4860(String id) {
153+
// should not be called as of Jackson 2.x
154+
throw new IllegalStateException("Should not auto-detect args-taking constructor");
155+
}
156+
}
157+
143158
private final ObjectMapper MAPPER_PROPS = mapperFor(ConstructorDetector.USE_PROPERTIES_BASED);
144159
private final ObjectMapper MAPPER_DELEGATING = mapperFor(ConstructorDetector.USE_DELEGATING);
160+
private final ObjectMapper MAPPER_DEFAULT = mapperFor(ConstructorDetector.DEFAULT);
145161
private final ObjectMapper MAPPER_EXPLICIT = mapperFor(ConstructorDetector.EXPLICIT_ONLY);
146162

147163
private final ObjectMapper MAPPER_MUST_ANNOTATE = mapperFor(ConstructorDetector.DEFAULT
@@ -379,6 +395,42 @@ void nullHandlingCreator3241() throws Exception {
379395
}
380396
}
381397

398+
// [databind#4860]
399+
@Test
400+
public void testDeserialization4860PropsBased() throws Exception {
401+
_test4680With(MAPPER_PROPS);
402+
}
403+
404+
@Test
405+
public void testDeserialization4860Delegating() throws Exception {
406+
_test4680With(MAPPER_DELEGATING);
407+
}
408+
409+
@Test
410+
public void testDeserialization4860Default() throws Exception {
411+
_test4680With(MAPPER_DEFAULT);
412+
}
413+
414+
@Test
415+
public void testDeserialization4860Explicit() throws Exception {
416+
_test4680With(MAPPER_EXPLICIT);
417+
}
418+
419+
private void _test4680With(ObjectMapper mapper) throws Exception
420+
{
421+
_test4680With(mapper, "{}", a2q("{'id':null,'name':null}"));
422+
_test4680With(mapper, a2q("{'id':'something'}"),
423+
a2q("{'id':'something','name':null}"));
424+
_test4680With(mapper, a2q("{'id':'something','name':'name'}"),
425+
a2q("{'id':'something','name':'name'}"));
426+
}
427+
428+
private void _test4680With(ObjectMapper mapper, String input, String output) throws Exception
429+
{
430+
Foo4860 result = mapper.readValue(input, Foo4860.class);
431+
assertEquals(output, mapper.writeValueAsString(result));
432+
}
433+
382434
/*
383435
/**********************************************************************
384436
/* Helper methods

0 commit comments

Comments
 (0)