PolymorphicPropsCreatorsTest.java
package com.fasterxml.jackson.databind.deser.creators;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for verifying that it is possible to annotate
* various kinds of things with {@link JsonCreator} annotation.
*/
public class PolymorphicPropsCreatorsTest extends DatabindTestUtil
{
static class Animal
{
// All animals have names, for our demo purposes...
public String name;
protected Animal() { }
/**
* Creator method that can instantiate instances of
* appropriate polymoprphic type
*/
@JsonCreator
public static Animal create(@JsonProperty("type") String type)
{
if ("dog".equals(type)) {
return new Dog();
}
if ("cat".equals(type)) {
return new Cat();
}
throw new IllegalArgumentException("No such animal type ('"+type+"')");
}
}
static class Dog extends Animal
{
double barkVolume; // in decibels
public Dog() { }
public void setBarkVolume(double v) { barkVolume = v; }
}
static class Cat extends Animal
{
boolean likesCream;
public int lives;
public Cat() { }
public void setLikesCream(boolean likesCreamSurely) { likesCream = likesCreamSurely; }
}
abstract static class AbstractRoot
{
protected final String opt;
protected AbstractRoot(String opt) {
this.opt = opt;
}
@JsonCreator
public static final AbstractRoot make(@JsonProperty("which") int which,
@JsonProperty("opt") String opt) {
if (1 == which) {
return new One(opt);
}
throw new RuntimeException("cannot instantiate " + which);
}
abstract public int getWhich();
public final String getOpt() {
return opt;
}
}
static final class One extends AbstractRoot {
protected One(String opt) {
super(opt);
}
@Override public int getWhich() {
return 1;
}
}
// [databind#113]
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class")
@JsonSubTypes({ @JsonSubTypes.Type(Dog113.class) })
public static abstract class Animal113 {
public final static String ID = "id";
private String id;
@JsonCreator
public Animal113(@JsonProperty(ID) String id) {
this.id = id;
}
@JsonProperty(ID)
public String getId() {
return id;
}
}
public static class Dog113 extends Animal113 {
@JsonCreator
public Dog113(@JsonProperty(ID) String id) {
super(id);
}
}
public static class AnimalWrapper113 {
private Animal113 animal;
@JsonCreator
public AnimalWrapper113(@JsonProperty("animal") Animal113 animal) {
this.animal = animal;
}
public Animal113 getAnimal() {
return animal;
}
}
/*
/**********************************************************
/* Actual tests
/**********************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
/**
* Simple test to verify that it is possible to implement polymorphic
* deserialization manually.
*/
@Test
public void testManualPolymorphicDog() throws Exception
{
// first, a dog, start with type
Animal animal = MAPPER.readValue("{ \"type\":\"dog\", \"name\":\"Fido\", \"barkVolume\" : 95.0 }", Animal.class);
assertEquals(Dog.class, animal.getClass());
assertEquals("Fido", animal.name);
assertEquals(95.0, ((Dog) animal).barkVolume);
}
@Test
public void testManualPolymorphicCatBasic() throws Exception
{
// and finally, lactose-intolerant, but otherwise robust super-cat:
Animal animal = MAPPER.readValue("{ \"name\" : \"Macavity\", \"type\":\"cat\", \"lives\":18, \"likesCream\":false }", Animal.class);
assertEquals(Cat.class, animal.getClass());
assertEquals("Macavity", animal.name); // ... there's no one like Macavity!
Cat cat = (Cat) animal;
assertEquals(18, cat.lives);
// ok, he can't drink dairy products. Let's verify:
assertFalse(cat.likesCream);
}
@Test
public void testManualPolymorphicCatWithReorder() throws Exception
{
// Then cat; shuffle order to mandate buffering
Animal animal = MAPPER.readValue("{ \"likesCream\":true, \"name\" : \"Venla\", \"type\":\"cat\" }", Animal.class);
assertEquals(Cat.class, animal.getClass());
assertEquals("Venla", animal.name);
// bah, of course cats like cream. But let's ensure Jackson won't mess with laws of nature!
assertTrue(((Cat) animal).likesCream);
}
@Test
public void testManualPolymorphicWithNumbered() throws Exception
{
final ObjectWriter w = MAPPER.writerFor(AbstractRoot.class);
final ObjectReader r = MAPPER.readerFor(AbstractRoot.class);
AbstractRoot input = AbstractRoot.make(1, "oh hai!");
String json = w.writeValueAsString(input);
AbstractRoot result = r.readValue(json);
assertNotNull(result);
assertEquals("oh hai!", result.getOpt());
}
// [databind#113]
@Test
public void testSubtypes113() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
String id = "nice dogy";
String json = mapper.writeValueAsString(new AnimalWrapper113(new Dog113(id)));
//System.err.println("JSON = "+json);
AnimalWrapper113 wrapper = mapper.readValue(json, AnimalWrapper113.class);
assertEquals(id, wrapper.getAnimal().getId());
}
}