• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.convert;
2 
3 import java.math.*;
4 import java.util.*;
5 import java.lang.reflect.Array;
6 
7 
8 import com.fasterxml.jackson.core.type.TypeReference;
9 import com.fasterxml.jackson.databind.*;
10 
11 public class TestArrayConversions
12     extends com.fasterxml.jackson.databind.BaseMapTest
13 {
14     final static String OVERFLOW_MSG_BYTE = "out of range of Java byte";
15     final static String OVERFLOW_MSG_SHORT = "out of range of Java short";
16 
17     final static String OVERFLOW_MSG_INT = "out of range of int";
18     final static String OVERFLOW_MSG_LONG = "out of range of long";
19 
20     final ObjectMapper MAPPER = new ObjectMapper();
21 
testNullXform()22     public void testNullXform() throws Exception
23     {
24         /* when given null, null should be returned without conversion
25          * (Java null has no type)
26          */
27         assertNull(MAPPER.convertValue(null, Integer.class));
28         assertNull(MAPPER.convertValue(null, String.class));
29         assertNull(MAPPER.convertValue(null, byte[].class));
30     }
31 
32     /**
33      * Tests to verify that primitive number arrays round-trip
34      * correctly, i.e. type -> type gives equal (although
35      * not necessarily same) output
36      */
testArrayIdentityTransforms()37     public void testArrayIdentityTransforms() throws Exception
38     {
39         // first integral types
40         // (note: byte[] is ok, even if it goes to base64 and back)
41         verifyByteArrayConversion(bytes(), byte[].class);
42         verifyShortArrayConversion(shorts(), short[].class);
43         verifyIntArrayConversion(ints(), int[].class);
44         verifyLongArrayConversion(longs(), long[].class);
45         // then primitive decimal types
46         verifyFloatArrayConversion(floats(), float[].class);
47         verifyDoubleArrayConversion(doubles(), float[].class);
48     }
49 
testByteArrayFrom()50     public void testByteArrayFrom() throws Exception
51     {
52         /* Note: byte arrays are tricky, since they are considered
53          * binary data primarily, not as array of numbers. Hence
54          * output will be base64 encoded...
55          */
56         byte[] data = _convert("c3VyZS4=", byte[].class);
57         byte[] exp = "sure.".getBytes("Ascii");
58         verifyIntegralArrays(exp, data, exp.length);
59     }
60 
testShortArrayToX()61     public void testShortArrayToX() throws Exception
62     {
63         short[] data = shorts();
64         verifyShortArrayConversion(data, byte[].class);
65         verifyShortArrayConversion(data, int[].class);
66         verifyShortArrayConversion(data, long[].class);
67     }
68 
testIntArrayToX()69     public void testIntArrayToX() throws Exception
70     {
71         int[] data = ints();
72         verifyIntArrayConversion(data, byte[].class);
73         verifyIntArrayConversion(data, short[].class);
74         verifyIntArrayConversion(data, long[].class);
75 
76         List<Number> expNums = _numberList(data, data.length);
77         // Alas, due to type erasure, need to use TypeRef, not just class
78         List<Integer> actNums = MAPPER.convertValue(data, new TypeReference<List<Integer>>() {});
79         assertEquals(expNums, actNums);
80     }
81 
testLongArrayToX()82     public void testLongArrayToX() throws Exception
83     {
84         long[] data = longs();
85         verifyLongArrayConversion(data, byte[].class);
86         verifyLongArrayConversion(data, short[].class);
87         verifyLongArrayConversion(data, int[].class);
88 
89         List<Number> expNums = _numberList(data, data.length);
90         List<Long> actNums = MAPPER.convertValue(data, new TypeReference<List<Long>>() {});
91         assertEquals(expNums, actNums);
92     }
93 
testOverflows()94     public void testOverflows()
95     {
96         // Byte overflow
97         try {
98             MAPPER.convertValue(new int[] { 1000 }, byte[].class);
99         } catch (IllegalArgumentException e) {
100             verifyException(e, OVERFLOW_MSG_BYTE);
101         }
102         // Short overflow
103         try {
104             MAPPER.convertValue(new int[] { -99999 }, short[].class);
105         } catch (IllegalArgumentException e) {
106             verifyException(e, OVERFLOW_MSG_SHORT);
107         }
108         // Int overflow
109         try {
110             MAPPER.convertValue(new long[] { Long.MAX_VALUE }, int[].class);
111         } catch (IllegalArgumentException e) {
112             verifyException(e, OVERFLOW_MSG_INT);
113         }
114         // Longs need help of BigInteger...
115         BigInteger biggie = BigInteger.valueOf(Long.MAX_VALUE);
116         biggie.add(BigInteger.ONE);
117         List<BigInteger> l = new ArrayList<BigInteger>();
118         l.add(biggie);
119         try {
120             MAPPER.convertValue(l, long[].class);
121         } catch (IllegalArgumentException e) {
122             verifyException(e, OVERFLOW_MSG_LONG);
123         }
124     }
125 
126     /*
127     /********************************************************
128     /* Helper methods
129     /********************************************************
130      */
131 
132     // note: all value need to be within byte range
133 
bytes()134     private byte[] bytes() { return new byte[] { 1, -1, 0, 98, 127 }; }
shorts()135     private short[] shorts() { return new short[] { 1, -1, 0, 98, 127 }; }
ints()136     private int[] ints() { return new int[] { 1, -1, 0, 98, 127 }; }
longs()137     private long[] longs() { return new long[] { 1, -1, 0, 98, 127 }; }
138 
139     // note: use values that are exact in binary
140 
doubles()141     private double[] doubles() { return new double[] { 0.0, 0.25, -0.125, 10.5, 9875.0 }; }
floats()142     private float[] floats() { return new float[] {
143             0.0f, 0.25f, -0.125f, 10.5f, 9875.0f };
144     }
145 
verifyByteArrayConversion(byte[] data, Class<T> arrayType)146     private <T> void verifyByteArrayConversion(byte[] data, Class<T> arrayType) {
147         T result = _convert(data, arrayType);
148         verifyIntegralArrays(data, result, data.length);
149     }
verifyShortArrayConversion(short[] data, Class<T> arrayType)150     private <T> void verifyShortArrayConversion(short[] data, Class<T> arrayType) {
151         T result = _convert(data, arrayType);
152         verifyIntegralArrays(data, result, data.length);
153     }
verifyIntArrayConversion(int[] data, Class<T> arrayType)154     private <T> void verifyIntArrayConversion(int[] data, Class<T> arrayType) {
155         T result = _convert(data, arrayType);
156         verifyIntegralArrays(data, result, data.length);
157     }
verifyLongArrayConversion(long[] data, Class<T> arrayType)158     private <T> void verifyLongArrayConversion(long[] data, Class<T> arrayType) {
159         T result = _convert(data, arrayType);
160         verifyIntegralArrays(data, result, data.length);
161     }
verifyFloatArrayConversion(float[] data, Class<T> arrayType)162     private <T> void verifyFloatArrayConversion(float[] data, Class<T> arrayType) {
163         T result = _convert(data, arrayType);
164         verifyDoubleArrays(data, result, data.length);
165     }
verifyDoubleArrayConversion(double[] data, Class<T> arrayType)166     private <T> void verifyDoubleArrayConversion(double[] data, Class<T> arrayType) {
167         T result = _convert(data, arrayType);
168         verifyDoubleArrays(data, result, data.length);
169     }
170 
_convert(Object input, Class<T> outputType)171     private <T> T _convert(Object input, Class<T> outputType)
172     {
173         // must be a primitive array, like "int[].class"
174         if (!outputType.isArray()) throw new IllegalArgumentException();
175         if (!outputType.getComponentType().isPrimitive()) throw new IllegalArgumentException();
176         T result = MAPPER.convertValue(input, outputType);
177         // sanity check first:
178         assertNotNull(result);
179         assertEquals(outputType, result.getClass());
180         return result;
181     }
182 
_numberList(Object numberArray, int size)183     private List<Number> _numberList(Object numberArray, int size)
184     {
185         ArrayList<Number> result = new ArrayList<Number>(size);
186         for (int i = 0; i < size; ++i) {
187             result.add((Number) Array.get(numberArray, i));
188         }
189         return result;
190     }
191 
192     /**
193      * Helper method for checking that given collections contain integral Numbers
194      * that essentially contain same values in same order
195      */
verifyIntegralArrays(Object inputArray, Object outputArray, int size)196     private void verifyIntegralArrays(Object inputArray, Object outputArray, int size)
197     {
198         for (int i = 0; i < size; ++i) {
199             Number n1 = (Number) Array.get(inputArray, i);
200             Number n2 = (Number) Array.get(outputArray, i);
201             double value1 = n1.longValue();
202             double value2 = n2.longValue();
203             assertEquals("Entry #"+i+"/"+size+" not equal", value1, value2);
204         }
205     }
206 
verifyDoubleArrays(Object inputArray, Object outputArray, int size)207     private void verifyDoubleArrays(Object inputArray, Object outputArray, int size)
208     {
209         for (int i = 0; i < size; ++i) {
210             Number n1 = (Number) Array.get(inputArray, i);
211             Number n2 = (Number) Array.get(outputArray, i);
212             double value1 = n1.doubleValue();
213             double value2 = n2.doubleValue();
214             assertEquals("Entry #"+i+"/"+size+" not equal", value1, value2);
215         }
216     }
217 }
218