@SuppressWarnings("deprecation") @Override public LinkedHashMap<String, AnnotatedMethod> findSetters( VisibilityChecker<?> visibilityChecker) { LinkedHashMap<String, AnnotatedMethod> results = new LinkedHashMap<String, AnnotatedMethod>(); for (BeanPropertyDefinition property : _properties) { AnnotatedMethod m = property.getSetter(); if (m != null) { results.put(property.getName(), m); } } return results; }
/** * 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; }
/** 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; }
/** * @param ignoredProperties (optional) names of properties to ignore; any fields that would be * recognized as one of these properties is ignored. * @param forSerialization If true, will collect serializable property fields; if false, * deserializable * @return Ordered Map with logical property name as key, and matching field as value. */ public LinkedHashMap<String, AnnotatedField> _findPropertyFields( Collection<String> ignoredProperties, boolean forSerialization) { LinkedHashMap<String, AnnotatedField> results = new LinkedHashMap<String, AnnotatedField>(); for (BeanPropertyDefinition property : _properties) { AnnotatedField f = property.getField(); if (f != null) { String name = property.getName(); if (ignoredProperties != null) { if (ignoredProperties.contains(name)) { continue; } } results.put(name, f); } } return results; }
@SuppressWarnings("deprecation") @Override public LinkedHashMap<String, AnnotatedMethod> findGetters( VisibilityChecker<?> visibilityChecker, Collection<String> ignoredProperties) { LinkedHashMap<String, AnnotatedMethod> results = new LinkedHashMap<String, AnnotatedMethod>(); for (BeanPropertyDefinition property : _properties) { AnnotatedMethod m = property.getGetter(); if (m != null) { String name = property.getName(); if (ignoredProperties != null) { if (ignoredProperties.contains(name)) { continue; } } results.put(name, m); } } return results; }
/** * Method for locating all back-reference properties (setters, fields) bean has * * @since 1.6 */ public Map<String, AnnotatedMember> findBackReferenceProperties() { HashMap<String, AnnotatedMember> result = null; for (BeanPropertyDefinition property : _properties) { AnnotatedMember am = property.getMutator(); if (am == null) { continue; } AnnotationIntrospector.ReferenceProperty refDef = _annotationIntrospector.findReferenceType(am); if (refDef != null && refDef.isBackReference()) { if (result == null) { result = new HashMap<String, AnnotatedMember>(); } String refName = refDef.getName(); if (result.put(refName, am) != null) { throw new IllegalArgumentException( "Multiple back-reference properties with name '" + refName + "'"); } } } return result; }
/** * Helper method called to filter out explicit ignored properties, as well as properties that have * "ignorable types". Note that this will not remove properties that have no setters. */ protected List<BeanPropertyDefinition> filterBeanProps( DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder, List<BeanPropertyDefinition> propDefsIn, Set<String> ignored) throws JsonMappingException { ArrayList<BeanPropertyDefinition> result = new ArrayList<BeanPropertyDefinition>(Math.max(4, propDefsIn.size())); HashMap<Class<?>, Boolean> ignoredTypes = new HashMap<Class<?>, Boolean>(); // These are all valid setters, but we do need to introspect bit more for (BeanPropertyDefinition property : propDefsIn) { String name = property.getName(); if (ignored.contains( name)) { // explicit ignoral using @JsonIgnoreProperties needs to block entries continue; } if (!property.hasConstructorParameter()) { // never skip constructor params Class<?> rawPropertyType = null; if (property.hasSetter()) { rawPropertyType = property.getSetter().getRawParameterType(0); } else if (property.hasField()) { rawPropertyType = property.getField().getRawType(); } // [JACKSON-429] Some types are declared as ignorable as well if ((rawPropertyType != null) && (isIgnorableType(ctxt.getConfig(), beanDesc, rawPropertyType, ignoredTypes))) { // important: make ignorable, to avoid errors if value is actually seen builder.addIgnorable(name); continue; } } result.add(property); } return result; }
/** * 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); } } }
private void _verifyProperty(BeanDescription beanDesc, boolean verifyDesc, boolean verifyIndex) { assertNotNull(beanDesc); List<BeanPropertyDefinition> props = beanDesc.findProperties(); assertEquals(2, props.size()); for (BeanPropertyDefinition prop : props) { String name = prop.getName(); final PropertyMetadata md = prop.getMetadata(); if ("a".equals(name)) { assertFalse(md.isRequired()); assertNull(md.getRequired()); if (verifyDesc) { assertEquals(PropDescBean.A_DESC, md.getDescription()); } if (verifyIndex) { assertNull(md.getIndex()); } } else if ("b".equals(name)) { assertTrue(md.isRequired()); assertEquals(Boolean.TRUE, md.getRequired()); if (verifyDesc) { assertNull(md.getDescription()); } if (verifyIndex) { assertEquals(Integer.valueOf(PropDescBean.B_INDEX), md.getIndex()); } } else { fail("Unrecognized property '" + name + "'"); } } }