1 package com.fasterxml.jackson.databind.exc;
2 
3 import java.io.IOException;
4 import java.util.*;
5 
6 import com.fasterxml.jackson.annotation.*;
7 
8 import com.fasterxml.jackson.databind.*;
9 
10 /**
11  * Unit tests for verifying that simple exceptions can be deserialized.
12  */
13 public class ExceptionDeserializationTest
14     extends BaseMapTest
15 {
16     @SuppressWarnings("serial")
17     static class MyException extends Exception
18     {
19         protected int value;
20 
21         protected String myMessage;
22         protected HashMap<String,Object> stuff = new HashMap<String, Object>();
23 
24         @JsonCreator
MyException(@sonProperty"message") String msg, @JsonProperty("value") int v)25         MyException(@JsonProperty("message") String msg, @JsonProperty("value") int v)
26         {
27             super(msg);
28             myMessage = msg;
29             value = v;
30         }
31 
getValue()32         public int getValue() { return value; }
33 
getFoo()34         public String getFoo() { return "bar"; }
35 
setter(String key, Object value)36         @JsonAnySetter public void setter(String key, Object value)
37         {
38             stuff.put(key, value);
39         }
40     }
41 
42     @SuppressWarnings("serial")
43     static class MyNoArgException extends Exception
44     {
MyNoArgException()45         @JsonCreator MyNoArgException() { }
46     }
47 
48     /*
49     /**********************************************************
50     /* Tests
51     /**********************************************************
52      */
53 
54     private final ObjectMapper MAPPER = new ObjectMapper();
55 
testIOException()56     public void testIOException() throws IOException
57     {
58         IOException ioe = new IOException("TEST");
59         String json = MAPPER.writeValueAsString(ioe);
60         IOException result = MAPPER.readValue(json, IOException.class);
61         assertEquals(ioe.getMessage(), result.getMessage());
62     }
63 
testWithCreator()64     public void testWithCreator() throws IOException
65     {
66         final String MSG = "the message";
67         String json = MAPPER.writeValueAsString(new MyException(MSG, 3));
68 
69         MyException result = MAPPER.readValue(json, MyException.class);
70         assertEquals(MSG, result.getMessage());
71         assertEquals(3, result.value);
72         assertEquals(1, result.stuff.size());
73         assertEquals(result.getFoo(), result.stuff.get("foo"));
74     }
75 
testWithNullMessage()76     public void testWithNullMessage() throws IOException
77     {
78         final ObjectMapper mapper = new ObjectMapper();
79         mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
80         String json = mapper.writeValueAsString(new IOException((String) null));
81         IOException result = mapper.readValue(json, IOException.class);
82         assertNotNull(result);
83         assertNull(result.getMessage());
84     }
85 
testNoArgsException()86     public void testNoArgsException() throws IOException
87     {
88         MyNoArgException exc = MAPPER.readValue("{}", MyNoArgException.class);
89         assertNotNull(exc);
90     }
91 
92     // try simulating JDK 7 behavior
testJDK7SuppressionProperty()93     public void testJDK7SuppressionProperty() throws IOException
94     {
95         Exception exc = MAPPER.readValue("{\"suppressed\":[]}", IOException.class);
96         assertNotNull(exc);
97     }
98 
99     // [databind#381]
testSingleValueArrayDeserialization()100     public void testSingleValueArrayDeserialization() throws Exception {
101         final ObjectMapper mapper = new ObjectMapper();
102         mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
103         final IOException exp;
104         try {
105             throw new IOException("testing");
106         } catch (IOException internal) {
107             exp = internal;
108         }
109         final String value = "[" + mapper.writeValueAsString(exp) + "]";
110 
111         final IOException cloned = mapper.readValue(value, IOException.class);
112         assertEquals(exp.getMessage(), cloned.getMessage());
113 
114         assertEquals(exp.getStackTrace().length, cloned.getStackTrace().length);
115         for (int i = 0; i < exp.getStackTrace().length; i ++) {
116             _assertEquality(i, exp.getStackTrace()[i], cloned.getStackTrace()[i]);
117         }
118     }
119 
_assertEquality(int ix, StackTraceElement exp, StackTraceElement act)120     protected void _assertEquality(int ix, StackTraceElement exp, StackTraceElement act)
121     {
122         _assertEquality(ix, "className", exp.getClassName(), act.getClassName());
123         _assertEquality(ix, "methodName", exp.getMethodName(), act.getMethodName());
124         _assertEquality(ix, "fileName", exp.getFileName(), act.getFileName());
125         _assertEquality(ix, "lineNumber", exp.getLineNumber(), act.getLineNumber());
126     }
127 
_assertEquality(int ix, String prop, Object exp, Object act)128     protected void _assertEquality(int ix, String prop,
129             Object exp, Object act)
130     {
131         if (exp == null) {
132             if (act == null) {
133                 return;
134             }
135         } else {
136             if (exp.equals(act)) {
137                 return;
138             }
139         }
140         fail(String.format("StackTraceElement #%d, property '%s' differs: expected %s, actual %s",
141                 ix, prop, exp, act));
142     }
143 
testSingleValueArrayDeserializationException()144     public void testSingleValueArrayDeserializationException() throws Exception {
145         final ObjectMapper mapper = new ObjectMapper();
146         mapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
147 
148         final IOException exp;
149         try {
150             throw new IOException("testing");
151         } catch (IOException internal) {
152             exp = internal;
153         }
154         final String value = "[" + mapper.writeValueAsString(exp) + "]";
155 
156         try {
157             mapper.readValue(value, IOException.class);
158             fail("Exception not thrown when attempting to deserialize an IOException wrapped in a single value array with UNWRAP_SINGLE_VALUE_ARRAYS disabled");
159         } catch (JsonMappingException exp2) {
160             verifyException(exp2, "from Array value (token `JsonToken.START_ARRAY`)");
161         }
162     }
163 
164     // mostly to help with XML module (and perhaps CSV)
testLineNumberAsString()165     public void testLineNumberAsString() throws IOException
166     {
167         Exception exc = MAPPER.readValue(aposToQuotes(
168                 "{'message':'Test',\n'stackTrace': "
169                 +"[ { 'lineNumber':'50' } ] }"
170         ), IOException.class);
171         assertNotNull(exc);
172     }
173 
174     // [databind#1842]:
testNullAsMessage()175     public void testNullAsMessage() throws IOException
176     {
177         Exception exc = MAPPER.readValue(aposToQuotes(
178                 "{'message':null, 'localizedMessage':null }"
179         ), IOException.class);
180         assertNotNull(exc);
181         assertNull(exc.getMessage());
182         assertNull(exc.getLocalizedMessage());
183     }
184 }
185