Issues while deserializing exception/throwable using Jackson in Java -
i facing issues while deserializing exception
, throwable
instances using jackson (version 2.2.1). consider 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(); } }
the output of system.out.println
in catch
block is:
{ "@class" : "java.lang.runtimeexception", "detailmessage" : "java.lang.numberformatexception: 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", [ ] ] }
which seems fine. when attempt deserialize using objectmapper.readvalue()
, following exception:
exception in thread "main" com.fasterxml.jackson.databind.exc.unrecognizedpropertyexception: unrecognized field "declaringclass" (class java.lang.stacktraceelement), not marked ignorable @ [source: java.io.stringreader@3c5ebd39; line: 9, column: 27] (through reference chain: java.lang.stacktraceelement["declaringclass"]) @ com.fasterxml.jackson.databind.exc.unrecognizedpropertyexception.from(unrecognizedpropertyexception.java:79) @ com.fasterxml.jackson.databind.deserializationcontext.reportunknownproperty(deserializationcontext.java:555) @ com.fasterxml.jackson.databind.deser.std.stddeserializer.handleunknownproperty(stddeserializer.java:708) @ com.fasterxml.jackson.databind.deser.std.jdkdeserializers$stacktraceelementdeserializer.deserialize(jdkdeserializers.java:414) @ com.fasterxml.jackson.databind.deser.std.jdkdeserializers$stacktraceelementdeserializer.deserialize(jdkdeserializers.java:380) @ com.fasterxml.jackson.databind.deser.std.objectarraydeserializer.deserialize(objectarraydeserializer.java:151) ...
i tried using mix-in annotations, ignore declaringclass
in java.lang.stacktraceelement
, deserialized exception
doesn't contain declaring class in stack trace:
java.lang.runtimeexception: java.lang.numberformatexception: input string: "string" @ .main(jacksontest.java:33) caused by: java.lang.numberformatexception: input string: "string" @ .forinputstring(numberformatexception.java:65) @ .parseint(integer.java:492) @ .parseint(integer.java:527) @ .main(jacksontest.java:30)
am missing anything? appreciated.
there seems jackson jira entry here. jackson doesn't seem able handle declaringclass
in java.lang.stacktraceelement
, since getter corresponding field called getclassname()
.
i fixed issue using custom wrapper around stacktraceelement
suggested in jira entry mentioned above. custom wrapper (customstacktraceelement
) have fields declaringclass
, methodname
, filename
, , linenumber
, corresponding getters , setters in it. modified catch
block (mentioned in question) 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(); }
the stacktraceelement[]
converted list<customstacktraceelement>
following method during serialization:
private static list<customstacktraceelement> transformstacktrace(throwable throwable) { list<customstacktraceelement> list = new arraylist<>(); (stacktraceelement stacktraceelement : throwable.getstacktrace()) { customstacktraceelement customstacktraceelement = new customstacktraceelement(stacktraceelement.getclassname(), stacktraceelement.getmethodname(), stacktraceelement.getfilename(), stacktraceelement.getlinenumber()); list.add(customstacktraceelement); } return list; }
... , reverse transformation done during deserialization:
private static stacktraceelement[] reversetransformstacktrace(list<customstacktraceelement> customstacktraceelementlist) { stacktraceelement[] stacktraceelementarray = new stacktraceelement[customstacktraceelementlist.size()]; (int = 0; < 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; }
now, after deserialization, throwable
object has expected stack trace in it.
Comments
Post a Comment