Jackson MyCustomDeserializer super.deserialize (парсер, d c, intoValue); не работает - PullRequest
0 голосов
/ 25 марта 2020

Я запускаю Spring Boot с Джексоном 2.10.3.

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.10.3</version>
</dependency>      
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.10.3</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.10.3</version>
</dependency>

Мое входное значение представляет собой json представление сериализованного объекта, в моем случае F C. java Когда При создании Mapper регистрируется новый CustomerFCDeserializer.

  mapper = new ObjectMapper();
  SimpleModule module = new SimpleModule();
  module.addDeserializer(FC.class, new CustomFCDeserializer(fcFactory));
  mapper.registerModule(module);

CustomFCDeserializer предназначен для инициализации объекта F C, в который сериализованный объект должен быть десериализован. fc = super.deserialize(parser, dc, fc);

Обычно я просто десериализовал бы его, но в этом конкретном c случае конструктор по умолчанию не может быть вызван, вместо этого объект нуждается в некоторой другой инициализации, как это делает FcFactory. Таким образом, в объекте, возвращаемом фабрикой, будут установлены также сериализованные поля.

public class CustomFCDeserializer extends StdDeserializer<FC> {
    private final FCFactory fcFactory;

    public CustomFCDeserializer(FCFactory fcFactory) {
        super(FC.class);
        this.fcFactory = fcFactory;
    }

    @Override
    public FC deserialize(JsonParser parser, DeserializationContext dc) throws IOException, JsonProcessingException {
        ObjectCodec codec = parser.getCodec();
        JsonNode node = codec.readTree(parser);
        JsonNode idNode = node.get("id");
        long id = idNode.asLong(0);
        FC fc = fcFactory.getFCById(id); //<!--- create my object
        //set values on prev created fc object
        fc = super.deserialize(parser, dc, fc); //<!-- pollute it 
        return fc;
    }
}

Выполнение этого примера рекурсивно вызовет deserialize, super.deserialize и, наконец, снова десериализацию, которая завершается неудачей при изменении структуры.

java.lang.NullPointerException: null
    at objectMapper.CustomFcDeserializer.deserialize(CustomFcDeserializer.java:38) ~[classes/:na]
    at objectMapper.CustomFcDeserializer.deserialize(CustomFcDeserializer.java:16) ~[classes/:na]
    at com.fasterxml.jackson.databind.JsonDeserializer.deserialize(JsonDeserializer.java:129) ~[jackson-databind-2.9.0.jar:2.9.0]
    at objectMapper.CustomFcDeserializer.deserialize(CustomFcDeserializer.java:51) ~[classes/:na]
    at objectMapper.CustomFcDeserializer.deserialize(CustomFcDeserializer.java:16) ~[classes/:na]
[...]

Есть ли лучший способ, чем решить эту проблему кучей операторов if? Или это более разумный способ загрязнения существующего объекта? deserialize(JsonParser p, DeserializationContext ctxt, T intoValue), кажется, будет в порядке, поскольку требуется intoValue, но я десериализирую объект, а не коллекцию или карту. Кстати, мой объект не имеет и не имеет неизменных членов.

com.​fasterxml.​jackson.​databind.​JsonDeserializer
public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) throws IOException
Alternate deserialization method (compared to the most commonly used, deserialize(JsonParser, DeserializationContext)), which takes in initialized value instance, to be configured and/or populated by deserializer. Method is not necessarily used (or supported) by all types (it will not work for immutable types, for obvious reasons): most commonly it is used for Collections and Maps. It may be used both with "updating readers" (for POJOs) and when Collections and Maps use "getter as setter".
Throws: IOException

1 Ответ

0 голосов
/ 25 марта 2020

углубился в переписывание картографа и десериализатора, просто сделайте

Map<String, Object> fcInput = dfe.getArgument("fcInput");
FC fcInput = mapper.convertValue(fcInput, FC.class);
String fcString = mapper.writeValueAsString(fcInput);

long fcId = fcInput.getId();
FC existingFc = fcFactory.getFC(fcId);

ObjectMapper om = new ObjectMapper();
ObjectReader or = om.readerForUpdating(existingFc);
FC updatedFc = or.readValue(fcString);
...