1 package com.fasterxml.jackson.databind.exc; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 7 import com.fasterxml.jackson.core.JsonParser; 8 import com.fasterxml.jackson.databind.*; 9 10 /** 11 * Unit tests for verifying that simple exceptions can be serialized. 12 */ 13 public class ExceptionSerializationTest 14 extends BaseMapTest 15 { 16 @SuppressWarnings("serial") 17 @JsonIgnoreProperties({ "bogus1" }) 18 static class ExceptionWithIgnoral extends RuntimeException 19 { 20 public int bogus1 = 3; 21 22 public int bogus2 = 5; 23 ExceptionWithIgnoral()24 protected ExceptionWithIgnoral() { } ExceptionWithIgnoral(String msg)25 public ExceptionWithIgnoral(String msg) { 26 super(msg); 27 } 28 } 29 30 // [databind#1368] 31 static class NoSerdeConstructor { 32 private String strVal; getVal()33 public String getVal() { return strVal; } NoSerdeConstructor( String strVal )34 public NoSerdeConstructor( String strVal ) { 35 this.strVal = strVal; 36 } 37 } 38 39 /* 40 /********************************************************** 41 /* Tests 42 /********************************************************** 43 */ 44 45 private final ObjectMapper MAPPER = new ObjectMapper(); 46 testSimple()47 public void testSimple() throws Exception 48 { 49 String TEST = "test exception"; 50 Map<String,Object> result = writeAndMap(MAPPER, new Exception(TEST)); 51 // JDK 7 has introduced a new property 'suppressed' to Throwable 52 Object ob = result.get("suppressed"); 53 if (ob != null) { 54 assertEquals(5, result.size()); 55 } else { 56 assertEquals(4, result.size()); 57 } 58 59 assertEquals(TEST, result.get("message")); 60 assertNull(result.get("cause")); 61 assertEquals(TEST, result.get("localizedMessage")); 62 63 // hmmh. what should we get for stack traces? 64 Object traces = result.get("stackTrace"); 65 if (!(traces instanceof List<?>)) { 66 fail("Expected a List for exception member 'stackTrace', got: "+traces); 67 } 68 } 69 70 // to double-check [databind#1413] testSimpleOther()71 public void testSimpleOther() throws Exception 72 { 73 JsonParser p = MAPPER.createParser("{ }"); 74 InvalidFormatException exc = InvalidFormatException.from(p, "Test", getClass(), String.class); 75 String json = MAPPER.writeValueAsString(exc); 76 p.close(); 77 assertNotNull(json); 78 } 79 80 // for [databind#877] 81 @SuppressWarnings("unchecked") testIgnorals()82 public void testIgnorals() throws Exception 83 { 84 ExceptionWithIgnoral input = new ExceptionWithIgnoral("foobar"); 85 input.initCause(new IOException("surprise!")); 86 87 // First, should ignore anything with class annotations 88 String json = MAPPER 89 .writerWithDefaultPrettyPrinter() 90 .writeValueAsString(input); 91 92 Map<String,Object> result = MAPPER.readValue(json, Map.class); 93 assertEquals("foobar", result.get("message")); 94 95 assertNull(result.get("bogus1")); 96 assertNotNull(result.get("bogus2")); 97 98 // and then also remova second property with config overrides 99 ObjectMapper mapper = new ObjectMapper(); 100 mapper.configOverride(ExceptionWithIgnoral.class) 101 .setIgnorals(JsonIgnoreProperties.Value.forIgnoredProperties("bogus2")); 102 String json2 = mapper 103 .writeValueAsString(new ExceptionWithIgnoral("foobar")); 104 105 Map<String,Object> result2 = mapper.readValue(json2, Map.class); 106 assertNull(result2.get("bogus1")); 107 assertNull(result2.get("bogus2")); 108 109 // and try to deserialize as well 110 ExceptionWithIgnoral output = mapper.readValue(json2, ExceptionWithIgnoral.class); 111 assertNotNull(output); 112 assertEquals("foobar", output.getMessage()); 113 } 114 115 // [databind#1368] testJsonMappingExceptionSerialization()116 public void testJsonMappingExceptionSerialization() throws IOException { 117 Exception e = null; 118 // cant deserialize due to unexpected constructor 119 try { 120 MAPPER.readValue( "{ \"val\": \"foo\" }", NoSerdeConstructor.class ); 121 fail("Should not pass"); 122 } catch (JsonMappingException e0) { 123 verifyException(e0, "cannot deserialize from Object"); 124 e = e0; 125 } 126 // but should be able to serialize new exception we got 127 String json = MAPPER.writeValueAsString(e); 128 JsonNode root = MAPPER.readTree(json); 129 String msg = root.path("message").asText(); 130 String MATCH = "cannot construct instance"; 131 if (!msg.toLowerCase().contains(MATCH)) { 132 fail("Exception should contain '"+MATCH+"', does not: '"+msg+"'"); 133 } 134 } 135 } 136