package com.fasterxml.jackson.databind.deser.impl; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.deser.SettableBeanProperty; import com.fasterxml.jackson.databind.introspect.AnnotatedMember; import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import com.fasterxml.jackson.databind.util.Annotations; /** * This concrete sub-class implements Collection or Map property that is * indirectly by getting the property value and directly modifying it. */ public final class SetterlessProperty extends SettableBeanProperty { private static final long serialVersionUID = 1L; protected final AnnotatedMethod _annotated; /** * Get method for accessing property value used to access property * (of Collection or Map type) to modify. */ protected final Method _getter; public SetterlessProperty(BeanPropertyDefinition propDef, JavaType type, TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedMethod method) { super(propDef, type, typeDeser, contextAnnotations); _annotated = method; _getter = method.getAnnotated(); } protected SetterlessProperty(SetterlessProperty src, JsonDeserializer<?> deser) { super(src, deser); _annotated = src._annotated; _getter = src._getter; } protected SetterlessProperty(SetterlessProperty src, String newName) { super(src, newName); _annotated = src._annotated; _getter = src._getter; } @Override public SetterlessProperty withName(String newName) { return new SetterlessProperty(this, newName); } @Override public SetterlessProperty withValueDeserializer(JsonDeserializer<?> deser) { return new SetterlessProperty(this, deser); } /* /********************************************************** /* BeanProperty impl /********************************************************** */ @Override public <A extends Annotation> A getAnnotation(Class<A> acls) { return _annotated.getAnnotation(acls); } @Override public AnnotatedMember getMember() { return _annotated; } /* /********************************************************** /* Overridden methods /********************************************************** */ @Override public final void deserializeAndSet(JsonParser jp, DeserializationContext ctxt, Object instance) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); if (t == JsonToken.VALUE_NULL) { /* Hmmh. Is this a problem? We won't be setting anything, so it's * equivalent of empty Collection/Map in this case */ return; } // Ok: then, need to fetch Collection/Map to modify: Object toModify; try { toModify = _getter.invoke(instance); } catch (Exception e) { _throwAsIOE(e); return; // never gets here } /* Note: null won't work, since we can't then inject anything * in. At least that's not good in common case. However, * theoretically the case where we get JSON null might * be compatible. If so, implementation could be changed. */ if (toModify == null) { throw new JsonMappingException("Problem deserializing 'setterless' property '"+getName()+"': get method returned null"); } _valueDeserializer.deserialize(jp, ctxt, toModify); } @Override public Object deserializeSetAndReturn(JsonParser jp, DeserializationContext ctxt, Object instance) throws IOException, JsonProcessingException { deserializeAndSet(jp, ctxt, instance); return instance; } @Override public final void set(Object instance, Object value) throws IOException { throw new UnsupportedOperationException("Should never call 'set' on setterless property"); } @Override public Object setAndReturn(Object instance, Object value) throws IOException { set(instance, value); return null; } }