GuavaImmutableMapDeserializer.java
package tools.jackson.datatype.guava.deser;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.JavaType;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.KeyDeserializer;
import tools.jackson.databind.deser.NullValueProvider;
import tools.jackson.databind.jsontype.TypeDeserializer;
import tools.jackson.databind.util.AccessPattern;
import tools.jackson.databind.util.ClassUtil;
import tools.jackson.datatype.guava.util.NullElementHelper;
import com.google.common.collect.ImmutableMap;
abstract class GuavaImmutableMapDeserializer<T extends ImmutableMap<Object, Object>> extends
GuavaMapDeserializer<T>
{
GuavaImmutableMapDeserializer(JavaType type, KeyDeserializer keyDeser,
ValueDeserializer<?> valueDeser, TypeDeserializer valueTypeDeser,
NullValueProvider nuller) {
super(type, keyDeser, valueDeser, valueTypeDeser, nuller);
}
@Override
public AccessPattern getEmptyAccessPattern() {
// immutable, hence:
return AccessPattern.CONSTANT;
}
protected abstract ImmutableMap.Builder<Object, Object> createBuilder();
@Override
protected T _deserializeEntries(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
final KeyDeserializer keyDes = _keyDeserializer;
final ValueDeserializer<?> valueDes = _valueDeserializer;
final TypeDeserializer typeDeser = _valueTypeDeserializer;
ImmutableMap.Builder<Object, Object> builder = createBuilder();
for (; p.currentToken() == JsonToken.PROPERTY_NAME; p.nextToken()) {
// Must point to field name now
String fieldName = p.currentName();
Object key = (keyDes == null) ? fieldName : keyDes.deserializeKey(fieldName, ctxt);
// And then the value...
JsonToken t = p.nextToken();
// 28-Nov-2010, tatu: Should probably support "ignorable properties" in future...
Object value;
if (t == JsonToken.VALUE_NULL) {
if (!_skipNullValues) {
value = _nullProvider.getNullValue(ctxt);
// [datatypes-collections#273]: Guava immutable maps do not accept `null`
// values: report (instead of silently dropping, as per [datatype-guava#52]),
// consistent with `ImmutableTable`; use `Nulls.SKIP` to drop
if (value == null) {
value = NullElementHelper.handleNull(p, ctxt, p.currentToken(),
_containerType.getContentType(),
"Guava `Map` of type "+ClassUtil.getTypeDescription(_containerType));
}
// `null` if dropped by problem handler
if (value != null) {
builder.put(key, value);
}
}
continue;
}
if (typeDeser == null) {
value = valueDes.deserialize(p, ctxt);
} else {
value = valueDes.deserializeWithType(p, ctxt, typeDeser);
}
if (value == null) {
// Value deserializer may return `null` for non-null token
NullElementHelper.addElement(p, ctxt, p.currentToken(),
_containerType.getContentType(),
"Guava `Map` of type "+ClassUtil.getTypeDescription(_containerType),
null, v -> builder.put(key, v));
} else {
builder.put(key, value);
}
}
// No class outside of the package will be able to subclass us,
// and we provide the proper builder for the subclasses we implement.
try {
@SuppressWarnings("unchecked")
T map = (T) builder.build();
return map;
} catch (IllegalArgumentException e) {
return ctxt.reportInputMismatch(this,
"Failed to build %s from deserialized entries: %s",
ClassUtil.getTypeDescription(_containerType), e.getMessage());
}
}
}