package com.fasterxml.jackson.databind.deser; import java.io.*; import java.util.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; /** * Unit test suite that tests "usingXxx" properties of * {@link JsonDeserialize} annotation. */ @SuppressWarnings("serial") public class TestAnnotationUsing extends BaseMapTest { /* /********************************************************************** /* Annotated Bean classes /********************************************************************** */ /** * Class for testing {@link JsonDeserializer} annotation * for class itself. */ @JsonDeserialize(using=ValueDeserializer.class) final static class ValueClass { int _a; /* we'll test it by not having default no-arg ctor, and leaving * out single-int-arg ctor (because deserializer would use that too) */ public ValueClass(int a, int b) { _a = a; } } /** * Class for testing {@link JsonDeserializer} annotation * for a method */ final static class MethodBean { int[] _ints; /* Note: could be made to work otherwise, except that * to trigger failure (in absence of annotation) Json * is of type VALUE_NUMBER_INT, not an Array: array would * work by default, but scalar not */ @JsonDeserialize(using=IntsDeserializer.class) public void setInts(int[] i) { _ints = i; } } static class ArrayBean { @JsonDeserialize(contentUsing=ValueDeserializer.class) public Object[] values; } static class ListBean { @JsonDeserialize(contentUsing=ValueDeserializer.class) public List<Object> values; } static class MapBean { @JsonDeserialize(contentUsing=ValueDeserializer.class) public Map<String,Object> values; } static class MapKeyBean { @JsonDeserialize(keyUsing=MapKeyDeserializer.class) public Map<Object,Object> values; } @JsonDeserialize(keyUsing=MapKeyDeserializer.class, contentUsing=ValueDeserializer.class) static class MapKeyMap extends HashMap<Object,Object> { } /* /********************************************************************** /* Deserializers /********************************************************************** */ static class ValueDeserializer extends StdDeserializer<ValueClass> { public ValueDeserializer() { super(ValueClass.class); } @Override public ValueClass deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { int i = jp.getIntValue(); return new ValueClass(i, i); } } private final static class IntsDeserializer extends StdDeserializer<int[]> { public IntsDeserializer() { super(int[].class); } @Override public int[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return new int[] { jp.getIntValue() }; } } private final static class MapKeyDeserializer extends KeyDeserializer { @Override public Object deserializeKey(String key, DeserializationContext ctxt) { return new String[] { key }; } } /* /********************************************************************** /* Tests: specifying deserializer of value itself /********************************************************************** */ // Unit test to verify that {@link JsonDeserialize#using} annotation works // when applied to a class public void testClassDeserializer() throws Exception { ObjectMapper m = new ObjectMapper(); ValueClass result = m.readValue(" 123 ", ValueClass.class); assertEquals(123, result._a); } // Unit test to verify that {@link JsonDeserialize#using} annotation works // when applied to a Method public void testMethodDeserializer() throws Exception { ObjectMapper m = new ObjectMapper(); // note: since it's part of method, must parse from Object struct MethodBean result = m.readValue(" { \"ints\" : 3 } ", MethodBean.class); assertNotNull(result); int[] ints = result._ints; assertNotNull(ints); assertEquals(1, ints.length); assertEquals(3, ints[0]); } /* /********************************************************************** /* Tests: specifying deserializer for keys and/or contents /********************************************************************** */ public void testArrayContentUsing() throws Exception { ObjectMapper m = new ObjectMapper(); ArrayBean result = m.readValue(" { \"values\" : [ 1, 2, 3 ] } ", ArrayBean.class); assertNotNull(result); Object[] obs = result.values; assertNotNull(obs); assertEquals(3, obs.length); assertEquals(ValueClass.class, obs[0].getClass()); assertEquals(1, ((ValueClass) obs[0])._a); assertEquals(ValueClass.class, obs[1].getClass()); assertEquals(2, ((ValueClass) obs[1])._a); assertEquals(ValueClass.class, obs[2].getClass()); assertEquals(3, ((ValueClass) obs[2])._a); } public void testListContentUsing() throws Exception { ObjectMapper m = new ObjectMapper(); ListBean result = m.readValue(" { \"values\" : [ 1, 2, 3 ] } ", ListBean.class); assertNotNull(result); List<Object> obs = result.values; assertNotNull(obs); assertEquals(3, obs.size()); assertEquals(ValueClass.class, obs.get(0).getClass()); assertEquals(1, ((ValueClass) obs.get(0))._a); assertEquals(ValueClass.class, obs.get(1).getClass()); assertEquals(2, ((ValueClass) obs.get(1))._a); assertEquals(ValueClass.class, obs.get(2).getClass()); assertEquals(3, ((ValueClass) obs.get(2))._a); } public void testMapContentUsing() throws Exception { ObjectMapper m = new ObjectMapper(); MapBean result = m.readValue(" { \"values\" : { \"a\": 1, \"b\":2 } } ", MapBean.class); assertNotNull(result); Map<String,Object> map = result.values; assertNotNull(map); assertEquals(2, map.size()); assertEquals(ValueClass.class, map.get("a").getClass()); assertEquals(1, ((ValueClass) map.get("a"))._a); assertEquals(ValueClass.class, map.get("b").getClass()); assertEquals(2, ((ValueClass) map.get("b"))._a); } public void testMapKeyUsing() throws Exception { ObjectMapper m = new ObjectMapper(); MapKeyBean result = m.readValue(" { \"values\" : { \"a\": true } } ", MapKeyBean.class); assertNotNull(result); Map<Object,Object> map = result.values; assertNotNull(map); assertEquals(1, map.size()); Map.Entry<Object,Object> en = map.entrySet().iterator().next(); assertEquals(String[].class, en.getKey().getClass()); assertEquals(Boolean.TRUE, en.getValue()); } // @since 1.8 public void testRootValueWithCustomKey() throws Exception { ObjectMapper m = new ObjectMapper(); MapKeyMap result = m.readValue(" { \"a\": 13 } ", MapKeyMap.class); assertNotNull(result); assertNotNull(result); assertEquals(1, result.size()); Map.Entry<Object,Object> en = result.entrySet().iterator().next(); assertEquals(ValueClass.class, en.getValue().getClass()); assertEquals(13, ((ValueClass) en.getValue())._a); assertEquals(String[].class, en.getKey().getClass()); } }