| package com.fasterxml.jackson.databind.deser.jdk; |
| |
| import java.io.IOException; |
| import java.util.*; |
| import java.util.concurrent.ArrayBlockingQueue; |
| |
| import com.fasterxml.jackson.core.*; |
| import com.fasterxml.jackson.core.type.TypeReference; |
| import com.fasterxml.jackson.databind.*; |
| import com.fasterxml.jackson.databind.annotation.JsonDeserialize; |
| import com.fasterxml.jackson.databind.deser.std.StdDeserializer; |
| |
| @SuppressWarnings("serial") |
| public class CollectionDeserTest |
| extends BaseMapTest |
| { |
| enum Key { |
| KEY1, KEY2, WHATEVER; |
| } |
| |
| @JsonDeserialize(using=ListDeserializer.class) |
| static class CustomList extends LinkedList<String> { } |
| |
| static class ListDeserializer extends StdDeserializer<CustomList> |
| { |
| public ListDeserializer() { super(CustomList.class); } |
| |
| @Override |
| public CustomList deserialize(JsonParser jp, DeserializationContext ctxt) |
| throws IOException |
| { |
| CustomList result = new CustomList(); |
| result.add(jp.getText()); |
| return result; |
| } |
| } |
| |
| static class XBean { |
| public int x; |
| |
| public XBean() { } |
| public XBean(int x) { this.x = x; } |
| } |
| |
| // [databind#199] |
| static class ListAsIterable { |
| public Iterable<String> values; |
| } |
| |
| // [databind#2251] |
| static class ListAsAbstract { |
| public AbstractList<String> values; |
| } |
| |
| static class SetAsAbstract { |
| public AbstractSet<String> values; |
| } |
| |
| static class ListAsIterableX { |
| public Iterable<XBean> nums; |
| } |
| |
| static class KeyListBean { |
| public List<Key> keys; |
| } |
| |
| // [Issue#828] |
| @JsonDeserialize(using=SomeObjectDeserializer.class) |
| static class SomeObject {} |
| |
| static class SomeObjectDeserializer extends StdDeserializer<SomeObject> { |
| public SomeObjectDeserializer() { super(SomeObject.class); } |
| |
| @Override |
| public SomeObject deserialize(JsonParser p, DeserializationContext ctxt) |
| throws IOException { |
| throw new RuntimeException("I want to catch this exception"); |
| } |
| } |
| |
| /* |
| /********************************************************** |
| /* Test methods |
| /********************************************************** |
| */ |
| |
| private final static ObjectMapper MAPPER = new ObjectMapper(); |
| |
| public void testUntypedList() throws Exception |
| { |
| // to get "untyped" default List, pass Object.class |
| String JSON = "[ \"text!\", true, null, 23 ]"; |
| |
| // Not a guaranteed cast theoretically, but will work: |
| // (since we know that Jackson will construct an ArrayList here...) |
| Object value = MAPPER.readValue(JSON, Object.class); |
| assertNotNull(value); |
| assertTrue(value instanceof ArrayList<?>); |
| List<?> result = (List<?>) value; |
| |
| assertEquals(4, result.size()); |
| |
| assertEquals("text!", result.get(0)); |
| assertEquals(Boolean.TRUE, result.get(1)); |
| assertNull(result.get(2)); |
| assertEquals(Integer.valueOf(23), result.get(3)); |
| } |
| |
| public void testExactStringCollection() throws Exception |
| { |
| // to get typing, must use type reference |
| String JSON = "[ \"a\", \"b\" ]"; |
| List<String> result = MAPPER.readValue(JSON, new TypeReference<ArrayList<String>>() { }); |
| |
| assertNotNull(result); |
| assertEquals(ArrayList.class, result.getClass()); |
| assertEquals(2, result.size()); |
| |
| assertEquals("a", result.get(0)); |
| assertEquals("b", result.get(1)); |
| } |
| |
| public void testHashSet() throws Exception |
| { |
| String JSON = "[ \"KEY1\", \"KEY2\" ]"; |
| |
| EnumSet<Key> result = MAPPER.readValue(JSON, new TypeReference<EnumSet<Key>>() { }); |
| assertNotNull(result); |
| assertTrue(EnumSet.class.isAssignableFrom(result.getClass())); |
| assertEquals(2, result.size()); |
| |
| assertTrue(result.contains(Key.KEY1)); |
| assertTrue(result.contains(Key.KEY2)); |
| assertFalse(result.contains(Key.WHATEVER)); |
| } |
| |
| /// Test to verify that @JsonDeserialize.using works as expected |
| public void testCustomDeserializer() throws IOException |
| { |
| CustomList result = MAPPER.readValue(quote("abc"), CustomList.class); |
| assertEquals(1, result.size()); |
| assertEquals("abc", result.get(0)); |
| } |
| |
| // Testing "implicit JSON array" for single-element arrays, |
| // mostly produced by Jettison, Badgerfish conversions (from XML) |
| @SuppressWarnings("unchecked") |
| public void testImplicitArrays() throws Exception |
| { |
| // can't share mapper, custom configs (could create ObjectWriter tho) |
| ObjectMapper mapper = new ObjectMapper(); |
| mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); |
| |
| // first with simple scalar types (numbers), with collections |
| List<Integer> ints = mapper.readValue("4", List.class); |
| assertEquals(1, ints.size()); |
| assertEquals(Integer.valueOf(4), ints.get(0)); |
| List<String> strings = mapper.readValue(quote("abc"), new TypeReference<ArrayList<String>>() { }); |
| assertEquals(1, strings.size()); |
| assertEquals("abc", strings.get(0)); |
| // and arrays: |
| int[] intArray = mapper.readValue("-7", int[].class); |
| assertEquals(1, intArray.length); |
| assertEquals(-7, intArray[0]); |
| String[] stringArray = mapper.readValue(quote("xyz"), String[].class); |
| assertEquals(1, stringArray.length); |
| assertEquals("xyz", stringArray[0]); |
| |
| // and then with Beans: |
| List<XBean> xbeanList = mapper.readValue("{\"x\":4}", new TypeReference<List<XBean>>() { }); |
| assertEquals(1, xbeanList.size()); |
| assertEquals(XBean.class, xbeanList.get(0).getClass()); |
| |
| Object ob = mapper.readValue("{\"x\":29}", XBean[].class); |
| XBean[] xbeanArray = (XBean[]) ob; |
| assertEquals(1, xbeanArray.length); |
| assertEquals(XBean.class, xbeanArray[0].getClass()); |
| } |
| |
| // [JACKSON-620]: allow "" to mean 'null' for Maps |
| public void testFromEmptyString() throws Exception |
| { |
| ObjectReader r = MAPPER.reader(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); |
| List<?> result = r.forType(List.class).readValue(quote("")); |
| assertNull(result); |
| } |
| |
| // [databind#161] |
| public void testArrayBlockingQueue() throws Exception |
| { |
| // ok to skip polymorphic type to get Object |
| ArrayBlockingQueue<?> q = MAPPER.readValue("[1, 2, 3]", ArrayBlockingQueue.class); |
| assertNotNull(q); |
| assertEquals(3, q.size()); |
| assertEquals(Integer.valueOf(1), q.take()); |
| assertEquals(Integer.valueOf(2), q.take()); |
| assertEquals(Integer.valueOf(3), q.take()); |
| } |
| |
| // [databind#199] |
| public void testIterableWithStrings() throws Exception |
| { |
| String JSON = "{ \"values\":[\"a\",\"b\"]}"; |
| ListAsIterable w = MAPPER.readValue(JSON, ListAsIterable.class); |
| assertNotNull(w); |
| assertNotNull(w.values); |
| Iterator<String> it = w.values.iterator(); |
| assertTrue(it.hasNext()); |
| assertEquals("a", it.next()); |
| assertEquals("b", it.next()); |
| assertFalse(it.hasNext()); |
| } |
| |
| public void testIterableWithBeans() throws Exception |
| { |
| String JSON = "{ \"nums\":[{\"x\":1},{\"x\":2}]}"; |
| ListAsIterableX w = MAPPER.readValue(JSON, ListAsIterableX.class); |
| assertNotNull(w); |
| assertNotNull(w.nums); |
| Iterator<XBean> it = w.nums.iterator(); |
| assertTrue(it.hasNext()); |
| XBean xb = it.next(); |
| assertNotNull(xb); |
| assertEquals(1, xb.x); |
| xb = it.next(); |
| assertEquals(2, xb.x); |
| assertFalse(it.hasNext()); |
| } |
| |
| // for [databind#506] |
| public void testArrayIndexForExceptions() throws Exception |
| { |
| final String OBJECTS_JSON = "[ \"KEY2\", false ]"; |
| try { |
| MAPPER.readValue(OBJECTS_JSON, Key[].class); |
| fail("Should not pass"); |
| } catch (JsonMappingException e) { |
| verifyException(e, "Cannot deserialize"); |
| List<JsonMappingException.Reference> refs = e.getPath(); |
| assertEquals(1, refs.size()); |
| assertEquals(1, refs.get(0).getIndex()); |
| } |
| |
| try { |
| MAPPER.readValue("[ \"xyz\", { } ]", String[].class); |
| fail("Should not pass"); |
| } catch (JsonMappingException e) { |
| verifyException(e, "Cannot deserialize"); |
| List<JsonMappingException.Reference> refs = e.getPath(); |
| assertEquals(1, refs.size()); |
| assertEquals(1, refs.get(0).getIndex()); |
| } |
| |
| try { |
| MAPPER.readValue("{\"keys\":"+OBJECTS_JSON+"}", KeyListBean.class); |
| fail("Should not pass"); |
| } catch (JsonMappingException e) { |
| verifyException(e, "Cannot deserialize"); |
| List<JsonMappingException.Reference> refs = e.getPath(); |
| assertEquals(2, refs.size()); |
| // Bean has no index, but has name: |
| assertEquals(-1, refs.get(0).getIndex()); |
| assertEquals("keys", refs.get(0).getFieldName()); |
| |
| // and for List, reverse: |
| assertEquals(1, refs.get(1).getIndex()); |
| assertNull(refs.get(1).getFieldName()); |
| } |
| } |
| |
| // for [databind#828] |
| public void testWrapExceptions() throws Exception |
| { |
| ObjectMapper mapper = new ObjectMapper(); |
| mapper.enable(DeserializationFeature.WRAP_EXCEPTIONS); |
| |
| try { |
| mapper.readValue("[{}]", new TypeReference<List<SomeObject>>() {}); |
| } catch (JsonMappingException exc) { |
| assertEquals("I want to catch this exception", exc.getOriginalMessage()); |
| } catch (RuntimeException exc) { |
| fail("The RuntimeException should have been wrapped with a JsonMappingException."); |
| } |
| |
| ObjectMapper mapperNoWrap = new ObjectMapper(); |
| mapperNoWrap.disable(DeserializationFeature.WRAP_EXCEPTIONS); |
| |
| try { |
| mapperNoWrap.readValue("[{}]", new TypeReference<List<SomeObject>>() {}); |
| } catch (JsonMappingException exc) { |
| fail("It should not have wrapped the RuntimeException."); |
| } catch (RuntimeException exc) { |
| assertEquals("I want to catch this exception", exc.getMessage()); |
| } |
| } |
| |
| // [databind#2251] |
| public void testAbstractListAndSet() throws Exception |
| { |
| final String JSON = "{\"values\":[\"foo\", \"bar\"]}"; |
| |
| ListAsAbstract list = MAPPER.readValue(JSON, ListAsAbstract.class); |
| assertEquals(2, list.values.size()); |
| assertEquals(ArrayList.class, list.values.getClass()); |
| |
| SetAsAbstract set = MAPPER.readValue(JSON, SetAsAbstract.class); |
| assertEquals(2, set.values.size()); |
| assertEquals(HashSet.class, set.values.getClass()); |
| } |
| } |