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 ResolvedType
s (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);
}
}