使用Java中的Jackson反序列化异常/ throwable时出现的问题 [英] Issues while deserializing exception/throwable using Jackson in Java
问题描述
我在使用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屋!