package com.fasterxml.classmate;

import java.io.Serializable;
import java.util.*;

import com.fasterxml.classmate.members.*;
import com.fasterxml.classmate.util.ClassKey;

Builder class used to completely resolve members (fields, methods, constructors) of ResolvedTypes (generics-aware classes).
/** * Builder class used to completely resolve members (fields, methods, * constructors) of {@link ResolvedType}s (generics-aware classes). */
@SuppressWarnings("serial") public class MemberResolver implements Serializable {
Type resolved needed for resolving types of member objects (method argument and return; field types; constructor argument types)
/** * Type resolved needed for resolving types of member objects * (method argument and return; field types; constructor argument types) */
protected final TypeResolver _typeResolver; /* /********************************************************************** /* Modifiable configuration /********************************************************************** */
Configuration setting that determines whether members from Object are included or not; by default false meaning that they are not.
/** * Configuration setting that determines whether members from * {@link java.lang.Object} are included or not; by default * false meaning that they are not. */
protected boolean _cfgIncludeLangObject;
Filter used for determining whether given field (static or member) is to be included in aggregation of all fields.
/** * Filter used for determining whether given * field (static or member) * is to be included in aggregation of all * fields. */
protected Filter<RawField> _fieldFilter;
Filter used for determining whether given method (static or member) is to be included in aggregation of all methods.
/** * Filter used for determining whether given * method (static or member) * is to be included in aggregation of all * methods. */
protected Filter<RawMethod> _methodFilter;
Filter used for determining whether given constructor is to be included in aggregation of all constructors.
/** * Filter used for determining whether given * constructor * is to be included in aggregation of all * constructors. */
protected Filter<RawConstructor> _constructorFilter; /* /********************************************************************** /* Life cycle (construct and config) /********************************************************************** */
Constructor for resolver that does not include java.lang.Object in type hierarchy
/** * Constructor for resolver that does not include <code>java.lang.Object</code> * in type hierarchy */
public MemberResolver(TypeResolver typeResolver) { _typeResolver = typeResolver; }
Configuration method for specifying whether members of java.lang.Object are to be included in resolution; if false, no members from Object are to be included; if true, will be included.
/** * Configuration method for specifying whether members of <code>java.lang.Object</code> * are to be included in resolution; if false, no members from {@link java.lang.Object} * are to be included; if true, will be included. */
public MemberResolver setIncludeLangObject(boolean state) { _cfgIncludeLangObject = state; return this; } public MemberResolver setFieldFilter(Filter<RawField> f) { _fieldFilter = f; return this; } public MemberResolver setMethodFilter(Filter<RawMethod> f) { _methodFilter = f; return this; } public MemberResolver setConstructorFilter(Filter<RawConstructor> f) { _constructorFilter = f; return this; } /* /********************************************************************** /* Public API /********************************************************************** */
Method for constructing hierarchy object needed to fully resolve member information, including basic type flattening as well as addition of mix-in types in appropriate positions.
Params:
  • mainType – Resolved type that is the starting point (i.e. the leaf class) for member resolution.
  • annotationConfig – Configuration of annotation types; which ones to include, how to inherit
  • annotationOverrides – Definitions of annotation overrides to use, if any (may be null)
/** * Method for constructing hierarchy object needed to fully resolve * member information, including basic type flattening as well as * addition of mix-in types in appropriate positions. * * @param mainType Resolved type that is the starting point (i.e. the leaf class) * for member resolution. * @param annotationConfig Configuration of annotation types; which ones to include, how to inherit * @param annotationOverrides Definitions of annotation overrides to use, if any (may be null) */
public ResolvedTypeWithMembers resolve(final ResolvedType mainType, AnnotationConfiguration annotationConfig, AnnotationOverrides annotationOverrides) { List<ResolvedType> types = new ArrayList<ResolvedType>(); HashSet<ClassKey> seenTypes = new HashSet<ClassKey>(); // First: flatten basic type hierarchy (highest to lowest precedence) // 09-May-2016, tatu: Special case, from [#30] is that of `Object.class`, which // by default settings has no parentage. Not 100% sure this is proper fix, but // it does take care of the immediate problem. if (!_cfgIncludeLangObject && (mainType.getErasedType() == Object.class)) { types = new ArrayList<ResolvedType>(1); types.add(mainType); seenTypes.add(new ClassKey(Object.class)); } else { types = new ArrayList<ResolvedType>(); _gatherTypes(mainType, seenTypes, types); } // Second step: inject mix-ins (keeping order from highest to lowest) HierarchicType[] htypes; HierarchicType mainHierarchicType = null; // Third step: add mix-ins (if any), reverse order (lowest to highest precedence) if (annotationOverrides == null) { // just create hierarchic instances int len = types.size(); htypes = new HierarchicType[len]; for (int i = 0; i < len; ++i) { // false -> not a mix-in htypes[i] = new HierarchicType(types.get(i), false, i); } mainHierarchicType = htypes[0]; } else { // need to add mix-ins, reorder ArrayList<HierarchicType> typesWithMixins = new ArrayList<HierarchicType>(); for (ResolvedType type : types) { // First add mix-ins (which override type itself) List<Class<?>> m = annotationOverrides.mixInsFor(type.getErasedType()); if (m != null) { for (Class<?> mixinClass : m) { _addOverrides(typesWithMixins, seenTypes, mixinClass); } } // Then actual type: HierarchicType ht = new HierarchicType(type, false, typesWithMixins.size()); if (mainHierarchicType == null) { mainHierarchicType = ht; } typesWithMixins.add(ht); } htypes = typesWithMixins.toArray(new HierarchicType[0]); } // And that's about all we need to do; rest computed lazily return new ResolvedTypeWithMembers(_typeResolver, annotationConfig, mainHierarchicType, htypes, _constructorFilter, _fieldFilter, _methodFilter); } private void _addOverrides(List<HierarchicType> typesWithOverrides, Set<ClassKey> seenTypes, Class<?> override) { ClassKey key = new ClassKey(override); if (!seenTypes.contains(key)) { seenTypes.add(key); ResolvedType resolvedOverride = _typeResolver.resolve(override); typesWithOverrides.add(new HierarchicType(resolvedOverride, true, typesWithOverrides.size())); for (ResolvedType r : resolvedOverride.getImplementedInterfaces()) { // interfaces? _addOverrides(typesWithOverrides, seenTypes, r); } ResolvedType superClass = resolvedOverride.getParentClass(); _addOverrides(typesWithOverrides, seenTypes, superClass); } } private void _addOverrides(List<HierarchicType> typesWithOverrides, Set<ClassKey> seenTypes, ResolvedType override) { if (override == null) return; // first: may need to exclude Object.class: Class<?> raw = override.getErasedType(); if (!_cfgIncludeLangObject && Object.class == raw) return; ClassKey key = new ClassKey(raw); if (!seenTypes.contains(key)) { seenTypes.add(key); typesWithOverrides.add(new HierarchicType(override, true, typesWithOverrides.size())); for (ResolvedType r : override.getImplementedInterfaces()) { // interfaces? _addOverrides(typesWithOverrides, seenTypes, r); } ResolvedType superClass = override.getParentClass(); if (superClass != null) { _addOverrides(typesWithOverrides, seenTypes, superClass); } } } /* /********************************************************************** /* Internal methods /********************************************************************** */ protected void _gatherTypes(ResolvedType currentType, Set<ClassKey> seenTypes, List<ResolvedType> types) { // may get called with null if no parent type if (currentType == null) { return; } Class<?> raw = currentType.getErasedType(); // Also, don't include Object.class unless that's ok if (!_cfgIncludeLangObject && (raw == Object.class)) { return; } // Finally, only include first instance of an interface, so: ClassKey key = new ClassKey(currentType.getErasedType()); if (seenTypes.contains(key)) { return; } // If all good so far, append seenTypes.add(key); types.add(currentType); /* and check supertypes; starting with interfaces. Why interfaces? * So that "highest" interfaces get priority; otherwise we'd recurse * super-class stack and actually start with the bottom. Usually makes * little difference, but in cases where it does this seems like the * correct order. */ for (ResolvedType t : currentType.getImplementedInterfaces()) { _gatherTypes(t, seenTypes, types); } // and then superclass _gatherTypes(currentType.getParentClass(), seenTypes, types); } }