Reputation: 2169
Is there an option in Jackson to let the deserialization fail when it encounters a null
for any (non-primitive) object property or for any (non-primitive) array element?
It should work similarly to the Deserialization Feature - FAIL_ON_NULL_FOR_PRIMITIVES).
So deserializing {"name": null}
should throw an exception when deserializing into a POJO
class User {
private String name = "Default name";
//+setters/getters
}
However, it should work fine and throw no exception when deserializing {}
into that POJO, as the default value for the name
field is not overwritten (see comments).
I would like to avoid null
elements in arrays also, so deserializing ["A", "B", null]
should throw an exception when deserializing into List<String>
.
Upvotes: 2
Views: 2478
Reputation: 2169
There is no easy way to do this as far as I know (jackson-databind 2.4.2).
I suggest you take a look at using custom constructors / factory methods for creating objects out of Json. That allows you to do more advanced validation of incoming Json strings.
You can add this feature by registering a SimpleModule
with an added BeanDeserializerModifier
in order to alter the deserialization functionality.
By overriding the appropriate method you can use the default JsonDeserializer
to deserialize the object easily and throw a mapping exception if a null
property occurs.
You can find details in the answers of a similar SO question.
Extend the existing deserialization:
//instantiate an objectMapper and alter the deserialization functionality
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return new DisallowNullDeserializer(beanDesc.getBeanClass(), deserializer);
}
});
mapper.registerModule(simpleModule);
The actual deserialization and exception throwing is happening in this utility class:
public class DisallowNullDeserializer<T> extends StdDeserializer<T> implements ResolvableDeserializer {
private final JsonDeserializer<?> delegateDeserializer;
public DisallowNullDeserializer(Class<T> clazz, JsonDeserializer<?> delegateDeserializer) {
super(clazz);
this.delegateDeserializer = delegateDeserializer;
}
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// delegate actual deserialization to default deserializer
T out = (T) delegateDeserializer.deserialize(jp, ctxt);
// check for null properties & throw exception
// -> there may be a better, more performant way to find null properties
Map<String, Object> propertyMap = mapper.convertValue(out, Map.class);
for (Object property: propertyMap.values())
if (property == null)
throw ctxt.mappingException("Can not map JSON null values.");
return out;
}
// there is no obvious reason why this is needed; see linked SO answers
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
((ResolvableDeserializer) delegateDeserializer).resolve(ctxt);
}
}
Upvotes: 1