-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix handling of ObjectId-property in JsonIdentityInfo for uniform des…
…erialization (#3868)
- Loading branch information
1 parent
d8f17b9
commit 325d129
Showing
2 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 197 additions & 0 deletions
197
src/test/java/com/fasterxml/jackson/databind/deser/JsonIdentityInfoIdProperty3838Test.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package com.fasterxml.jackson.databind.deser; | ||
|
||
import com.fasterxml.jackson.annotation.*; | ||
import com.fasterxml.jackson.databind.BaseMapTest; | ||
import com.fasterxml.jackson.databind.DeserializationFeature; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.databind.exc.MismatchedInputException; | ||
|
||
// [databind#3838]: Difference in the handling of ObjectId-property in JsonIdentityInfo depending on the deserialization route. | ||
public class JsonIdentityInfoIdProperty3838Test extends BaseMapTest { | ||
|
||
/* | ||
/********************************************************** | ||
/* Set Up | ||
/********************************************************** | ||
*/ | ||
interface ResultGetter { | ||
String result(); | ||
} | ||
|
||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class) | ||
static class SetterBased implements ResultGetter { | ||
private String id; | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
public void setId(String id) { | ||
this.id = id; | ||
} | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class) | ||
static class CreatorBased implements ResultGetter { | ||
private final String id; | ||
|
||
@JsonCreator | ||
CreatorBased(@JsonProperty(value = "id") String id) { | ||
this.id = id; | ||
} | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class) | ||
static class DefaultConstructorBased implements ResultGetter { | ||
public String id; | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class) | ||
static class StaticFactoryMethodBased implements ResultGetter { | ||
private final String id; | ||
|
||
private StaticFactoryMethodBased(String id) { | ||
this.id = id; | ||
} | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
@JsonCreator | ||
public static StaticFactoryMethodBased create(@JsonProperty("id") String id) { | ||
return new StaticFactoryMethodBased(id); | ||
} | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class) | ||
static class MultiArgConstructorBased implements ResultGetter { | ||
private final String id; | ||
private final int value; | ||
|
||
@JsonCreator | ||
MultiArgConstructorBased(@JsonProperty("id") String id, @JsonProperty("value") int value) { | ||
this.id = id; | ||
this.value = value; | ||
} | ||
|
||
public String getId() { | ||
return id; | ||
} | ||
|
||
public int getValue() { | ||
return value; | ||
} | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo( | ||
generator = ObjectIdGenerators.PropertyGenerator.class, | ||
property = "id" | ||
) | ||
@JsonTypeInfo( | ||
use = JsonTypeInfo.Id.NAME, | ||
include = JsonTypeInfo.As.WRAPPER_OBJECT, | ||
property = "type" | ||
) | ||
@JsonSubTypes({ | ||
@JsonSubTypes.Type(value = Concrete3838.class, name = "concrete_3838") | ||
}) | ||
static class BaseType3838 implements ResultGetter { | ||
public String id; | ||
|
||
@Override | ||
public String result() { | ||
return id; | ||
} | ||
} | ||
|
||
@JsonTypeName("concrete_3838") | ||
static class Concrete3838 extends BaseType3838 { | ||
public String location; | ||
|
||
protected Concrete3838() {} | ||
|
||
public Concrete3838(String id, String loc) { | ||
this.id = id; | ||
location = loc; | ||
} | ||
} | ||
|
||
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id") | ||
static class IntSequencedBean implements ResultGetter{ | ||
public String value; | ||
|
||
@Override | ||
public String result() { | ||
return value; | ||
} | ||
} | ||
|
||
/* | ||
/********************************************************** | ||
/* Test | ||
/********************************************************** | ||
*/ | ||
|
||
private final ObjectMapper MAPPER = newJsonMapper(); | ||
|
||
final static Object[][] CLASS_AND_JSON_STRING = new Object[][]{ | ||
{SetterBased.class, "{'id':'great'}"}, | ||
{CreatorBased.class, "{'id':'great'}"}, | ||
{DefaultConstructorBased.class, "{'id':'great'}"}, | ||
{StaticFactoryMethodBased.class, "{'id':'great'}"}, | ||
{MultiArgConstructorBased.class, "{'id':'great','value':42}"}, | ||
{BaseType3838.class, "{'concrete_3838':{'id':'great','location':'Bangkok'}}"}, | ||
{IntSequencedBean.class, "{'id':-1,'value':'great'}"} | ||
}; | ||
|
||
public void testUniformHandlingForMissingObjectId() throws Exception { | ||
for (Object[] classAndJsonStrEntry : CLASS_AND_JSON_STRING) { | ||
final Class<?> cls = (Class<?>) classAndJsonStrEntry[0]; | ||
final String jsonStr = (String) classAndJsonStrEntry[1]; | ||
|
||
// 1. throws MismatchedInputException with empty JSON object | ||
try { | ||
MAPPER.readValue("{}", cls); | ||
fail("should not pass"); | ||
} catch (MismatchedInputException e) { | ||
verifyException(e, | ||
"No Object Id found for an instance of", "to", | ||
"to assign to property 'id'"); | ||
} | ||
|
||
// 2. but works with non-empty JSON object | ||
ResultGetter nonEmptyObj = (ResultGetter) MAPPER.readValue(a2q(jsonStr), cls); | ||
assertEquals("great", nonEmptyObj.result()); | ||
} | ||
} | ||
} |