| package com.fasterxml.jackson.databind.deser; |
| |
| import java.io.*; |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.net.URL; |
| import java.net.URI; |
| import java.util.*; |
| |
| import org.junit.Assert; |
| |
| import com.fasterxml.jackson.core.*; |
| import com.fasterxml.jackson.databind.*; |
| import com.fasterxml.jackson.databind.util.TokenBuffer; |
| |
| /** |
| * Unit tests for verifying handling of simple basic non-structured |
| * types; primitives (and/or their wrappers), Strings. |
| */ |
| public class TestSimpleTypes |
| extends BaseMapTest |
| { |
| final static String NAN_STRING = "NaN"; |
| |
| final static class BooleanBean { |
| boolean _v; |
| void setV(boolean v) { _v = v; } |
| } |
| |
| static class IntBean { |
| int _v; |
| void setV(int v) { _v = v; } |
| } |
| |
| final static class DoubleBean { |
| double _v; |
| void setV(double v) { _v = v; } |
| } |
| |
| final static class FloatBean { |
| float _v; |
| void setV(float v) { _v = v; } |
| } |
| |
| /** |
| * Also, let's ensure that it's ok to override methods. |
| */ |
| static class IntBean2 |
| extends IntBean |
| { |
| @Override |
| void setV(int v2) { super.setV(v2+1); } |
| } |
| |
| /* |
| /********************************************************** |
| /* Then tests for primitives |
| /********************************************************** |
| */ |
| |
| private final ObjectMapper MAPPER = new ObjectMapper(); |
| |
| public void testBooleanPrimitive() throws Exception |
| { |
| // first, simple case: |
| BooleanBean result = MAPPER.readValue(new StringReader("{\"v\":true}"), BooleanBean.class); |
| assertTrue(result._v); |
| // then [JACKSON-79]: |
| result = MAPPER.readValue(new StringReader("{\"v\":null}"), BooleanBean.class); |
| assertNotNull(result); |
| assertFalse(result._v); |
| |
| // should work with arrays too.. |
| boolean[] array = MAPPER.readValue(new StringReader("[ null ]"), boolean[].class); |
| assertNotNull(array); |
| assertEquals(1, array.length); |
| assertFalse(array[0]); |
| } |
| |
| public void testIntPrimitive() throws Exception |
| { |
| // first, simple case: |
| IntBean result = MAPPER.readValue(new StringReader("{\"v\":3}"), IntBean.class); |
| assertEquals(3, result._v); |
| // then [JACKSON-79]: |
| result = MAPPER.readValue(new StringReader("{\"v\":null}"), IntBean.class); |
| assertNotNull(result); |
| assertEquals(0, result._v); |
| |
| // should work with arrays too.. |
| int[] array = MAPPER.readValue(new StringReader("[ null ]"), int[].class); |
| assertNotNull(array); |
| assertEquals(1, array.length); |
| assertEquals(0, array[0]); |
| } |
| |
| public void testDoublePrimitive() throws Exception |
| { |
| // first, simple case: |
| // bit tricky with binary fps but... |
| double value = 0.016; |
| DoubleBean result = MAPPER.readValue(new StringReader("{\"v\":"+value+"}"), DoubleBean.class); |
| assertEquals(value, result._v); |
| // then [JACKSON-79]: |
| result = MAPPER.readValue(new StringReader("{\"v\":null}"), DoubleBean.class); |
| assertNotNull(result); |
| assertEquals(0.0, result._v); |
| |
| // should work with arrays too.. |
| double[] array = MAPPER.readValue(new StringReader("[ null ]"), double[].class); |
| assertNotNull(array); |
| assertEquals(1, array.length); |
| assertEquals(0.0, array[0]); |
| } |
| |
| public void testDoublePrimitiveNonNumeric() throws Exception |
| { |
| // first, simple case: |
| // bit tricky with binary fps but... |
| double value = Double.POSITIVE_INFINITY; |
| DoubleBean result = MAPPER.readValue(new StringReader("{\"v\":\""+value+"\"}"), DoubleBean.class); |
| assertEquals(value, result._v); |
| |
| // should work with arrays too.. |
| double[] array = MAPPER.readValue(new StringReader("[ \"Infinity\" ]"), double[].class); |
| assertNotNull(array); |
| assertEquals(1, array.length); |
| assertEquals(Double.POSITIVE_INFINITY, array[0]); |
| } |
| |
| public void testFloatPrimitiveNonNumeric() throws Exception |
| { |
| // bit tricky with binary fps but... |
| float value = Float.POSITIVE_INFINITY; |
| FloatBean result = MAPPER.readValue(new StringReader("{\"v\":\""+value+"\"}"), FloatBean.class); |
| assertEquals(value, result._v); |
| |
| // should work with arrays too.. |
| float[] array = MAPPER.readValue(new StringReader("[ \"Infinity\" ]"), float[].class); |
| assertNotNull(array); |
| assertEquals(1, array.length); |
| assertEquals(Float.POSITIVE_INFINITY, array[0]); |
| } |
| |
| /** |
| * Beyond simple case, let's also ensure that method overriding works as |
| * expected. |
| */ |
| public void testIntWithOverride() throws Exception |
| { |
| IntBean2 result = MAPPER.readValue(new StringReader("{\"v\":8}"), IntBean2.class); |
| assertEquals(9, result._v); |
| } |
| |
| /* |
| /********************************************************** |
| /* Then tests for wrappers |
| /********************************************************** |
| */ |
| |
| /** |
| * Simple unit test to verify that we can map boolean values to |
| * java.lang.Boolean. |
| */ |
| public void testBooleanWrapper() throws Exception |
| { |
| Boolean result = MAPPER.readValue(new StringReader("true"), Boolean.class); |
| assertEquals(Boolean.TRUE, result); |
| result = MAPPER.readValue(new StringReader("false"), Boolean.class); |
| assertEquals(Boolean.FALSE, result); |
| |
| // [JACKSON-78]: should accept ints too, (0 == false, otherwise true) |
| result = MAPPER.readValue(new StringReader("0"), Boolean.class); |
| assertEquals(Boolean.FALSE, result); |
| result = MAPPER.readValue(new StringReader("1"), Boolean.class); |
| assertEquals(Boolean.TRUE, result); |
| } |
| |
| public void testByteWrapper() throws Exception |
| { |
| Byte result = MAPPER.readValue(new StringReader(" -42\t"), Byte.class); |
| assertEquals(Byte.valueOf((byte)-42), result); |
| |
| // Also: should be able to coerce floats, strings: |
| result = MAPPER.readValue(new StringReader(" \"-12\""), Byte.class); |
| assertEquals(Byte.valueOf((byte)-12), result); |
| |
| result = MAPPER.readValue(new StringReader(" 39.07"), Byte.class); |
| assertEquals(Byte.valueOf((byte)39), result); |
| } |
| |
| public void testShortWrapper() throws Exception |
| { |
| Short result = MAPPER.readValue(new StringReader("37"), Short.class); |
| assertEquals(Short.valueOf((short)37), result); |
| |
| // Also: should be able to coerce floats, strings: |
| result = MAPPER.readValue(new StringReader(" \"-1009\""), Short.class); |
| assertEquals(Short.valueOf((short)-1009), result); |
| |
| result = MAPPER.readValue(new StringReader("-12.9"), Short.class); |
| assertEquals(Short.valueOf((short)-12), result); |
| } |
| |
| public void testCharacterWrapper() throws Exception |
| { |
| // First: canonical value is 1-char string |
| Character result = MAPPER.readValue(new StringReader("\"a\""), Character.class); |
| assertEquals(Character.valueOf('a'), result); |
| |
| // But can also pass in ascii code |
| result = MAPPER.readValue(new StringReader(" "+((int) 'X')), Character.class); |
| assertEquals(Character.valueOf('X'), result); |
| } |
| |
| public void testIntWrapper() throws Exception |
| { |
| Integer result = MAPPER.readValue(new StringReader(" -42\t"), Integer.class); |
| assertEquals(Integer.valueOf(-42), result); |
| |
| // Also: should be able to coerce floats, strings: |
| result = MAPPER.readValue(new StringReader(" \"-1200\""), Integer.class); |
| assertEquals(Integer.valueOf(-1200), result); |
| |
| result = MAPPER.readValue(new StringReader(" 39.07"), Integer.class); |
| assertEquals(Integer.valueOf(39), result); |
| } |
| |
| public void testLongWrapper() throws Exception |
| { |
| Long result = MAPPER.readValue(new StringReader("12345678901"), Long.class); |
| assertEquals(Long.valueOf(12345678901L), result); |
| |
| // Also: should be able to coerce floats, strings: |
| result = MAPPER.readValue(new StringReader(" \"-9876\""), Long.class); |
| assertEquals(Long.valueOf(-9876), result); |
| |
| result = MAPPER.readValue(new StringReader("1918.3"), Long.class); |
| assertEquals(Long.valueOf(1918), result); |
| } |
| |
| /* Note: dealing with floating-point values is tricky; not sure if |
| * we can really use equality tests here... JDK does have decent |
| * conversions though, to retain accuracy and round-trippability. |
| * But still... |
| */ |
| public void testFloatWrapper() throws Exception |
| { |
| // Also: should be able to coerce floats, strings: |
| String[] STRS = new String[] { |
| "1.0", "0.0", "-0.3", "0.7", "42.012", "-999.0", NAN_STRING |
| }; |
| |
| for (String str : STRS) { |
| Float exp = Float.valueOf(str); |
| Float result; |
| |
| if (NAN_STRING != str) { |
| // First, as regular floating point value |
| result = MAPPER.readValue(new StringReader(str), Float.class); |
| assertEquals(exp, result); |
| } |
| |
| // and then as coerced String: |
| result = MAPPER.readValue(new StringReader(" \""+str+"\""), Float.class); |
| assertEquals(exp, result); |
| } |
| } |
| |
| public void testDoubleWrapper() throws Exception |
| { |
| // Also: should be able to coerce doubles, strings: |
| String[] STRS = new String[] { |
| "1.0", "0.0", "-0.3", "0.7", "42.012", "-999.0", NAN_STRING |
| }; |
| |
| for (String str : STRS) { |
| Double exp = Double.valueOf(str); |
| Double result; |
| |
| // First, as regular double value |
| if (NAN_STRING != str) { |
| result = MAPPER.readValue(new StringReader(str), Double.class); |
| assertEquals(exp, result); |
| } |
| // and then as coerced String: |
| result = MAPPER.readValue(new StringReader(" \""+str+"\""), Double.class); |
| assertEquals(exp, result); |
| } |
| } |
| |
| // as per [Issue#42], allow Base64 variant use as well |
| public void testBase64Variants() throws Exception |
| { |
| final byte[] INPUT = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890X".getBytes("UTF-8"); |
| |
| // default encoding is "MIME, no linefeeds", so: |
| Assert.assertArrayEquals(INPUT, MAPPER.readValue( |
| quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA=="), |
| byte[].class)); |
| ObjectReader reader = MAPPER.reader(byte[].class); |
| Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MIME_NO_LINEFEEDS).readValue( |
| quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA==" |
| ))); |
| |
| // but others should be slightly different |
| Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MIME).readValue( |
| quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1\\ndnd4eXoxMjM0NTY3ODkwWA==" |
| ))); |
| Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.MODIFIED_FOR_URL).readValue( |
| quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA" |
| ))); |
| // PEM mandates 64 char lines: |
| Assert.assertArrayEquals(INPUT, (byte[]) reader.with(Base64Variants.PEM).readValue( |
| quote("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwYWJjZGVmZ2hpamts\\nbW5vcHFyc3R1dnd4eXoxMjM0NTY3ODkwWA==" |
| ))); |
| } |
| /* |
| /********************************************************** |
| /* Simple non-primitive types |
| /********************************************************** |
| */ |
| |
| public void testSingleString() throws Exception |
| { |
| String value = "FOO!"; |
| String result = MAPPER.readValue(new StringReader("\""+value+"\""), String.class); |
| assertEquals(value, result); |
| } |
| |
| public void testNull() throws Exception |
| { |
| // null doesn't really have a type, fake by assuming Object |
| Object result = MAPPER.readValue(" null", Object.class); |
| assertNull(result); |
| } |
| |
| public void testClass() throws Exception |
| { |
| Class<?> result = MAPPER.readValue("\"java.lang.String\"", Class.class); |
| assertEquals(String.class, result); |
| } |
| |
| public void testBigDecimal() throws Exception |
| { |
| BigDecimal value = new BigDecimal("0.001"); |
| BigDecimal result = MAPPER.readValue(new StringReader(value.toString()), BigDecimal.class); |
| assertEquals(value, result); |
| } |
| |
| public void testBigInteger() throws Exception |
| { |
| BigInteger value = new BigInteger("-1234567890123456789012345567809"); |
| BigInteger result = MAPPER.readValue(new StringReader(value.toString()), BigInteger.class); |
| assertEquals(value, result); |
| } |
| |
| public void testUUID() throws Exception |
| { |
| UUID value = UUID.fromString("76e6d183-5f68-4afa-b94a-922c1fdb83f8"); |
| assertEquals(value, MAPPER.readValue("\""+value.toString()+"\"", UUID.class)); |
| |
| // [JACKSON-393] fix: |
| |
| // first, null should come as null |
| TokenBuffer buf = new TokenBuffer(null, false); |
| buf.writeObject(null); |
| assertNull(MAPPER.readValue(buf.asParser(), UUID.class)); |
| buf.close(); |
| |
| // then, UUID itself come as is: |
| buf = new TokenBuffer(null, false); |
| buf.writeObject(value); |
| assertSame(value, MAPPER.readValue(buf.asParser(), UUID.class)); |
| |
| // and finally from byte[] |
| // oh crap; JDK UUID just... sucks. Not even byte[] accessors or constructors? Huh? |
| ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| DataOutputStream out = new DataOutputStream(bytes); |
| out.writeLong(value.getMostSignificantBits()); |
| out.writeLong(value.getLeastSignificantBits()); |
| byte[] data = bytes.toByteArray(); |
| assertEquals(16, data.length); |
| |
| buf.writeObject(data); |
| |
| UUID value2 = MAPPER.readValue(buf.asParser(), UUID.class); |
| |
| assertEquals(value, value2); |
| buf.close(); |
| } |
| |
| public void testURL() throws Exception |
| { |
| URL value = new URL("http://foo.com"); |
| assertEquals(value, MAPPER.readValue("\""+value.toString()+"\"", URL.class)); |
| |
| // trivial case; null to null, embedded URL to URL |
| TokenBuffer buf = new TokenBuffer(null, false); |
| buf.writeObject(null); |
| assertNull(MAPPER.readValue(buf.asParser(), URL.class)); |
| buf.close(); |
| |
| // then, UUID itself come as is: |
| buf = new TokenBuffer(null, false); |
| buf.writeObject(value); |
| assertSame(value, MAPPER.readValue(buf.asParser(), URL.class)); |
| buf.close(); |
| } |
| |
| public void testURI() throws Exception |
| { |
| URI value = new URI("http://foo.com"); |
| assertEquals(value, MAPPER.readValue("\""+value.toString()+"\"", URI.class)); |
| } |
| |
| /* |
| /********************************************************** |
| /* Sequence tests |
| /********************************************************** |
| */ |
| |
| /** |
| * Then a unit test to verify that we can conveniently bind sequence of |
| * space-separate simple values |
| */ |
| public void testSequenceOfInts() throws Exception |
| { |
| final int NR_OF_INTS = 100; |
| |
| StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < NR_OF_INTS; ++i) { |
| sb.append(" "); |
| sb.append(i); |
| } |
| JsonParser jp = MAPPER.getFactory().createParser(sb.toString()); |
| for (int i = 0; i < NR_OF_INTS; ++i) { |
| Integer result = MAPPER.readValue(jp, Integer.class); |
| assertEquals(Integer.valueOf(i), result); |
| } |
| jp.close(); |
| } |
| } |
| |