package com.fasterxml.jackson.databind.ser; import java.io.IOException; import java.util.*; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonSerialize; /** * This unit test suite tests use of @JsonClass Annotation * with bean serialization. */ public class TestJsonSerialize extends BaseMapTest { /* /********************************************************** /* Annotated helper classes /********************************************************** */ interface ValueInterface { public int getX(); } static class ValueClass implements ValueInterface { @Override public int getX() { return 3; } public int getY() { return 5; } } /** * Test class to verify that <code>JsonSerialize.as</code> * works as expected */ static class WrapperClassForAs { @JsonSerialize(as=ValueInterface.class) public ValueClass getValue() { return new ValueClass(); } } // This should indicate that static type be used for all fields @JsonSerialize(typing=JsonSerialize.Typing.STATIC) static class WrapperClassForStaticTyping { public ValueInterface getValue() { return new ValueClass(); } } static class WrapperClassForStaticTyping2 { @JsonSerialize(typing=JsonSerialize.Typing.STATIC) public ValueInterface getStaticValue() { return new ValueClass(); } @JsonSerialize(typing=JsonSerialize.Typing.DYNAMIC) public ValueInterface getDynamicValue() { return new ValueClass(); } } /** * Test bean that has an invalid {@link JsonSerialize} annotation. */ static class BrokenClass { // invalid annotation: String not a supertype of Long @JsonSerialize(as=String.class) public Long getValue() { return Long.valueOf(4L); } } @SuppressWarnings("serial") static class ValueMap extends HashMap<String,ValueInterface> { } @SuppressWarnings("serial") static class ValueList extends ArrayList<ValueInterface> { } @SuppressWarnings("serial") static class ValueLinkedList extends LinkedList<ValueInterface> { } // Classes for [JACKSON-294] static class Foo294 { @JsonProperty private String id; @JsonSerialize(using = Bar294Serializer.class) private Bar294 bar; public Foo294() { } public Foo294(String id, String id2) { this.id = id; bar = new Bar294(id2); } } static class Bar294{ @JsonProperty protected String id; @JsonProperty protected String name; public Bar294() { } public Bar294(String id) { this.id = id; } public String getId() { return id; } public String getName() { return name; } } static class Bar294Serializer extends JsonSerializer<Bar294> { @Override public void serialize(Bar294 bar, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(bar.id); } } /* /********************************************************** /* Main tests /********************************************************** */ final ObjectMapper MAPPER = objectMapper(); @SuppressWarnings("unchecked") public void testSimpleValueDefinition() throws Exception { Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForAs()); assertEquals(1, result.size()); Object ob = result.get("value"); // Should see only "x", not "y" result = (Map<String,Object>) ob; assertEquals(1, result.size()); assertEquals(Integer.valueOf(3), result.get("x")); } public void testBrokenAnnotation() throws Exception { try { serializeAsString(MAPPER, new BrokenClass()); fail("Should not succeed"); } catch (Exception e) { verifyException(e, "types not related"); } } @SuppressWarnings("unchecked") public void testStaticTypingForClass() throws Exception { Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForStaticTyping()); assertEquals(1, result.size()); Object ob = result.get("value"); // Should see only "x", not "y" result = (Map<String,Object>) ob; assertEquals(1, result.size()); assertEquals(Integer.valueOf(3), result.get("x")); } @SuppressWarnings("unchecked") public void testMixedTypingForClass() throws Exception { Map<String,Object> result = writeAndMap(MAPPER, new WrapperClassForStaticTyping2()); assertEquals(2, result.size()); Object obStatic = result.get("staticValue"); // Should see only "x", not "y" Map<String,Object> stat = (Map<String,Object>) obStatic; assertEquals(1, stat.size()); assertEquals(Integer.valueOf(3), stat.get("x")); Object obDynamic = result.get("dynamicValue"); // Should see both Map<String,Object> dyn = (Map<String,Object>) obDynamic; assertEquals(2, dyn.size()); assertEquals(Integer.valueOf(3), dyn.get("x")); assertEquals(Integer.valueOf(5), dyn.get("y")); } public void testStaticTypingWithMap() throws Exception { ObjectMapper m = new ObjectMapper(); m.configure(MapperFeature.USE_STATIC_TYPING, true); ValueMap map = new ValueMap(); map.put("a", new ValueClass()); assertEquals("{\"a\":{\"x\":3}}", serializeAsString(m, map)); } public void testStaticTypingWithArrayList() throws Exception { ObjectMapper m = new ObjectMapper(); m.configure(MapperFeature.USE_STATIC_TYPING, true); ValueList list = new ValueList(); list.add(new ValueClass()); assertEquals("[{\"x\":3}]", m.writeValueAsString(list)); } public void testStaticTypingWithLinkedList() throws Exception { ObjectMapper m = new ObjectMapper(); m.configure(MapperFeature.USE_STATIC_TYPING, true); ValueLinkedList list = new ValueLinkedList(); list.add(new ValueClass()); assertEquals("[{\"x\":3}]", serializeAsString(m, list)); } public void testStaticTypingWithArray() throws Exception { ObjectMapper m = new ObjectMapper(); m.configure(MapperFeature.USE_STATIC_TYPING, true); ValueInterface[] array = new ValueInterface[] { new ValueClass() }; assertEquals("[{\"x\":3}]", serializeAsString(m, array)); } public void testIssue294() throws Exception { assertEquals("{\"id\":\"fooId\",\"bar\":\"barId\"}", MAPPER.writeValueAsString(new Foo294("fooId", "barId"))); } @JsonPropertyOrder({ "a", "something" }) static class Response { public String a = "x"; @JsonProperty //does not show up public boolean isSomething() { return true; } } public void testWithIsGetter() throws Exception { ObjectMapper m = new ObjectMapper(); m.setVisibility(PropertyAccessor.GETTER, Visibility.NONE) .setVisibility(PropertyAccessor.FIELD, Visibility.ANY) .setVisibility(PropertyAccessor.CREATOR, Visibility.NONE) .setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE) .setVisibility(PropertyAccessor.SETTER, Visibility.NONE); final String JSON = m.writeValueAsString(new Response()); assertEquals(aposToQuotes("{'a':'x','something':true}"), JSON); } }