Skip to content

Commit b283aad

Browse files
committed
Fix #2668
1 parent 7752ea7 commit b283aad

File tree

9 files changed

+93
-41
lines changed

9 files changed

+93
-41
lines changed

release-notes/VERSION-2.x

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ Project: jackson-databind
5252
#2657: Allow serialization of `Properties` with non-String values
5353
#2663: Add new factory method for creating custom `EnumValues` to pass to `EnumDeserializer
5454
(requested by Rafal K)
55+
#2668: `IllegalArgumentException` thrown for mismatched subclass deserialization
56+
(reported by nbruno@github)
5557
- Add `SerializerProvider.findContentValueSerializer()` methods
5658

5759
2.10.4 (not yet released)

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ public final TypeFactory getTypeFactory() {
253253
}
254254

255255
@Override // since 2.11
256-
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
256+
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass)
257+
throws IllegalArgumentException
258+
{
257259
if (baseType.hasRawClass(subclass)) {
258260
return baseType;
259261
}

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ public final TypeFactory getTypeFactory() {
334334
}
335335

336336
@Override // since 2.11
337-
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
337+
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass)
338+
throws IllegalArgumentException
339+
{
338340
if (baseType.hasRawClass(subclass)) {
339341
return baseType;
340342
}

src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
import java.util.concurrent.ConcurrentHashMap;
66

77
import com.fasterxml.jackson.annotation.JsonTypeInfo;
8+
89
import com.fasterxml.jackson.core.*;
9-
import com.fasterxml.jackson.databind.BeanProperty;
10-
import com.fasterxml.jackson.databind.DeserializationContext;
11-
import com.fasterxml.jackson.databind.DeserializationFeature;
12-
import com.fasterxml.jackson.databind.JavaType;
13-
import com.fasterxml.jackson.databind.JsonDeserializer;
10+
11+
import com.fasterxml.jackson.databind.*;
1412
import com.fasterxml.jackson.databind.deser.std.NullifyingDeserializer;
1513
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
1614
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
@@ -188,7 +186,13 @@ protected final JsonDeserializer<Object> _findDeserializer(DeserializationContex
188186
// Whether this is sufficient to avoid problems remains to be seen, but for
189187
// now it should improve things.
190188
if (!type.hasGenericTypes()) {
191-
type = ctxt.getTypeFactory().constructSpecializedType(_baseType, type.getRawClass());
189+
try { // [databind#2668]: Should not expose generic RTEs
190+
type = ctxt.constructSpecializedType(_baseType, type.getRawClass());
191+
} catch (IllegalArgumentException e) {
192+
// 29-Mar-2020, tatu: I hope this is not misleading for other cases, but
193+
// for [databind#2668] seems reasonable
194+
throw ctxt.invalidTypeIdException(_baseType, typeId, e.getMessage());
195+
}
192196
}
193197
}
194198
deser = ctxt.findContextualValueDeserializer(type, _property);

src/main/java/com/fasterxml/jackson/databind/module/SimpleAbstractTypeResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class SimpleAbstractTypeResolver
3030
extends AbstractTypeResolver
3131
implements java.io.Serializable
3232
{
33-
private static final long serialVersionUID = 8635483102371490919L;
33+
private static final long serialVersionUID = 1L;
3434

3535
/**
3636
* Mappings from super types to subtypes

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,9 @@ protected Class<?> _findPrimitive(String className)
366366
* that is, will use "strict" compatibility checking, usually used for
367367
* deserialization purposes (but often not for serialization).
368368
*/
369-
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
369+
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass)
370+
throws IllegalArgumentException
371+
{
370372
return constructSpecializedType(baseType, subclass, false);
371373
}
372374

@@ -389,6 +391,7 @@ public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
389391
*/
390392
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass,
391393
boolean relaxedCompatibilityCheck)
394+
throws IllegalArgumentException
392395
{
393396
// simple optimization to avoid costly introspection if type-erased type does NOT differ
394397
final Class<?> rawBase = baseType.getRawClass();
@@ -404,8 +407,9 @@ public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass,
404407
break;
405408
}
406409
if (!rawBase.isAssignableFrom(subclass)) {
407-
throw new IllegalArgumentException(String.format(
408-
"Class %s not subtype of %s", subclass.getName(), baseType));
410+
throw new IllegalArgumentException(String.format("Class %s not subtype of %s",
411+
ClassUtil.nameOf(subclass), ClassUtil.getTypeDescription(baseType)
412+
));
409413
}
410414
// A few special cases where we can simplify handling:
411415

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.fasterxml.jackson.databind.jsontype;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
5+
6+
import com.fasterxml.jackson.databind.*;
7+
8+
public class PolymorphicDeserErrorHandlingTest extends BaseMapTest
9+
{
10+
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY,
11+
property = "clazz")
12+
abstract static class BaseForUnknownClass {
13+
}
14+
15+
static class BaseUnknownWrapper {
16+
public BaseForUnknownClass value;
17+
}
18+
19+
// [databind#2668]
20+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
21+
@JsonSubTypes({
22+
@JsonSubTypes.Type(value = Child1.class, name = "child1"),
23+
@JsonSubTypes.Type(value = Child2.class, name = "child2")
24+
})
25+
static class Parent2668 {
26+
}
27+
28+
static class Child1 extends Parent2668 {
29+
public String bar;
30+
}
31+
32+
static class Child2 extends Parent2668 {
33+
public String baz;
34+
}
35+
36+
/*
37+
/**********************************************************************
38+
/* Test methods
39+
/**********************************************************************
40+
*/
41+
42+
private final ObjectMapper MAPPER = newJsonMapper();
43+
44+
public void testUnknownClassAsSubtype() throws Exception
45+
{
46+
ObjectReader reader = MAPPER.readerFor(BaseUnknownWrapper.class)
47+
.without(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
48+
BaseUnknownWrapper w = reader.readValue(aposToQuotes
49+
("{'value':{'clazz':'com.foobar.Nothing'}}'"));
50+
assertNotNull(w);
51+
}
52+
53+
// [databind#2668]
54+
public void testSubType2668() throws Exception
55+
{
56+
String json = "{\"type\": \"child2\", \"baz\":\"1\"}"; // JSON for Child2
57+
58+
try {
59+
/*Child1 c =*/ MAPPER.readValue(json, Child1.class); // Deserializing into Child1
60+
fail("Should not pass");
61+
} catch (JsonMappingException e) {
62+
verifyException(e, "not subtype of");
63+
}
64+
}
65+
}

src/test/java/com/fasterxml/jackson/databind/jsontype/TestAbstractContainers.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ static class ListWrapper {
4444
public interface IDataValueList extends List<String> { }
4545

4646
static class DataValueList extends LinkedList<String> implements IDataValueList { }
47-
47+
4848
/*
4949
/**********************************************************
5050
/* Test methods
5151
/**********************************************************
5252
*/
5353

54-
private final ObjectMapper MAPPER = new ObjectMapper();
54+
private final ObjectMapper MAPPER = newJsonMapper();
5555

5656
public void testAbstractLists() throws Exception
5757
{

src/test/java/com/fasterxml/jackson/databind/jsontype/UnknownSubClassTest.java

-27
This file was deleted.

0 commit comments

Comments
 (0)