blob: 4f602bb28792554b56ce6e0a7629d0d28e29913f [file] [log] [blame]
package org.codehaus.jackson.map.deser;
import org.codehaus.jackson.annotate.*;
import org.codehaus.jackson.map.*;
/**
* Unit tests for verifying that it is possible to annotate
* various kinds of things with {@link JsonCreator} annotation.
*/
public class TestPolymorphicCreators
extends BaseMapTest
{
/*
/**********************************************************
/* Helper beans
/**********************************************************
*/
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
{
private final String opt;
private 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 {
private One(String opt) {
super(opt);
}
@Override public int getWhich() {
return 1;
}
}
/*
**********************************************
* Actual tests
**********************************************
*/
/**
* Simple test to verify that it is possible to implement polymorphic
* deserialization manually.
*/
public void testManualPolymorphicDog() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// 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);
}
public void testManualPolymorphicCatBasic() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// 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:
assertEquals(false, cat.likesCream);
}
public void testManualPolymorphicCatWithReorder() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// 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);
}
public void testManualPolymorphicWithNumbered() throws Exception
{
final ObjectMapper m = new ObjectMapper();
final ObjectWriter w = m.writerWithType(AbstractRoot.class);
final ObjectReader r = m.reader(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());
}
}