/** Method that will construct a regular bean property setter using the given setter method. */ protected SettableBeanProperty constructSetterlessProperty( DeserializationContext ctxt, BeanDescription beanDesc, BeanPropertyDefinition propDef) throws JsonMappingException { final AnnotatedMethod getter = propDef.getGetter(); // need to ensure it is callable now: if (ctxt.canOverrideAccessModifiers()) { getter.fixAccess(); } /* 26-Jan-2012, tatu: Alas, this complication is still needed to handle * (or at least work around) local type declarations... */ JavaType type = getter.getType(beanDesc.bindingsForBeanType()); /* First: does the Method specify the deserializer to use? * If so, let's use it. */ JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, getter); type = modifyTypeByAnnotation(ctxt, getter, type); TypeDeserializer typeDeser = type.getTypeHandler(); SettableBeanProperty prop = new SetterlessProperty(propDef, type, typeDeser, beanDesc.getClassAnnotations(), getter); if (propDeser != null) { prop = prop.withValueDeserializer(propDeser); } return prop; }
/** * Method called to finalize setup of this deserializer, after deserializer itself has been * registered. This is needed to handle recursive and transitive dependencies. */ public void resolve(DeserializationConfig config, DeserializerProvider provider) throws JsonMappingException { // just need to worry about property-based one if (_propertyBasedCreator != null) { // Need to / should not create separate HashMap<JavaType, JsonDeserializer<Object>> seen = new HashMap<JavaType, JsonDeserializer<Object>>(); for (SettableBeanProperty prop : _propertyBasedCreator.properties()) { prop.setValueDeserializer( findDeserializer(config, provider, prop.getType(), prop.getPropertyName(), seen)); } } }
@SuppressWarnings("unchecked") public Map<Object, Object> _deserializeUsingCreator(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { final Creator.PropertyBased creator = _propertyBasedCreator; PropertyValueBuffer buffer = creator.startBuilding(jp, ctxt); JsonToken t = jp.getCurrentToken(); if (t == JsonToken.START_OBJECT) { t = jp.nextToken(); } final JsonDeserializer<Object> valueDes = _valueDeserializer; final TypeDeserializer typeDeser = _valueTypeDeserializer; for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) { String propName = jp.getCurrentName(); t = jp.nextToken(); // to get to value if (_ignorableProperties != null && _ignorableProperties.contains(propName)) { jp.skipChildren(); // and skip it (in case of array/object) continue; } // creator property? SettableBeanProperty prop = creator.findCreatorProperty(propName); if (prop != null) { // Last property to set? Object value = prop.deserialize(jp, ctxt); if (buffer.assignParameter(prop.getCreatorIndex(), value)) { jp.nextToken(); Map<Object, Object> result = (Map<Object, Object>) creator.build(buffer); _readAndBind(jp, ctxt, result); return result; } continue; } // other property? needs buffering String fieldName = jp.getCurrentName(); Object key = (_keyDeserializer == null) ? fieldName : _keyDeserializer.deserializeKey(fieldName, ctxt); Object value; if (t == JsonToken.VALUE_NULL) { value = null; } else if (typeDeser == null) { value = valueDes.deserialize(jp, ctxt); } else { value = valueDes.deserializeWithType(jp, ctxt, typeDeser); } buffer.bufferMapProperty(key, value); } // end of JSON object? // if so, can just construct and leave... return (Map<Object, Object>) creator.build(buffer); }
/** * Method that will construct a regular bean property setter using the given setter method. * * @return Property constructed, if any; or null to indicate that there should be no property * based on given definitions. */ protected SettableBeanProperty constructSettableProperty( DeserializationContext ctxt, BeanDescription beanDesc, BeanPropertyDefinition propDef, Type jdkType) throws JsonMappingException { // need to ensure method is callable (for non-public) AnnotatedMember mutator = propDef.getMutator(); if (ctxt.canOverrideAccessModifiers()) { mutator.fixAccess(); } // note: this works since we know there's exactly one argument for methods JavaType t0 = beanDesc.resolveType(jdkType); BeanProperty.Std property = new BeanProperty.Std(propDef.getName(), t0, beanDesc.getClassAnnotations(), mutator); JavaType type = resolveType(ctxt, beanDesc, t0, mutator); // did type change? if (type != t0) { property = property.withType(type); } /* First: does the Method specify the deserializer to use? * If so, let's use it. */ JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, mutator); type = modifyTypeByAnnotation(ctxt, mutator, type); TypeDeserializer typeDeser = type.getTypeHandler(); SettableBeanProperty prop; if (mutator instanceof AnnotatedMethod) { prop = new MethodProperty( propDef, type, typeDeser, beanDesc.getClassAnnotations(), (AnnotatedMethod) mutator); } else { prop = new FieldProperty( propDef, type, typeDeser, beanDesc.getClassAnnotations(), (AnnotatedField) mutator); } if (propDeser != null) { prop = prop.withValueDeserializer(propDeser); } // [JACKSON-235]: need to retain name of managed forward references: AnnotationIntrospector.ReferenceProperty ref = propDef.findReferenceType(); if (ref != null && ref.isManagedReference()) { prop.setManagedReferenceName(ref.getName()); } return prop; }
protected void addObjectIdReader( DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder) throws JsonMappingException { ObjectIdInfo objectIdInfo = beanDesc.getObjectIdInfo(); if (objectIdInfo == null) { return; } Class<?> implClass = objectIdInfo.getGeneratorType(); JavaType idType; SettableBeanProperty idProp; ObjectIdGenerator<?> gen; // Just one special case: Property-based generator is trickier if (implClass == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work String propName = objectIdInfo.getPropertyName(); idProp = builder.findProperty(propName); if (idProp == null) { throw new IllegalArgumentException( "Invalid Object Id definition for " + beanDesc.getBeanClass().getName() + ": can not find property with name '" + propName + "'"); } idType = idProp.getType(); gen = new PropertyBasedObjectIdGenerator(objectIdInfo.getScope()); } else { JavaType type = ctxt.constructType(implClass); idType = ctxt.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0]; idProp = null; gen = ctxt.objectIdGeneratorInstance(beanDesc.getClassInfo(), objectIdInfo); } // also: unlike with value deserializers, let's just resolve one we need here JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType); builder.setObjectIdReader( ObjectIdReader.construct(idType, objectIdInfo.getPropertyName(), gen, deser, idProp)); }
/** * Method called to figure out settable properties for the bean deserializer to use. * * <p>Note: designed to be overridable, and effort is made to keep interface similar between * versions. */ protected void addBeanProps( DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder) throws JsonMappingException { final SettableBeanProperty[] creatorProps = builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig()); // Things specified as "ok to ignore"? [JACKSON-77] AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); boolean ignoreAny = false; { Boolean B = intr.findIgnoreUnknownProperties(beanDesc.getClassInfo()); if (B != null) { ignoreAny = B.booleanValue(); builder.setIgnoreUnknownProperties(ignoreAny); } } // Or explicit/implicit definitions? Set<String> ignored = ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo())); for (String propName : ignored) { builder.addIgnorable(propName); } // Also, do we have a fallback "any" setter? AnnotatedMethod anySetter = beanDesc.findAnySetter(); if (anySetter != null) { builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter)); } // NOTE: we do NOT add @JsonIgnore'd properties into blocked ones if there's any setter // Implicit ones via @JsonIgnore and equivalent? if (anySetter == null) { Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames(); if (ignored2 != null) { for (String propName : ignored2) { // allow ignoral of similarly named JSON property, but do not force; // latter means NOT adding this to 'ignored': builder.addIgnorable(propName); } } } final boolean useGettersAsSetters = (ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS) && ctxt.isEnabled(MapperFeature.AUTO_DETECT_GETTERS)); // Ok: let's then filter out property definitions List<BeanPropertyDefinition> propDefs = filterBeanProps(ctxt, beanDesc, builder, beanDesc.findProperties(), ignored); // After which we can let custom code change the set if (_factoryConfig.hasDeserializerModifiers()) { for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs); } } // At which point we still have all kinds of properties; not all with mutators: for (BeanPropertyDefinition propDef : propDefs) { SettableBeanProperty prop = null; if (propDef.hasConstructorParameter()) { /* [JACKSON-700] If property is passed via constructor parameter, we must * handle things in special way. Not sure what is the most optimal way... * for now, let's just call a (new) method in builder, which does nothing. */ // but let's call a method just to allow custom builders to be aware... final String name = propDef.getName(); for (SettableBeanProperty cp : creatorProps) { if (name.equals(cp.getName())) { prop = cp; break; } } if (prop == null) { throw ctxt.mappingException("Could not find creator property with name '" + name + "'"); } builder.addCreatorProperty(prop); continue; } if (propDef.hasSetter()) { Type propertyType = propDef.getSetter().getGenericParameterType(0); prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType); } else if (propDef.hasField()) { Type propertyType = propDef.getField().getGenericType(); prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType); } else if (useGettersAsSetters && propDef.hasGetter()) { /* As per [JACKSON-88], may also need to consider getters * for Map/Collection properties; but with lowest precedence */ AnnotatedMethod getter = propDef.getGetter(); // should only consider Collections and Maps, for now? Class<?> rawPropertyType = getter.getRawType(); if (Collection.class.isAssignableFrom(rawPropertyType) || Map.class.isAssignableFrom(rawPropertyType)) { prop = constructSetterlessProperty(ctxt, beanDesc, propDef); } } if (prop != null) { Class<?>[] views = propDef.findViews(); if (views == null) { // one more twist: if default inclusion disabled, need to force empty set of views if (!ctxt.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) { views = NO_VIEWS; } } // one more thing before adding to builder: copy any metadata prop.setViews(views); builder.addProperty(prop); } } }