Бесконечная рекурсия при десериализации с помощью Jackson и Mockito

Я пытаюсь напечатать любой объект с помощью mapper.writeValueAsString, но сталкиваюсь с бесконечной рекурсией при десериализации объектов с помощью Mockito и Jackson. Объекты, которые я пытаюсь десериализовать, выполняют базовые вызовы Hibernate к БД и т. д., и я не контролирую сами классы.

В настоящее время я использую следующие версии Mockito и Jackson, но то же самое происходит и со старыми версиями Jackson 1.X.

  • Мокито: org.mockito:mockito-all:jar:1.9.5:compile
  • Джексон: com.fasterxml.jackson.core:jackson-databind:jar:2.9.7:compile

Как указано, я не могу изменить базовые классы с помощью аннотации, такой как @JsonIgnore, потому что они являются внешними зависимостями, не находящимися под моим контролем. Я также не могу создавать примеси для своего пользовательского случая, потому что я пытаюсь в общем распечатать содержимое любого отправленного объекта.

Я попытался добавить DeserializationConfig FAIL_ON_UNKNOWN_PROPERTIES к false в более старой версии Джексона, и я попытался установить DeserializationFeature FAIL_ON_MISSING_CREATOR_PROPERTIES в false.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public static PrintUtil {
    public static String printJSON(Object obj) {
        String printstring = "printfailed";
        try {
            ObjectMapper mapper = new ObjectMapper();
            LOG.debug("formatted JSON String ");
            printstring = mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return printstring;
    }
}

Вывод терминала бесконечной рекурсии виден при запуске тестов Mockito для методов, содержащих операторы Log4j, которые, в свою очередь, вызывают функцию PrintUtil. Оператор e.printStackTrace() начинает печатать во время выполнения тестов.

Большинство объектов, отправляемых этому служебному методу, представляют собой объекты ответов JAXB XML Service Response.


person RoyValentine    schedule 05.10.2018    source источник
comment
Я не понимаю, какова здесь роль mockito? Кроме того, что это за объект, который вы пытаетесь сериализовать?   -  person Sergii Bishyr    schedule 08.10.2018
comment
@SergiiBishyr Я отредактировал свой вопрос и добавил дополнительную информацию о mockito и объектах, которые я сериализую.   -  person RoyValentine    schedule 09.10.2018
comment
Возможно, вы захотите взглянуть на комбинацию @JsonIgnore, @JsonIgnoreProperties или @JsonManagedReference / @JsonBackReference, чтобы увидеть, какая из них лучше всего подходит для вашего варианта использования.   -  person The Head Rush    schedule 09.10.2018
comment
@TheHeadRush Как я уже говорил в вопросе, я не могу добавлять аннотации к объектам, которые я передаю, потому что они не принадлежат мне и в основном представляют собой XML-объекты JAXB, которые по сути являются интерфейсами для базовых объектов C++.   -  person RoyValentine    schedule 09.10.2018


Ответы (1)


Не имея возможности изменять сами классы, я вижу два возможных решения.

1) Оберните объекты в объекты, которыми вы владеете, как это было предложено @TheHeadRush, и соответствующим образом аннотируйте их. Я бы предложил использовать @JsonIdentityInfo, чтобы объекты сериализовались по своему идентификатору, а не полностью игнорировались с помощью @JsonIgnore.

2) Используйте собственный десериализатор для объекта, вызывающего рекурсию. Вот пример:

public class CustomDeserializer extends StdDeserializer<MyObject>{

   // Add constructors as necessary.

    @Override
    public List<Item> deserialize(
      JsonParser jsonparser, 
      DeserializationContext context) 
      throws IOException, JsonProcessingException {
       return null; // Return something that won't recurse here.
    }
}

Затем зарегистрируйте десериализатор с помощью ObjectMapper, который вы используете:

// Register the deserializer:
SimpleModule module = new SimpleModule()
    .addDeserializer(MyObject.class, new CustomDeserializer());

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
person Adam    schedule 09.10.2018