Сериализация только информации времени компиляции - PullRequest
2 голосов
/ 28 марта 2019

При сериализации объекта Java, поскольку он использует отражение, Джексон сериализует объект в его представлении времени выполнения.

У меня есть следующий класс:

@lombok.AllArgsConstructor
@lombokGetter
class ErrorInformation {

   private final Exception exception;
}

и

final ErrorInformation errorInfo = new ErrorInformation(new IllegalArgumentException("foo"));

Вместо того, чтобы просто сериализовать Exception, Джексон фактически сериализует все поля в IllegalArgumentException - с неконтролируемыми последствиями, такими как циклические ссылки (см., Например, mostSpecificCause в org.springframework.web.client.HttpServerErrorException).

Как можноЯ говорю Джексону на самом деле только сериализовать информацию Exception, не учитывая фактический тип среды выполнения, как вы ожидаете от статически типизированного языка, такого как Java?

Ответы [ 2 ]

3 голосов
/ 28 марта 2019

Jackson по умолчанию сериализует все getters метод в данном POJO.Если мы хотим сериализовать 3-rd party классы, нам нужно позаботиться о циклах и других проблемах.Для этого мы можем использовать MixIn функцию .Нам нужно определить, что для всех NestedRuntimeException исключений мы хотим игнорировать getMostSpecificCause метод.

interface NestedRuntimeExceptionMixIn {

    @JsonIgnore
    Throwable getMostSpecificCause();
}

Пример использования:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpServerErrorException;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        HttpServerErrorException exception = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "error");
        ErrorInformation ei = new ErrorInformation(exception);

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.addMixIn(NestedRuntimeException.class, NestedRuntimeExceptionMixIn.class);

        System.out.println(mapper.writeValueAsString(ei));
    }
}

печатает:

{
  "exception" : {
    "cause" : null,
    "stackTrace" : [ {
      "methodName" : "main",
      "fileName" : "JsonApp.java",
      "lineNumber" : 13,
      "className" : "JsonApp",
      "nativeMethod" : false
    } ],
    "rawStatusCode" : 500,
    "statusText" : "error",
    "responseHeaders" : null,
    "statusCode" : "INTERNAL_SERVER_ERROR",
    "responseBodyAsByteArray" : "",
    "responseBodyAsString" : "",
    "message" : "500 error",
    "rootCause" : null,
    "localizedMessage" : "500 error",
    "suppressed" : [ ]
  }
}
2 голосов
/ 28 марта 2019

Поскольку мы не можем изменить логику класса IllegalArgumentException, вы можете создать дополнительное поле экземпляра в своем классе ErrorInformation, заполнить его информацией, которую вы хотите сериализовать, и пометить переменную exception как transient

например. Допустим, вы хотите сохранить информацию об ошибке. Итак, создайте поле String скажем errorMessage и заполните его информацией об ошибке в конструкторе. Ниже приведен пример кода.

@lombok.AllArgsConstructor
@lombokGetter
class ErrorInformation {

   private final transient Exception exception;
   private final String errorMessage ;
   ErrorInformation(Exception exp) {
    this.exception = exp;
    this.errorMessage = exp.getMessage();
    }

}

Во время десериализации вы можете использовать эту информацию сообщения об ошибке для создания аналогичного (не того же) экземпляра объекта исключения, который был сериализован

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...