package com.fasterxml.jackson.databind.ser; import java.io.IOException; import java.util.*; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.introspect.AnnotatedField; import com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; import com.fasterxml.jackson.databind.ser.BeanSerializer; import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder; import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.type.ArrayType; import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.MapType; /** * Unit tests for verifying that it is possible to configure * construction of {@link BeanSerializer} instances. */ @SuppressWarnings("serial") public class BeanSerializerModifierTest extends BaseMapTest { static class SerializerModifierModule extends SimpleModule { protected BeanSerializerModifier modifier; public SerializerModifierModule(BeanSerializerModifier modifier) { super("test", Version.unknownVersion()); this.modifier = modifier; } @Override public void setupModule(SetupContext context) { super.setupModule(context); if (modifier != null) { context.addBeanSerializerModifier(modifier); } } } @JsonPropertyOrder({"b", "a"}) static class Bean { public String b = "b"; public String a = "a"; } static class RemovingModifier extends BeanSerializerModifier { private final String _removedProperty; public RemovingModifier(String remove) { _removedProperty = remove; } @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { Iterator<BeanPropertyWriter> it = beanProperties.iterator(); while (it.hasNext()) { BeanPropertyWriter bpw = it.next(); if (bpw.getName().equals(_removedProperty)) { it.remove(); } } return beanProperties; } } static class ReorderingModifier extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> orderProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { TreeMap<String,BeanPropertyWriter> props = new TreeMap<String,BeanPropertyWriter>(); for (BeanPropertyWriter bpw : beanProperties) { props.put(bpw.getName(), bpw); } return new ArrayList<BeanPropertyWriter>(props.values()); } } static class ReplacingModifier extends BeanSerializerModifier { private final JsonSerializer<?> _serializer; public ReplacingModifier(JsonSerializer<?> s) { _serializer = s; } @Override public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) { return _serializer; } } static class BuilderModifier extends BeanSerializerModifier { private final JsonSerializer<?> _serializer; public BuilderModifier(JsonSerializer<?> ser) { _serializer = ser; } @Override public BeanSerializerBuilder updateBuilder(SerializationConfig config, BeanDescription beanDesc, BeanSerializerBuilder builder) { return new BogusSerializerBuilder(builder, _serializer); } } static class BogusSerializerBuilder extends BeanSerializerBuilder { private final JsonSerializer<?> _serializer; public BogusSerializerBuilder(BeanSerializerBuilder src, JsonSerializer<?> ser) { super(src); _serializer = ser; } @Override public JsonSerializer<?> build() { return _serializer; } } static class BogusBeanSerializer extends JsonSerializer<Object> { private final int _value; public BogusBeanSerializer(int v) { _value = v; } @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumber(_value); } } static class EmptyBean { @JsonIgnore public String name = "foo"; } static class EmptyBeanModifier extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { JavaType strType = config.constructType(String.class); // we need a valid BeanPropertyDefinition; this will do (just need name to match) POJOPropertyBuilder prop = new POJOPropertyBuilder(config, null, true, new PropertyName("bogus")); try { AnnotatedField f = new AnnotatedField(null, EmptyBean.class.getDeclaredField("name"), null); beanProperties.add(new BeanPropertyWriter(prop, f, null, strType, null, null, strType, false, null, null)); } catch (NoSuchFieldException e) { throw new IllegalStateException(e.getMessage()); } return beanProperties; } } // [Issue#539]: use post-modifier static class EmptyBeanModifier539 extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { return beanProperties; } @Override public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new BogusBeanSerializer(42); } } // [databind#120], arrays, collections, maps static class ArraySerializerModifier extends BeanSerializerModifier { @Override public JsonSerializer<?> modifyArraySerializer(SerializationConfig config, ArrayType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new StdSerializer<Object>(Object.class) { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumber(123); } }; } } static class CollectionSerializerModifier extends BeanSerializerModifier { @Override public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config, CollectionType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new StdSerializer<Object>(Object.class) { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumber(123); } }; } } static class MapSerializerModifier extends BeanSerializerModifier { @Override public JsonSerializer<?> modifyMapSerializer(SerializationConfig config, MapType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new StdSerializer<Object>(Object.class) { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumber(123); } }; } } static class EnumSerializerModifier extends BeanSerializerModifier { @Override public JsonSerializer<?> modifyEnumSerializer(SerializationConfig config, JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new StdSerializer<Object>(Object.class) { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeNumber(123); } }; } } static class KeySerializerModifier extends BeanSerializerModifier { @Override public JsonSerializer<?> modifyKeySerializer(SerializationConfig config, JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) { return new StdSerializer<Object>(Object.class) { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeFieldName("foo"); } }; } } /* /******************************************************** /* Unit tests: success /******************************************************** */ public void testPropertyRemoval() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SerializerModifierModule(new RemovingModifier("a"))); Bean bean = new Bean(); assertEquals("{\"b\":\"b\"}", mapper.writeValueAsString(bean)); } public void testPropertyReorder() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SerializerModifierModule(new ReorderingModifier())); Bean bean = new Bean(); assertEquals("{\"a\":\"a\",\"b\":\"b\"}", mapper.writeValueAsString(bean)); } public void testBuilderReplacement() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SerializerModifierModule(new BuilderModifier(new BogusBeanSerializer(17)))); Bean bean = new Bean(); assertEquals("17", mapper.writeValueAsString(bean)); } public void testSerializerReplacement() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SerializerModifierModule(new ReplacingModifier(new BogusBeanSerializer(123)))); Bean bean = new Bean(); assertEquals("123", mapper.writeValueAsString(bean)); } // for [JACKSON-670] public void testEmptyBean() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test", Version.unknownVersion()) { @Override public void setupModule(SetupContext context) { super.setupModule(context); context.addBeanSerializerModifier(new EmptyBeanModifier()); } }); String json = mapper.writeValueAsString(new EmptyBean()); assertEquals("{\"bogus\":\"foo\"}", json); } public void testEmptyBean539() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test", Version.unknownVersion()) { @Override public void setupModule(SetupContext context) { super.setupModule(context); context.addBeanSerializerModifier(new EmptyBeanModifier539()); } }); String json = mapper.writeValueAsString(new EmptyBean()); assertEquals("42", json); } // [databind#121] public void testModifyArraySerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test") .setSerializerModifier(new ArraySerializerModifier())); assertEquals("123", mapper.writeValueAsString(new Integer[] { 1, 2 })); } public void testModifyCollectionSerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test") .setSerializerModifier(new CollectionSerializerModifier())); assertEquals("123", mapper.writeValueAsString(new ArrayList<Integer>())); } public void testModifyMapSerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test") .setSerializerModifier(new MapSerializerModifier())); assertEquals("123", mapper.writeValueAsString(new HashMap<String,String>())); } public void testModifyEnumSerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test") .setSerializerModifier(new EnumSerializerModifier())); assertEquals("123", mapper.writeValueAsString(ABC.C)); } public void testModifyKeySerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SimpleModule("test") .setSerializerModifier(new KeySerializerModifier())); Map<String,Integer> map = new HashMap<String,Integer>(); map.put("x", 3); assertEquals("{\"foo\":3}", mapper.writeValueAsString(map)); } }