| 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()); |
| } |
| |
| } |