Skip to content

Commit c084b8a

Browse files
committed
Fix #3654
1 parent e5a972f commit c084b8a

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Project: jackson-databind
66

77
2.15.0 (not yet released)
88

9+
#3654: Infer `@JsonCreator(mode = Mode.DELEGATING)` from use of `@JsonValue`)
910
#3676: Allow use of `@JsonCreator(mode = Mode.PROPERTIES)` creator for POJOs
1011
with"empty String" coercion
1112
#3680: Timestamp in classes inside jar showing 02/01/1980

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,8 @@ protected void _addImplicitConstructorCreators(DeserializationContext ctxt,
498498
// some single-arg factory methods (String, number) are auto-detected
499499
if (argCount == 1) {
500500
final BeanPropertyDefinition propDef = candidate.propertyDef(0);
501-
final boolean useProps = preferPropsBased || _checkIfCreatorPropertyBased(intr, ctor, propDef);
501+
final boolean useProps = preferPropsBased
502+
|| _checkIfCreatorPropertyBased(beanDesc, intr, ctor, propDef);
502503

503504
if (useProps) {
504505
SettableBeanProperty[] properties = new SettableBeanProperty[1];
@@ -705,7 +706,7 @@ protected void _addImplicitFactoryCreators(DeserializationContext ctxt,
705706
continue; // 2 and more args? Must be explicit, handled earlier
706707
}
707708
BeanPropertyDefinition argDef = candidate.propertyDef(0);
708-
boolean useProps = _checkIfCreatorPropertyBased(intr, factory, argDef);
709+
boolean useProps = _checkIfCreatorPropertyBased(beanDesc, intr, factory, argDef);
709710
if (!useProps) { // not property based but delegating
710711
/*boolean added=*/ _handleSingleArgumentCreator(creators,
711712
factory, false, vchecker.isCreatorVisible(factory));
@@ -972,12 +973,16 @@ protected void _addExplicitAnyCreator(DeserializationContext ctxt,
972973
if (!useProps && (paramDef != null)) {
973974
// One more thing: if implicit name matches property with a getter
974975
// or field, we'll consider it property-based as well
975-
976-
// 25-May-2018, tatu: as per [databind#2051], looks like we have to get
977-
// not implicit name, but name with possible strategy-based-rename
976+
977+
// 01-Dec-2022, tatu: [databind#3654] Consider `@JsonValue` to strongly
978+
// hint at delegation-based
979+
if (beanDesc.findJsonValueAccessor() == null) {
980+
// 25-May-2018, tatu: as per [databind#2051], looks like we have to get
981+
// not implicit name, but name with possible strategy-based-rename
978982
// paramName = candidate.findImplicitParamName(0);
979-
paramName = candidate.paramName(0);
980-
useProps = (paramName != null) && paramDef.couldSerialize();
983+
paramName = candidate.paramName(0);
984+
useProps = (paramName != null) && paramDef.couldSerialize();
985+
}
981986
}
982987
}
983988
}
@@ -1000,14 +1005,21 @@ protected void _addExplicitAnyCreator(DeserializationContext ctxt,
10001005
}
10011006
}
10021007

1003-
private boolean _checkIfCreatorPropertyBased(AnnotationIntrospector intr,
1008+
private boolean _checkIfCreatorPropertyBased(BeanDescription beanDesc,
1009+
AnnotationIntrospector intr,
10041010
AnnotatedWithParams creator, BeanPropertyDefinition propDef)
10051011
{
10061012
// If explicit name, or inject id, property-based
10071013
if (((propDef != null) && propDef.isExplicitlyNamed())
10081014
|| (intr.findInjectableValue(creator.getParameter(0)) != null)) {
10091015
return true;
10101016
}
1017+
// 01-Dec-2022, tatu: [databind#3654] Consider `@JsonValue` to strongly
1018+
// hint at delegation-based
1019+
if (beanDesc.findJsonValueAccessor() != null) {
1020+
return false;
1021+
}
1022+
10111023
if (propDef != null) {
10121024
// One more thing: if implicit name matches property with a getter
10131025
// or field, we'll consider it property-based as well

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.fasterxml.jackson.databind.deser.creators;
22

3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonValue;
35
import com.fasterxml.jackson.databind.*;
46
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
57
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
@@ -45,6 +47,21 @@ public Bean2932(/*@com.fasterxml.jackson.annotation.JsonProperty("paramName0")*/
4547
}
4648
}
4749

50+
// [databind#3654]: infer "DELEGATING" style from `@JsonValue`
51+
static class XY3654 {
52+
public int paramName0; // has to be public to misdirect
53+
54+
@JsonCreator
55+
public XY3654(int paramName0) {
56+
this.paramName0 = paramName0;
57+
}
58+
59+
@JsonValue
60+
public int serializedAs() {
61+
return paramName0;
62+
}
63+
}
64+
4865
/*
4966
/**********************************************************
5067
/* Test methods
@@ -72,4 +89,15 @@ public void testJsonCreatorWithOtherAnnotations() throws Exception
7289
assertEquals(1, bean._a);
7390
assertEquals(2, bean._b);
7491
}
92+
93+
// [databind#3654]
94+
public void testDelegatingInferFromJsonValue() throws Exception
95+
{
96+
// First verify serialization via `@JsonValue`
97+
assertEquals("123", MAPPER.writeValueAsString(new XY3654(123)));
98+
99+
// And then deser, should infer despite existence of "matching" property
100+
XY3654 result = MAPPER.readValue("345", XY3654.class);
101+
assertEquals(345, result.paramName0);
102+
}
75103
}

0 commit comments

Comments
 (0)