First you need to annotate the properties of the Result
class,
so that Jackson will deserialize the positionText
property,
but not the positionNumber
.
You will do the latter by yourself in a taylor-made deserializer.
@Getter
@Setter
public class Result {
@JsonProperty("position")
private String positionText;
@JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
By default Jackson would use a BeanDeserializer
for deserializing Result
objects.
But you want a slightly modified implementation of this deserializer.
The rest of this answer is largely an adaptation of the accepted answer given to
the question How do I call the default deserializer from a custom deserializer in Jackson.
As usual your deserializer extends from StdDeserializer<Result>
,
but it also implements the ResolvableDeserializer
interface.
In the deserialize
method most of the work is delegated to the default deserializer
(in this case a BeanDeserializer
) which we got from Jackson.
We only add a small extra logic for setting the positionNumber
property
based on the positionText
property.
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
@Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
Finally you need to tell Jackson that you want the above ResultDeserializer
to be used for deserializing Result
objects.
This is done by the following customization of the ObjectMapper
,
which will wrap your ResultDeserializer
around Jackson's
default deserializer, only if a Result
object is to be deserialized:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
Then you can deserialize your JSON content as usual, for example:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});