使用Java中的Jackson反序列化异常/ throwable时出现的问题 [英] Issues while deserializing exception/throwable using Jackson in Java

查看:123
本文介绍了使用Java中的Jackson反序列化异常/ throwable时出现的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Jackson(版本2.2.1)反序列化 Exception Throwable 实例时遇到问题。请考虑以下代码段:

I am facing issues while deserializing Exception and Throwable instances using Jackson (version 2.2.1). Consider the following snippet:

public static void main(String[] args) throws IOException
{
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
    objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    objectMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);

    try {
        Integer.parseInt("String");
    }
    catch (NumberFormatException e) {
        RuntimeException runtimeException = new RuntimeException(e);
        String serializedException = objectMapper.writeValueAsString(runtimeException);
        System.out.println(serializedException);
        Throwable throwable = objectMapper.readValue(serializedException, Throwable.class);
        throwable.printStackTrace();
    }
}

系统的输出。 catch 块中的out.println 是:

The output of System.out.println in the catch block is:

{
  "@class" : "java.lang.RuntimeException",
  "detailMessage" : "java.lang.NumberFormatException: For input string: \"String\"",
  "cause" : {
    "@class" : "java.lang.NumberFormatException",
    "detailMessage" : "For input string: \"String\"",
    "cause" : null,
    "stackTrace" : [ {
      "declaringClass" : "java.lang.NumberFormatException",
      "methodName" : "forInputString",
      "fileName" : "NumberFormatException.java",
      "lineNumber" : 65
    }, {
      "declaringClass" : "java.lang.Integer",
      "methodName" : "parseInt",
      "fileName" : "Integer.java",
      "lineNumber" : 492
    }, {
      "declaringClass" : "java.lang.Integer",
      "methodName" : "parseInt",
      "fileName" : "Integer.java",
      "lineNumber" : 527
    }, {
      "declaringClass" : "test.jackson.JacksonTest",
      "methodName" : "main",
      "fileName" : "JacksonTest.java",
      "lineNumber" : 26
    } ],
    "suppressedExceptions" : [ "java.util.ArrayList", [ ] ]
  },
  "stackTrace" : [ {
    "declaringClass" : "test.jackson.JacksonTest",
    "methodName" : "main",
    "fileName" : "JacksonTest.java",
    "lineNumber" : 29
  } ],
  "suppressedExceptions" : [ "java.util.ArrayList", [ ] ]
}

看起来不错。但是当我尝试使用 objectMapper.readValue()反序列化时,我得到以下异常:

which seems fine. But when I attempt to deserialize this using objectMapper.readValue(), I get the following exception:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "declaringClass" (class java.lang.StackTraceElement), not marked as ignorable
 at [Source: java.io.StringReader@3c5ebd39; line: 9, column: 27] (through reference chain: java.lang.StackTraceElement["declaringClass"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
    at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:555)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:708)
    at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StackTraceElementDeserializer.deserialize(JdkDeserializers.java:414)
    at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StackTraceElementDeserializer.deserialize(JdkDeserializers.java:380)
    at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:151)
...

然后尝试使用混合注释 ,在 java.lang.StackTraceElement 中忽略 declaringClass ,但现在反序列化的异常在其堆栈跟踪中不包含声明类:

I then tried using mix-in annotations, to ignore declaringClass in java.lang.StackTraceElement, but now the deserialized Exception doesn't contain the declaring class in its stack trace:

java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "String"
    at .main(JacksonTest.java:33)
Caused by: java.lang.NumberFormatException: For input string: "String"
    at .forInputString(NumberFormatException.java:65)
    at .parseInt(Integer.java:492)
    at .parseInt(Integer.java:527)
    at .main(JacksonTest.java:30)

我错过了什么吗?非常感谢任何帮助。

Am I missing anything? Any help is greatly appreciated.

推荐答案

似乎有一个Jackson JIRA条目这里。杰克逊似乎无法处理 java.lang.StackTraceElement 中的 declaringClass ,因为getter对应于这个字段被称为 getClassName()

There seems to be a Jackson JIRA entry for this here. Jackson doesn't seem to be able to handle the declaringClass in java.lang.StackTraceElement, since the getter corresponding to this field is called getClassName().

我通过使用<$ c $周围的自定义包装来修复此问题c> StackTraceElement ,如上面提到的JIRA条目中所建议的那样。自定义包装器( CustomStackTraceElement )将包含字段 declaringClass methodName fileName lineNumber 以及相应的getter和setter。我修改了 catch 块(在问题中提到)如下:

I fixed this issue by using a custom wrapper around StackTraceElement as suggested in the JIRA entry mentioned above. The custom wrapper (CustomStackTraceElement) will have the fields declaringClass, methodName, fileName, and lineNumber and the corresponding getters and setters in it. I modified the catch block (mentioned in the question) to be as follows:

catch (NumberFormatException e) {
    RuntimeException runtimeException = new RuntimeException(e);
    e.printStackTrace();
    String serializedException = objectMapper.writeValueAsString(runtimeException);
    System.out.println(serializedException);

    String serializedStackTrace = objectMapper.writeValueAsString(transformStackTrace(runtimeException));
    String serializedStackTraceForCause = objectMapper.writeValueAsString(transformStackTrace(runtimeException.getCause()));

    Throwable throwable = objectMapper.readValue(serializedException, Throwable.class);
    List<CustomStackTraceElement> customStackTraceElementList = objectMapper.readValue(serializedStackTrace, List.class);
    List<CustomStackTraceElement> customStackTraceElementListForCause = objectMapper.readValue(serializedStackTraceForCause, List.class);

    throwable.setStackTrace(reverseTransformStackTrace(customStackTraceElementList));
    throwable.getCause().setStackTrace(reverseTransformStackTrace(customStackTraceElementListForCause));
    throwable.printStackTrace();
}

StackTraceElement [] 转换为 List< CustomStackTraceElement>

private static List<CustomStackTraceElement> transformStackTrace(Throwable throwable)
{
    List<CustomStackTraceElement> list = new ArrayList<>();
    for (StackTraceElement stackTraceElement : throwable.getStackTrace()) {
        CustomStackTraceElement customStackTraceElement =
            new CustomStackTraceElement(stackTraceElement.getClassName(),
                                        stackTraceElement.getMethodName(),
                                        stackTraceElement.getFileName(),
                                        stackTraceElement.getLineNumber());

        list.add(customStackTraceElement);
    }

    return list;
}

...反序列化期间将完成反向转换:

... and the reverse transformation will be done during deserialization:

private static StackTraceElement[] reverseTransformStackTrace(List<CustomStackTraceElement> customStackTraceElementList)
{
    StackTraceElement[] stackTraceElementArray = new StackTraceElement[customStackTraceElementList.size()];
    for (int i = 0; i < customStackTraceElementList.size(); i++) {
        CustomStackTraceElement customStackTraceElement = customStackTraceElementList.get(i);
        StackTraceElement stackTraceElement =
            new StackTraceElement(customStackTraceElement.getDeclaringClass(),
                                  customStackTraceElement.getMethodName(),
                                  customStackTraceElement.getFileName(),
                                  customStackTraceElement.getLineNumber());

        stackTraceElementArray[i] = stackTraceElement;
    }

    return stackTraceElementArray;
}

现在,在反序列化后, Throwable object中包含预期的堆栈跟踪。

Now, after deserialization, the Throwable object has the expected stack trace in it.

这篇关于使用Java中的Jackson反序列化异常/ throwable时出现的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆