blob: 44c3698ea4b953d1af506152a563b7c01f36faf9 [file] [log] [blame]
package org.codehaus.jackson.map.jsontype;
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.annotate.JsonTypeInfo.As;
import org.codehaus.jackson.annotate.JsonTypeInfo.Id;
import org.codehaus.jackson.annotate.JsonTypeName;
import org.codehaus.jackson.map.BaseMapTest;
import org.codehaus.jackson.map.ObjectMapper;
// Tests for [JACKSON-453]
public class TestExternalId extends BaseMapTest
{
/*
/**********************************************************
/* Helper types
/**********************************************************
*/
static class ExternalBean
{
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType")
public Object bean;
public ExternalBean() { }
public ExternalBean(int v) {
bean = new ValueBean(v);
}
}
static class ExternalBean3
{
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType1")
public Object value1;
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType2")
public Object value2;
public int foo;
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType3")
public Object value3;
public ExternalBean3() { }
public ExternalBean3(int v) {
value1 = new ValueBean(v);
value2 = new ValueBean(v+1);
value3 = new ValueBean(v+2);
foo = v;
}
}
static class ExternalBeanWithCreator
{
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType")
public Object value;
public int foo;
@JsonCreator
public ExternalBeanWithCreator(@JsonProperty("foo") int f)
{
foo = f;
value = new ValueBean(f);
}
}
@JsonTypeName("vbean")
static class ValueBean {
public int value;
public ValueBean() { }
public ValueBean(int v) { value = v; }
}
@JsonTypeName("funk")
@JsonTypeInfo(use=Id.NAME, include=As.EXTERNAL_PROPERTY, property="extType")
static class FunkyExternalBean {
public int i = 3;
}
// [JACKSON-831]
interface Pet {}
static class Dog implements Pet {
public String name;
}
static class House831 {
private String petType;
@JsonTypeInfo(use = Id.NAME, include = As.EXTERNAL_PROPERTY, property = "petType")
@JsonSubTypes({@JsonSubTypes.Type(name = "dog", value = Dog.class)})
public Pet pet;
public String getPetType() {
return petType;
}
public void setPetType(String petType) {
this.petType = petType;
}
}
/*
/**********************************************************
/* Unit tests, serialization
/**********************************************************
*/
public void testSimpleSerialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(ValueBean.class);
// This may look odd, but one implementation nastiness is the fact
// that we can not properly serialize type id before the object,
// because call is made after property name (for object) has already
// been written out. So we'll write it after...
// Deserializer will work either way as it can not rely on ordering
// anyway.
assertEquals("{\"bean\":{\"value\":11},\"extType\":\"vbean\"}",
mapper.writeValueAsString(new ExternalBean(11)));
}
// If trying to use with Class, should just become "PROPERTY" instead:
public void testImproperExternalIdSerialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
assertEquals("{\"extType\":\"funk\",\"i\":3}",
mapper.writeValueAsString(new FunkyExternalBean()));
}
/*
/**********************************************************
/* Unit tests, deserialization
/**********************************************************
*/
public void testSimpleDeserialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(ValueBean.class);
ExternalBean result = mapper.readValue("{\"bean\":{\"value\":11},\"extType\":\"vbean\"}", ExternalBean.class);
assertNotNull(result);
assertNotNull(result.bean);
ValueBean vb = (ValueBean) result.bean;
assertEquals(11, vb.value);
}
/**
* Test for verifying that it's ok to have multiple (say, 3)
* externally typed things, mixed with other stuff...
*/
public void testMultipleTypeIdsDeserialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(ValueBean.class);
String json = mapper.writeValueAsString(new ExternalBean3(3));
ExternalBean3 result = mapper.readValue(json, ExternalBean3.class);
assertNotNull(result);
assertNotNull(result.value1);
assertNotNull(result.value2);
assertNotNull(result.value3);
assertEquals(3, ((ValueBean)result.value1).value);
assertEquals(4, ((ValueBean)result.value2).value);
assertEquals(5, ((ValueBean)result.value3).value);
assertEquals(3, result.foo);
}
/**
* Also, it should be ok to use @JsonCreator as well...
*/
public void testExternalTypeWithCreator() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(ValueBean.class);
String json = mapper.writeValueAsString(new ExternalBeanWithCreator(7));
ExternalBeanWithCreator result = mapper.readValue(json, ExternalBeanWithCreator.class);
assertNotNull(result);
assertNotNull(result.value);
assertEquals(7, ((ValueBean)result.value).value);
assertEquals(7, result.foo);
}
// If trying to use with Class, should just become "PROPERTY" instead:
public void testImproperExternalIdDeserialization() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
FunkyExternalBean result = mapper.readValue("{\"extType\":\"funk\",\"i\":3}", FunkyExternalBean.class);
assertNotNull(result);
assertEquals(3, result.i);
}
// There seems to be some problems if type is also visible...
public void testIssue831() throws Exception
{
final String JSON = "{ \"petType\": \"dog\",\n"
+"\"pet\": { \"name\": \"Pluto\" }\n}";
ObjectMapper mapper = new ObjectMapper();
House831 result = mapper.readValue(JSON, House831.class);
assertNotNull(result);
assertNotNull(result.pet);
assertSame(Dog.class, result.pet.getClass());
assertEquals("dog", result.petType);
}
}