protected boolean _useStatic( SerializerProvider provider, BeanProperty property, JavaType referredType) { // First: no serializer for `Object.class`, must be dynamic if (referredType.isJavaLangObject()) { return false; } // but if type is final, might as well fetch if (referredType.isFinal()) { // or should we allow annotation override? (only if requested...) return true; } // also: if indicated by typing, should be considered static if (referredType.useStaticType()) { return true; } // if neither, maybe explicit annotation? AnnotationIntrospector intr = provider.getAnnotationIntrospector(); if ((intr != null) && (property != null)) { Annotated ann = property.getMember(); if (ann != null) { JsonSerialize.Typing t = intr.findSerializationTyping(property.getMember()); if (t == JsonSerialize.Typing.STATIC) { return true; } if (t == JsonSerialize.Typing.DYNAMIC) { return false; } } } // and finally, may be forced by global static typing (unlikely...) return provider.isEnabled(MapperFeature.USE_STATIC_TYPING); }
// @Override public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException { /* 29-Sep-2012, tatu: Actually, we need to do much more contextual * checking here since we finally know for sure the property, * and it may have overrides */ JsonSerializer<?> ser = null; JsonSerializer<?> keySer = null; // First: if we have a property, may have property-annotation overrides if (property != null) { AnnotatedMember m = property.getMember(); if (m != null) { Object serDef; final AnnotationIntrospector intr = provider.getAnnotationIntrospector(); serDef = intr.findKeySerializer(m); if (serDef != null) { keySer = provider.serializerInstance(m, serDef); } serDef = intr.findContentSerializer(m); if (serDef != null) { ser = provider.serializerInstance(m, serDef); } } } if (ser == null) { ser = _valueSerializer; } if (ser == null) { // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated, // we can consider it a static case as well. if (_valueTypeIsStatic || hasContentTypeAnnotation(provider, property)) { ser = provider.findValueSerializer(_valueType, property); } } else if (ser instanceof ContextualSerializer) { ser = ((ContextualSerializer) ser).createContextual(provider, property); } if (keySer == null) { keySer = _keySerializer; } if (keySer == null) { keySer = provider.findKeySerializer(_keyType, property); } else if (keySer instanceof ContextualSerializer) { keySer = ((ContextualSerializer) keySer).createContextual(provider, property); } HashSet<String> ignored = this._ignoredEntries; AnnotationIntrospector intr = provider.getAnnotationIntrospector(); if (intr != null && property != null) { String[] moreToIgnore = intr.findPropertiesToIgnore(property.getMember()); if (moreToIgnore != null) { ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored); for (String str : moreToIgnore) { ignored.add(str); } } } return withResolved(property, keySer, ser, ignored); }
public <A> Collection<AnnotationTarget<MethodInfo, A>> resolveMethods( ClassTypeInfo cti, AnnotationType<A, ?> annotationClass) { ArrayList<AnnotationTarget<MethodInfo, A>> methods = new ArrayList<AnnotationTarget<MethodInfo, A>>(); AnnotationIntrospector<A> introspector = new AnnotationIntrospector<A>(annotationClass); for (MethodInfo method : getMethods(cti)) { AnnotationTarget<MethodInfo, A> annotation = introspector.resolve(method); if (annotation != null) { methods.add(annotation); } } return methods; }
// !!! TODO: added late in 2.7 in `jackson-databind`: remove from 2.8 protected JsonSerializer<?> findContentSerializer( SerializerProvider serializers, BeanProperty property) throws JsonMappingException { if (property != null) { AnnotatedMember m = property.getMember(); final AnnotationIntrospector intr = serializers.getAnnotationIntrospector(); if (m != null) { Object serDef = intr.findContentSerializer(m); if (serDef != null) { return serializers.serializerInstance(m, serDef); } } } return null; }
public void testRootNameAccess() throws Exception { AnnotationIntrospector ai = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); // If no @XmlRootElement, should get null (unless pkg has etc) assertNull(ai.findRootName(AnnotatedClass.construct(SimpleBean.class, ai, null))); // With @XmlRootElement, but no name, empty String PropertyName rootName = ai.findRootName(AnnotatedClass.construct(NamespaceBean.class, ai, null)); assertNotNull(rootName); assertEquals("", rootName.getSimpleName()); assertEquals("urn:class", rootName.getNamespace()); // and otherwise explicit name rootName = ai.findRootName(AnnotatedClass.construct(RootNameBean.class, ai, null)); assertNotNull(rootName); assertEquals("test", rootName.getSimpleName()); assertNull(rootName.getNamespace()); }
/** * Method for getting ordered list of named Creator properties. Returns an empty list is none * found. If multiple Creator methods are defined, order between properties from different methods * is undefined; however, properties for each such Creator are ordered properly relative to each * other. For the usual case of just a single Creator, named properties are thus properly ordered. */ public List<String> findCreatorPropertyNames() { List<String> names = null; for (int i = 0; i < 2; ++i) { List<? extends AnnotatedWithParams> l = (i == 0) ? getConstructors() : getFactoryMethods(); for (AnnotatedWithParams creator : l) { int argCount = creator.getParameterCount(); if (argCount < 1) continue; String name = _annotationIntrospector.findPropertyNameForParam(creator.getParameter(0)); if (name == null) continue; if (names == null) { names = new ArrayList<String>(); } names.add(name); for (int p = 1; p < argCount; ++p) { names.add(_annotationIntrospector.findPropertyNameForParam(creator.getParameter(p))); } } } if (names == null) { return Collections.emptyList(); } return names; }
/** * 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; }
protected boolean isFactoryMethod(AnnotatedMethod am) { /* First: return type must be compatible with the introspected class * (i.e. allowed to be sub-class, although usually is the same * class) */ Class<?> rt = am.getRawType(); if (!getBeanClass().isAssignableFrom(rt)) { return false; } /* Also: must be a recognized factory method, meaning: * (a) marked with @JsonCreator annotation, or * (a) "valueOf" (at this point, need not be public) */ if (_annotationIntrospector.hasCreatorAnnotation(am)) { return true; } if ("valueOf".equals(am.getName())) { return true; } return false; }
/** * Method for determining whether null properties should be written out for a Bean of introspected * type. This is based on global feature (lowest priority, passed as argument) and per-class * annotation (highest priority). */ public JsonSerialize.Inclusion findSerializationInclusion(JsonSerialize.Inclusion defValue) { if (_annotationIntrospector == null) { return defValue; } return _annotationIntrospector.findSerializationInclusion(_classInfo, defValue); }
/** * 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); } } }
/** * Method called to see if given method has annotations that indicate a more specific type than * what the argument specifies. If annotations are present, they must specify compatible Class; * instance of which can be assigned using the method. This means that the Class has to be raw * class of type, or its sub-class (or, implementing class if original Class instance is an * interface). * * @param a Method or field that the type is associated with * @param type Type derived from the setter argument * @return Original type if no annotations are present; or a more specific type derived from it if * type annotation(s) was found * @throws JsonMappingException if invalid annotation is found */ private JavaType modifyTypeByAnnotation(DeserializationContext ctxt, Annotated a, JavaType type) throws JsonMappingException { // first: let's check class for the instance itself: AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); Class<?> subclass = intr.findDeserializationType(a, type); if (subclass != null) { try { type = type.narrowBy(subclass); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow type " + type + " with concrete-type annotation (value " + subclass.getName() + "), method '" + a.getName() + "': " + iae.getMessage(), null, iae); } } // then key class if (type.isContainerType()) { Class<?> keyClass = intr.findDeserializationKeyType(a, type.getKeyType()); if (keyClass != null) { // illegal to use on non-Maps if (!(type instanceof MapLikeType)) { throw new JsonMappingException( "Illegal key-type annotation: type " + type + " is not a Map(-like) type"); } try { type = ((MapLikeType) type).narrowKey(keyClass); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow key type " + type + " with key-type annotation (" + keyClass.getName() + "): " + iae.getMessage(), null, iae); } } JavaType keyType = type.getKeyType(); /* 21-Mar-2011, tatu: ... and associated deserializer too (unless already assigned) * (not 100% why or how, but this does seem to get called more than once, which * is not good: for now, let's just avoid errors) */ if (keyType != null && keyType.getValueHandler() == null) { Object kdDef = intr.findKeyDeserializer(a); if (kdDef != null) { KeyDeserializer kd = ctxt.keyDeserializerInstance(a, kdDef); if (kd != null) { type = ((MapLikeType) type).withKeyValueHandler(kd); keyType = type.getKeyType(); // just in case it's used below } } } // and finally content class; only applicable to structured types Class<?> cc = intr.findDeserializationContentType(a, type.getContentType()); if (cc != null) { try { type = type.narrowContentsBy(cc); } catch (IllegalArgumentException iae) { throw new JsonMappingException( "Failed to narrow content type " + type + " with content-type annotation (" + cc.getName() + "): " + iae.getMessage(), null, iae); } } // ... as well as deserializer for contents: JavaType contentType = type.getContentType(); if (contentType.getValueHandler() == null) { // as with above, avoid resetting (which would trigger exception) Object cdDef = intr.findContentDeserializer(a); if (cdDef != null) { JsonDeserializer<?> cd = null; if (cdDef instanceof JsonDeserializer<?>) { cdDef = (JsonDeserializer<?>) cdDef; } else { Class<?> cdClass = _verifyAsClass(cdDef, "findContentDeserializer", JsonDeserializer.None.class); if (cdClass != null) { cd = ctxt.deserializerInstance(a, cdClass); } } if (cd != null) { type = type.withContentValueHandler(cd); } } } } return type; }
@Override public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException { JsonSerializer<?> ser = null; JsonSerializer<?> keySer = null; final AnnotationIntrospector intr = provider.getAnnotationIntrospector(); final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember(); // First: if we have a property, may have property-annotation overrides if ((propertyAcc != null) && (intr != null)) { Object serDef = intr.findKeySerializer(propertyAcc); if (serDef != null) { keySer = provider.serializerInstance(propertyAcc, serDef); } serDef = intr.findContentSerializer(propertyAcc); if (serDef != null) { ser = provider.serializerInstance(propertyAcc, serDef); } } if (ser == null) { ser = _valueSerializer; } // [databind#124]: May have a content converter ser = findContextualConvertingSerializer(provider, property, ser); if (ser == null) { // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated, // we can consider it a static case as well. // 20-Aug-2013, tatu: Need to avoid trying to access serializer for java.lang.Object tho if (_valueTypeIsStatic && !_valueType.isJavaLangObject()) { ser = provider.findValueSerializer(_valueType, property); } } if (keySer == null) { keySer = _keySerializer; } if (keySer == null) { keySer = provider.findKeySerializer(_keyType, property); } else { keySer = provider.handleSecondaryContextualization(keySer, property); } Set<String> ignored = _ignoredEntries; boolean sortKeys = false; if ((intr != null) && (propertyAcc != null)) { JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnorals(propertyAcc); if (ignorals != null) { Set<String> newIgnored = ignorals.findIgnoredForSerialization(); if ((newIgnored != null) && !newIgnored.isEmpty()) { ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored); for (String str : newIgnored) { ignored.add(str); } } } Boolean b = intr.findSerializationSortAlphabetically(propertyAcc); sortKeys = (b != null) && b.booleanValue(); } JsonFormat.Value format = findFormatOverrides(provider, property, Map.class); if (format != null) { Boolean B = format.getFeature(JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES); if (B != null) { sortKeys = B.booleanValue(); } } MapSerializer mser = withResolved(property, keySer, ser, ignored, sortKeys); // [databind#307]: allow filtering if (property != null) { AnnotatedMember m = property.getMember(); if (m != null) { Object filterId = intr.findFilterId(m); if (filterId != null) { mser = mser.withFilterId(filterId); } } JsonInclude.Value inclV = property.findPropertyInclusion(provider.getConfig(), null); if (inclV != null) { JsonInclude.Include incl = inclV.getContentInclusion(); if (incl != JsonInclude.Include.USE_DEFAULTS) { Object valueToSuppress; boolean suppressNulls; switch (incl) { case NON_DEFAULT: valueToSuppress = BeanUtil.getDefaultValue(_valueType); suppressNulls = true; if (valueToSuppress != null) { if (valueToSuppress.getClass().isArray()) { valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress); } } break; case NON_ABSENT: suppressNulls = true; valueToSuppress = _valueType.isReferenceType() ? MARKER_FOR_EMPTY : null; break; case NON_EMPTY: suppressNulls = true; valueToSuppress = MARKER_FOR_EMPTY; break; case CUSTOM: valueToSuppress = provider.includeFilterInstance(null, inclV.getContentFilter()); if (valueToSuppress == null) { // is this legal? suppressNulls = true; } else { suppressNulls = provider.includeFilterSuppressNulls(valueToSuppress); } break; case NON_NULL: valueToSuppress = null; suppressNulls = true; break; case ALWAYS: // default default: valueToSuppress = null; // 30-Sep-2016, tatu: Should not need to check global flags here, // if inclusion forced to be ALWAYS suppressNulls = false; break; } mser = mser.withContentInclusion(valueToSuppress, suppressNulls); } } } return mser; }