package com.fasterxml.jackson.databind.ser; import java.util.*; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonAppend; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.introspect.AnnotatedClass; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import com.fasterxml.jackson.databind.util.Annotations; /** * Tests for verifying that one can append virtual properties after regular ones. * * @since 2.5 */ public class TestVirtualProperties extends BaseMapTest { @JsonAppend(attrs={ @JsonAppend.Attr("id"), @JsonAppend.Attr(value="internal", propName="extra", required=true) }) static class SimpleBean { public int value = 13; } @JsonAppend(prepend=true, attrs={ @JsonAppend.Attr("id"), @JsonAppend.Attr(value="internal", propName="extra") }) static class SimpleBeanPrepend { public int value = 13; } enum ABC { A, B, C; } @JsonAppend(attrs=@JsonAppend.Attr(value="desc", include=JsonInclude.Include.NON_EMPTY)) static class OptionalsBean { public int value = 28; } @SuppressWarnings("serial") static class CustomVProperty extends VirtualBeanPropertyWriter { private CustomVProperty() { super(); } private CustomVProperty(BeanPropertyDefinition propDef, Annotations ctxtAnn, JavaType type) { super(propDef, ctxtAnn, type); } @Override protected Object value(Object bean, JsonGenerator jgen, SerializerProvider prov) { if (_name.toString().equals("id")) { return "abc123"; } if (_name.toString().equals("extra")) { return new int[] { 42 }; } return "???"; } @Override public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type) { return new CustomVProperty(propDef, declaringClass.getAnnotations(), type); } } @JsonAppend(prepend=true, props={ @JsonAppend.Prop(value=CustomVProperty.class, name="id"), @JsonAppend.Prop(value=CustomVProperty.class, name="extra") }) static class CustomVBean { public int value = 72; } /* /********************************************************** /* Test methods /********************************************************** */ private final ObjectWriter WRITER = objectWriter(); public void testAttributeProperties() throws Exception { Map<String,Object> stuff = new LinkedHashMap<String,Object>(); stuff.put("x", 3); stuff.put("y", ABC.B); String json = WRITER.withAttribute("id", "abc123") .withAttribute("internal", stuff) .writeValueAsString(new SimpleBean()); assertEquals(aposToQuotes("{'value':13,'id':'abc123','extra':{'x':3,'y':'B'}}"), json); json = WRITER.withAttribute("id", "abc123") .withAttribute("internal", stuff) .writeValueAsString(new SimpleBeanPrepend()); assertEquals(aposToQuotes("{'id':'abc123','extra':{'x':3,'y':'B'},'value':13}"), json); } public void testAttributePropInclusion() throws Exception { // first, with desc String json = WRITER.withAttribute("desc", "nice") .writeValueAsString(new OptionalsBean()); assertEquals(aposToQuotes("{'value':28,'desc':'nice'}"), json); // then with null (not defined) json = WRITER.writeValueAsString(new OptionalsBean()); assertEquals(aposToQuotes("{'value':28}"), json); // and finally "empty" json = WRITER.withAttribute("desc", "") .writeValueAsString(new OptionalsBean()); assertEquals(aposToQuotes("{'value':28}"), json); } public void testCustomProperties() throws Exception { String json = WRITER.withAttribute("desc", "nice") .writeValueAsString(new CustomVBean()); assertEquals(aposToQuotes("{'id':'abc123','extra':[42],'value':72}"), json); } }