Issues while deserializing exception/throwable using Jackson in Java

前端 未结 6 1811
無奈伤痛
無奈伤痛 2021-02-19 13:42

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



        
6条回答
  •  忘掉有多难
    2021-02-19 14:06

    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().

    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 customStackTraceElementList = objectMapper.readValue(serializedStackTrace, List.class);
        List customStackTraceElementListForCause = objectMapper.readValue(serializedStackTraceForCause, List.class);
    
        throwable.setStackTrace(reverseTransformStackTrace(customStackTraceElementList));
        throwable.getCause().setStackTrace(reverseTransformStackTrace(customStackTraceElementListForCause));
        throwable.printStackTrace();
    }
    

    The StackTraceElement[] will be converted into List by the following method during serialization:

    private static List transformStackTrace(Throwable throwable)
    {
        List 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 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;
    }
    

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

提交回复
热议问题