Skip to content

Commit 9325008

Browse files
committed
Merge branch '2.18' into 2.19
2 parents 39ac2b6 + 4b6f1c4 commit 9325008

File tree

4 files changed

+142
-3
lines changed

4 files changed

+142
-3
lines changed

release-notes/CREDITS-2.x

+5
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,11 @@ Gustavo Bazan (@gssbzn)
18841884
@ConstructorProperties between 2.17 and 2.18
18851885
(2.18.3)
18861886

1887+
Zhen Lin Low (@zhenlin-pay2)
1888+
* Reported, fixed #4920: Creator properties are ignored on abstract types
1889+
when collecting bean properties, breaking AsExternalTypeDeserializer
1890+
(2.18.3)
1891+
18871892
Liam Feid (@fxshlein)
18881893
* Contributed #1467: Support `@JsonUnwrapped` with `@JsonCreator`
18891894
(2.19.0)

release-notes/VERSION-2.x

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ Project: jackson-databind
8686
(reported by Gustavo B)
8787
#4917: `BigDecimal` deserialization issue when using `@JsonCreator`
8888
(reported by @dbachdev)
89+
#4920: Creator properties are ignored on abstract types when collecting
90+
bean properties, breaking AsExternalTypeDeserializer
91+
(reported, fix contributed by Zhen L-L)
8992
#4922: Failing `@JsonMerge` with a custom Map
9093
(reported by @nlisker)
9194
#4932: Conversion of `MissingNode` throws `JsonProcessingException`

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,9 @@ protected void addBeanProps(DeserializationContext ctxt,
512512
BeanDescription beanDesc, BeanDeserializerBuilder builder)
513513
throws JsonMappingException
514514
{
515-
final boolean isConcrete = !beanDesc.getType().isAbstract();
516-
final SettableBeanProperty[] creatorProps = isConcrete
517-
? builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig())
515+
final ValueInstantiator valueInstantiator = builder.getValueInstantiator();
516+
final SettableBeanProperty[] creatorProps = (valueInstantiator != null)
517+
? valueInstantiator.getFromObjectArguments(ctxt.getConfig())
518518
: null;
519519
final boolean hasCreatorProps = (creatorProps != null);
520520

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package com.fasterxml.jackson.databind.deser.creators;
2+
3+
import java.io.IOException;
4+
5+
import org.junit.jupiter.api.Assertions;
6+
import org.junit.jupiter.api.Test;
7+
8+
import com.fasterxml.jackson.annotation.JsonCreator;
9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
11+
import com.fasterxml.jackson.databind.DatabindContext;
12+
import com.fasterxml.jackson.databind.JavaType;
13+
import com.fasterxml.jackson.databind.ObjectMapper;
14+
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
15+
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
16+
17+
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.newJsonMapper;
18+
19+
/**
20+
* Unit test for [databind#4920]: Creator properties are ignored on abstract types when
21+
* collecting bean properties, breaking
22+
* {@link com.fasterxml.jackson.databind.jsontype.impl.AsExternalTypeDeserializer}.
23+
*/
24+
public class BeanDeserializerFactory4920Test
25+
{
26+
interface TypedData {
27+
@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type", visible = true)
28+
@JsonTypeIdResolver(ValueTypeIdResolver.class)
29+
Value getValue();
30+
31+
String getType();
32+
33+
@JsonCreator
34+
static TypedData immutableOf(@JsonProperty("value") Value value, @JsonProperty("type") String type) {
35+
return new TypedData.Immutable(value, type);
36+
}
37+
38+
final class Immutable implements TypedData {
39+
40+
private final Value value;
41+
private final String type;
42+
43+
public Immutable(Value value, String type) {
44+
this.value = value;
45+
this.type = type;
46+
}
47+
48+
@Override
49+
public Value getValue() {
50+
return value;
51+
}
52+
53+
@Override
54+
public String getType() {
55+
return type;
56+
}
57+
}
58+
59+
final class ValueTypeIdResolver extends TypeIdResolverBase {
60+
@Override
61+
public String idFromValue(Object value) {
62+
throw new UnsupportedOperationException();
63+
}
64+
65+
@Override
66+
public String idFromValueAndType(Object value, Class<?> suggestedType) {
67+
throw new UnsupportedOperationException();
68+
}
69+
70+
@Override
71+
public JsonTypeInfo.Id getMechanism() {
72+
return JsonTypeInfo.Id.CUSTOM;
73+
}
74+
75+
@Override
76+
public JavaType typeFromId(DatabindContext context, String id) throws IOException {
77+
Class<?> type;
78+
try {
79+
type = Class.forName(id);
80+
} catch (ClassNotFoundException e) {
81+
throw new IllegalArgumentException(e);
82+
}
83+
84+
return context.constructType(type);
85+
}
86+
}
87+
}
88+
89+
interface Value {
90+
}
91+
92+
static final class StringValue implements Value {
93+
94+
private final String value;
95+
96+
public StringValue(String value) {
97+
this.value = value;
98+
}
99+
100+
public String getValue() {
101+
return value;
102+
}
103+
}
104+
105+
static final class LongValue implements Value {
106+
107+
private final long value;
108+
109+
public LongValue(long value) {
110+
this.value = value;
111+
}
112+
113+
public long getValue() {
114+
return value;
115+
}
116+
}
117+
118+
@Test
119+
void testDeserializeAbstract() throws Exception {
120+
ObjectMapper objectMapper = newJsonMapper();
121+
122+
//language=JSON
123+
String json = "{ \"value\": \"1234567890\", \"type\": \"" + StringValue.class.getName() + "\" }";
124+
125+
TypedData actual = objectMapper.readValue(json, TypedData.class);
126+
127+
Assertions.assertNotNull(actual);
128+
Assertions.assertInstanceOf(StringValue.class, actual.getValue());
129+
Assertions.assertEquals("1234567890", ((StringValue) actual.getValue()).getValue());
130+
}
131+
}

0 commit comments

Comments
 (0)