ObjectId3838Test.java
package com.fasterxml.jackson.databind.objectid;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
// [databind#3838]: Difference in the handling of ObjectId-property in JsonIdentityInfo depending on the deserialization route.
public class ObjectId3838Test extends DatabindTestUtil
{
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 methods
/**********************************************************************
*/
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'}"}
};
@Test
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());
}
}
}