package com.fasterxml.jackson.databind.struct;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
public class TestPOJOAsArray extends BaseMapTest
{
static class PojoAsArrayWrapper
{
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
public PojoAsArray value;
public PojoAsArrayWrapper() { }
public PojoAsArrayWrapper(String name, int x, int y, boolean c) {
value = new PojoAsArray(name, x, y, c);
}
}
@JsonPropertyOrder(alphabetic=true)
static class NonAnnotatedXY {
public int x, y;
public NonAnnotatedXY() { }
public NonAnnotatedXY(int x0, int y0) {
x = x0;
y = y0;
}
}
// note: must be serialized/deserialized alphabetically; fields NOT declared in that order
@JsonPropertyOrder(alphabetic=true)
static class PojoAsArray
{
public int x, y;
public String name;
public boolean complete;
public PojoAsArray() { }
public PojoAsArray(String name, int x, int y, boolean c) {
this.name = name;
this.x = x;
this.y = y;
this.complete = c;
}
}
@JsonPropertyOrder(alphabetic=true)
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
static class FlatPojo
{
public int x, y;
public String name;
public boolean complete;
public FlatPojo() { }
public FlatPojo(String name, int x, int y, boolean c) {
this.name = name;
this.x = x;
this.y = y;
this.complete = c;
}
}
static class ForceArraysIntrospector extends JacksonAnnotationIntrospector
{
private static final long serialVersionUID = 1L;
@Override
public JsonFormat.Value findFormat(Annotated a) {
return new JsonFormat.Value().withShape(JsonFormat.Shape.ARRAY);
}
}
static class A {
public B value = new B();
}
@JsonPropertyOrder(alphabetic=true)
static class B {
public int x = 1;
public int y = 2;
}
@JsonFormat(shape=Shape.ARRAY)
static class SingleBean {
public String name = "foo";
}
@JsonPropertyOrder(alphabetic=true)
@JsonFormat(shape=Shape.ARRAY)
static class TwoStringsBean {
public String bar = null;
public String foo = "bar";
}
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
@JsonPropertyOrder(alphabetic=true)
static class AsArrayWithMap
{
public Map<Integer,Integer> attrs;
public AsArrayWithMap() { }
public AsArrayWithMap(int x, int y) {
attrs = new HashMap<Integer,Integer>();
attrs.put(x, y);
}
}
@JsonFormat(shape=JsonFormat.Shape.ARRAY)
static class CreatorWithIndex {
protected int _a, _b;
@JsonCreator
public CreatorWithIndex(@JsonProperty(index=0, value="a") int a,
@JsonProperty(index=1, value="b") int b) {
this._a = a;
this._b = b;
}
}
/*
/*****************************************************
/* Basic tests
/*****************************************************
*/
private final static ObjectMapper MAPPER = new ObjectMapper();
/**
* Test that verifies that property annotation works
*/
public void testReadSimplePropertyValue() throws Exception
{
String json = "{\"value\":[true,\"Foobar\",42,13]}";
PojoAsArrayWrapper p = MAPPER.readValue(json, PojoAsArrayWrapper.class);
assertNotNull(p.value);
assertTrue(p.value.complete);
assertEquals("Foobar", p.value.name);
assertEquals(42, p.value.x);
assertEquals(13, p.value.y);
}
/**
* Test that verifies that Class annotation works
*/
public void testReadSimpleRootValue() throws Exception
{
String json = "[false,\"Bubba\",1,2]";
FlatPojo p = MAPPER.readValue(json, FlatPojo.class);
assertFalse(p.complete);
assertEquals("Bubba", p.name);
assertEquals(1, p.x);
assertEquals(2, p.y);
}
/**
* Test that verifies that property annotation works
*/
public void testWriteSimplePropertyValue() throws Exception
{
String json = MAPPER.writeValueAsString(new PojoAsArrayWrapper("Foobar", 42, 13, true));
// will have wrapper POJO, then POJO-as-array..
assertEquals("{\"value\":[true,\"Foobar\",42,13]}", json);
}
/**
* Test that verifies that Class annotation works
*/
public void testWriteSimpleRootValue() throws Exception
{
String json = MAPPER.writeValueAsString(new FlatPojo("Bubba", 1, 2, false));
// will have wrapper POJO, then POJO-as-array..
assertEquals("[false,\"Bubba\",1,2]", json);
}
// [Issue#223]
public void testNullColumn() throws Exception
{
assertEquals("[null,\"bar\"]", MAPPER.writeValueAsString(new TwoStringsBean()));
}
/*
/*****************************************************
/* Compatibility with "single-elem as array" feature
/*****************************************************
*/
public void testSerializeAsArrayWithSingleProperty() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
String json = mapper.writeValueAsString(new SingleBean());
assertEquals("\"foo\"", json);
}
public void testBeanAsArrayUnwrapped() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
SingleBean result = mapper.readValue("[\"foobar\"]", SingleBean.class);
assertNotNull(result);
assertEquals("foobar", result.name);
}
/*
/*****************************************************
/* Round-trip tests
/*****************************************************
*/
public void testAnnotationOverride() throws Exception
{
// by default, POJOs become JSON Objects;
assertEquals("{\"value\":{\"x\":1,\"y\":2}}", MAPPER.writeValueAsString(new A()));
// but override should change it:
ObjectMapper mapper2 = new ObjectMapper();
mapper2.setAnnotationIntrospector(new ForceArraysIntrospector());
assertEquals("[[1,2]]", mapper2.writeValueAsString(new A()));
// and allow reading back, too
}
public void testWithMaps() throws Exception
{
AsArrayWithMap input = new AsArrayWithMap(1, 2);
String json = MAPPER.writeValueAsString(input);
AsArrayWithMap output = MAPPER.readValue(json, AsArrayWithMap.class);
assertNotNull(output);
assertNotNull(output.attrs);
assertEquals(1, output.attrs.size());
assertEquals(Integer.valueOf(2), output.attrs.get(1));
}
public void testSimpleWithIndex() throws Exception
{
// as POJO:
// CreatorWithIndex value = MAPPER.readValue(aposToQuotes("{'b':1,'a':2}"),
CreatorWithIndex value = MAPPER.readValue(aposToQuotes("[2,1]"),
CreatorWithIndex.class);
assertEquals(2, value._a);
assertEquals(1, value._b);
}
public void testWithConfigOverrides() throws Exception
{
ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(NonAnnotatedXY.class)
.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.ARRAY));
String json = mapper.writeValueAsString(new NonAnnotatedXY(2, 3));
assertEquals("[2,3]", json);
// also, read it back
NonAnnotatedXY result = mapper.readValue(json, NonAnnotatedXY.class);
assertNotNull(result);
assertEquals(3, result.y);
}
/*
/*****************************************************
/* Failure tests
/*****************************************************
*/
public void testUnknownExtraProp() throws Exception
{
String json = "{\"value\":[true,\"Foobar\",42,13, false]}";
try {
MAPPER.readValue(json, PojoAsArrayWrapper.class);
fail("should not pass with extra element");
} catch (MismatchedInputException e) {
verifyException(e, "Unexpected JSON values");
}
// but actually fine if skip-unknown set
PojoAsArrayWrapper v = MAPPER.readerFor(PojoAsArrayWrapper.class)
.without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.readValue(json);
assertNotNull(v);
// note: +1 for both so
assertEquals(v.value.x, 42);
assertEquals(v.value.y, 13);
assertTrue(v.value.complete);
assertEquals("Foobar", v.value.name);
}
}