Jackson的readEntity将我的异常序列化为java.lang.Throwable而不是正确的Error异常

时间:2017-07-07 15:01:25

标签: java rest serialization jackson jersey

在我的代码中,我有一个扩展IllegalArgumentException的异常:

public class InvalidDataSourceException extends IllegalArgumentException {
  public InvalidDataSourceException(String message, Throwable cause) {
    super(message, cause);
  }
}

在我的Jersey REST Web服务中,所有错误都包含在类RESTError中 所有其他服务都可以抛出同样的异常:

public class RESTError extends Throwable {
    public RESTError(Throwable cause) {
        super(cause);
    }
}

因此,当InvalidDataSourceException发生时,它会被抛出为RESTError的原因:

throw new RESTError(invalidDataSourceException);

我们已经为Throwable对象注册了一个序列化器:

public class ThrowableSerializer extends JsonSerializer<Throwable> {

  @Override
  public void serialize(Throwable value, JsonGenerator jgen,
      SerializerProvider provider) throws IOException, JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeStringField("class", value.getClass().getCanonicalName());
    jgen.writeStringField("message", value.getMessage());
    jgen.writeObjectField("stackTrace", value.getStackTrace());
    jgen.writeStringField("stackTraceAsString", Throwables.getStackTraceAsString(value));
    jgen.writeObjectField("cause", value.getCause());
    jgen.writeEndObject();

  }
}

下面是一个单元测试,我尝试将RESTError编写为string,然后重新序列化:

public class TestJsonSerializationOfExceptions {
  private static final Logger log = LoggerFactory.getLogger(TestJsonSerializationOfExceptions.class);

  @Test
  public void testBasic() throws Exception {
    ObjectMapper objectMapper = ObjectMapperFactory.create();
    try {
      throw new InvalidDataSourceException("test msg");
    } catch (Throwable t) {
      RESTError restError = new RESTError(Response.Status.INTERNAL_SERVER_ERROR, Errors.General, t);
      String str = objectMapper.writeValueAsString(restError); // It is correct here!
      log.info("Rest error when serialized: {}", str);
      restError = objectMapper.readValue(str, RESTError.class);
      Assert.assertEquals(restError.getCause().getClass(), InvalidDataSourceException.class);
    }
  }
}

执行此操作时,异常原因会序列化为java.lang.Throwable,而不是我的自定义InvalidDataSourceException。它降级了它。因此单元测试失败。这是为什么?

1 个答案:

答案 0 :(得分:1)

查看Throwable javadoc。

当您扩展Throwable并将另一个传递给构造函数时,它将传递给private Throwable cause属性。然后这是关于类型的唯一信息。因此,在反序列化期间,Java只知道存在类型为cause的属性Throwable,并且如果它是InvalidDataSourceException或其他任何内容,则没有信息。

编辑:现在看起来缺少反序列化问题