I'm running Spring Boot with Jackson 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>
My input value is a json representation of an serialized object, in my case FC.java When creating the Mapper a new CustomerFCDeserializer is registered.
mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(FC.class, new CustomFCDeserializer(fcFactory));
mapper.registerModule(module);
The CustomFCDeserializer is inteded to initialize an FC object the serialized object should be deserialized into.
fc = super.deserialize(parser, dc, fc);
Normally i would just deserialize it, but in this specific case the default constructor can't be called, instead the object needs some other initializiation as done by FcFactory. This way also serialized fields will be set in the object returned by the factory.
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;
}
}
Running this example will recursivly call deserialize, super.deserialize and finally deserialize again which fails as structure changed.
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]
[...]
Is there a better way than handeling this issue by a bunch of if statements?
Or is the a more intelligent way to pollute and existing object?
deserialize(JsonParser p, DeserializationContext ctxt, T intoValue)
seems be fine as it takes an intoValue
, but im deserializing an object, not a collection nor map. Btw and my object isn't and doesnt have immutable members.
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
went to deep into overwriting mapper and deserializer, simply do
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);