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