Hank
Hank

Reputation: 4716

jackson: deserialize a custom exception

I am trying to get Jackson to deserialize a JSON-encoded custom exception, and it fails if the exception disables the stacktrace.

Working example:

public static class CustomException extends Exception {
    public CustomException(String msg) {
        super(msg);
    }
}

@Test
public void testSerializeAndDeserializeCustomException() throws Exception {
    log.info("Test: testSerializeAndDeserializeCustomException");

    CustomException ex1 = new CustomException("boom");
    ObjectMapper om = new ObjectMapper();

    String json = om.writerFor(CustomException.class).writeValueAsString(ex1);
    assertNotNull(json);
    log.info("JSON: {}", json);

    CustomException ex2 = om.readerFor(CustomException.class).readValue(json);
    assertNotNull(ex2);
    assertEquals(ex2.getMessage(), ex1.getMessage());
}

Not working example:

public static class CustomNoStackException extends Exception {
    public CustomNoStackException(String msg) {
        super(msg, null, true, false);
    }
}

@Test
public void testSerializeAndDeserializeCustomNoStackException() throws Exception {
    log.info("Test: testSerializeAndDeserializeCustomNoStackException");

    CustomNoStackException ex1 = new CustomNoStackException("boom");
    ObjectMapper om = new ObjectMapper();

    String json = om.writerFor(CustomNoStackException.class).writeValueAsString(ex1);
    assertNotNull(json);
    log.info("JSON: {}", json);

    CustomNoStackException ex2 = om.readerFor(CustomNoStackException.class).readValue(json);
    assertNotNull(ex2);
    assertEquals(ex2.getMessage(), ex1.getMessage());
}

In the second case, readValue(json) actually throws the CustomNoStackException wrapped in an IOException.

What am I doing wrong?

Upvotes: 1

Views: 1371

Answers (1)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279990

When an Exception is initialized without a cause, it marks itself as the cause.

private Throwable cause = this;

It uses that as a sentinel value to indicate that it has no cause. initCause only lets you change the cause if it's not itself.

Your CustomNoStackException constructor is initializing the cause with null, breaking the sentinel value. When Jackson later tries to call initCause method because of the

"cause":null

pair in the JSON, initCause throws an exception saying you can't overwrite an exception's cause (this is nested in the JsonMappingException).

Upvotes: 2

Related Questions