lonord
7 years ago
589 changed files with 23742 additions and 1306 deletions
@ -1,3 +0,0 @@ |
|||||||
# dependence-adapter |
|
||||||
|
|
||||||
该模块为一个辅助的中间模块,为改过包名的第三方包之间的相互引用作适配 |
|
@ -1,65 +0,0 @@ |
|||||||
package com.fr.third.adapter.druid; |
|
||||||
|
|
||||||
import java.sql.Connection; |
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import com.fr.third.org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; |
|
||||||
import com.fr.third.org.hibernate.service.spi.Configurable; |
|
||||||
import com.fr.third.org.hibernate.service.spi.Stoppable; |
|
||||||
|
|
||||||
import com.fr.third.alibaba.druid.pool.DruidDataSource; |
|
||||||
import com.fr.third.alibaba.druid.pool.DruidDataSourceFactory; |
|
||||||
|
|
||||||
public class DruidConnectionProvider implements ConnectionProvider, Configurable, Stoppable { |
|
||||||
|
|
||||||
private static final long serialVersionUID = 1026193803901107651L; |
|
||||||
|
|
||||||
private DruidDataSource dataSource; |
|
||||||
|
|
||||||
public DruidConnectionProvider(){ |
|
||||||
dataSource = new DruidDataSource(); |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes") |
|
||||||
@Override |
|
||||||
public boolean isUnwrappableAs(Class unwrapType) { |
|
||||||
return dataSource.isWrapperFor(unwrapType); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public <T> T unwrap(Class<T> unwrapType) { |
|
||||||
return dataSource.unwrap(unwrapType); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Connection getConnection() throws SQLException { |
|
||||||
return dataSource.getConnection(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void closeConnection(Connection conn) throws SQLException { |
|
||||||
conn.close(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean supportsAggressiveRelease() { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes") |
|
||||||
@Override |
|
||||||
public void configure(Map configurationValues) { |
|
||||||
try { |
|
||||||
DruidDataSourceFactory.config(dataSource, configurationValues); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new IllegalArgumentException("config error", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void stop() { |
|
||||||
dataSource.close(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,6 @@ |
|||||||
|
# fine-classmate |
||||||
|
|
||||||
|
改包名的classmate(1.3.0),以下模块需要依赖该模块: |
||||||
|
|
||||||
|
- fine-hibernate |
||||||
|
|
@ -0,0 +1,115 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.util.ClassKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface for object that determines handling of annotations in regards |
||||||
|
* to inheritance, overrides. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public abstract class AnnotationConfiguration implements Serializable |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Method called to figure out how to handle instances of specified annotation |
||||||
|
* type when used as class annotation. |
||||||
|
*/ |
||||||
|
public abstract AnnotationInclusion getInclusionForClass(Class<? extends Annotation> annotationType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to figure out how to handle instances of specified annotation |
||||||
|
* type when used as constructor annotation. |
||||||
|
*<p> |
||||||
|
* Note that constructor annotations can never be inherited so this just determines |
||||||
|
* between inclusion or non-inclusion. |
||||||
|
*/ |
||||||
|
public abstract AnnotationInclusion getInclusionForConstructor(Class<? extends Annotation> annotationType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to figure out how to handle instances of specified annotation |
||||||
|
* type when used as field annotation. |
||||||
|
*<p> |
||||||
|
* Note that field annotations can never be inherited so this just determines |
||||||
|
* between inclusion or non-inclusion. |
||||||
|
*/ |
||||||
|
public abstract AnnotationInclusion getInclusionForField(Class<? extends Annotation> annotationType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to figure out how to handle instances of specified annotation |
||||||
|
* type when used as method annotation. |
||||||
|
*<p> |
||||||
|
* Note that method annotations can be inherited for member methods, but not for static |
||||||
|
* methods; for static methods thereby this just determines between inclusion and |
||||||
|
* non-inclusion. |
||||||
|
*/ |
||||||
|
public abstract AnnotationInclusion getInclusionForMethod(Class<? extends Annotation> annotationType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to figure out how to handle instances of specified annotation |
||||||
|
* type when used as parameter annotation. |
||||||
|
*<p> |
||||||
|
* Note that parameter annotations can be inherited for member methods, but not for static |
||||||
|
* methods; for static methods thereby this just determines between inclusion and |
||||||
|
* non-inclusion. |
||||||
|
*/ |
||||||
|
public abstract AnnotationInclusion getInclusionForParameter(Class<? extends Annotation> annotationType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple implementation that can be configured with default behavior |
||||||
|
* for unknown annotations, as well as explicit behaviors for |
||||||
|
* enumerated annotation types. Same default is used for both class and |
||||||
|
* member method annotations (constructor, field and static method |
||||||
|
* annotations are never inherited) |
||||||
|
*/ |
||||||
|
public static class StdConfiguration extends AnnotationConfiguration implements Serializable |
||||||
|
{ |
||||||
|
protected final AnnotationInclusion _defaultInclusion; |
||||||
|
|
||||||
|
protected final HashMap<ClassKey,AnnotationInclusion> _inclusions = new HashMap<ClassKey,AnnotationInclusion>(); |
||||||
|
|
||||||
|
public StdConfiguration(AnnotationInclusion defaultBehavior) |
||||||
|
{ |
||||||
|
_defaultInclusion = defaultBehavior; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationInclusion getInclusionForClass(Class<? extends Annotation> annotationType) { |
||||||
|
return _inclusionFor(annotationType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationInclusion getInclusionForConstructor(Class<? extends Annotation> annotationType) { |
||||||
|
return _inclusionFor(annotationType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationInclusion getInclusionForField(Class<? extends Annotation> annotationType) { |
||||||
|
return getInclusionForClass(annotationType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationInclusion getInclusionForMethod(Class<? extends Annotation> annotationType) { |
||||||
|
return getInclusionForClass(annotationType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationInclusion getInclusionForParameter(Class<? extends Annotation> annotationType) { |
||||||
|
return getInclusionForClass(annotationType); |
||||||
|
} |
||||||
|
|
||||||
|
public void setInclusion(Class<? extends Annotation> annotationType, AnnotationInclusion incl) |
||||||
|
{ |
||||||
|
_inclusions.put(new ClassKey(annotationType), incl); |
||||||
|
} |
||||||
|
|
||||||
|
protected AnnotationInclusion _inclusionFor(Class<? extends Annotation> annotationType) |
||||||
|
{ |
||||||
|
ClassKey key = new ClassKey(annotationType); |
||||||
|
AnnotationInclusion beh = _inclusions.get(key); |
||||||
|
return (beh == null) ? _defaultInclusion : beh; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
/** |
||||||
|
* Enumeration that defines different settings for handling behavior |
||||||
|
* of individual annotations |
||||||
|
*/ |
||||||
|
public enum AnnotationInclusion |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Value that indicates that annotation is to be ignored, not included |
||||||
|
* in resolved bean information. |
||||||
|
* Applicable to all member types. |
||||||
|
*/ |
||||||
|
DONT_INCLUDE, |
||||||
|
|
||||||
|
/** |
||||||
|
* Value that indicates that annotation is to be included in results, but |
||||||
|
* only if directly associated with included member (or attached mix-in); |
||||||
|
* will not inherit from supertypes. |
||||||
|
* Applicable only to member methods; if used with other members will |
||||||
|
* mean basic inclusion. |
||||||
|
*/ |
||||||
|
INCLUDE_BUT_DONT_INHERIT, |
||||||
|
|
||||||
|
/** |
||||||
|
* Value that indicates that annotation is to be included in results, and |
||||||
|
* values from overridden members are inherited only if the annotation is |
||||||
|
* marked with the {@link java.lang.annotation.Inherited} annotation. |
||||||
|
* Applicable only to member methods; if used with other members will |
||||||
|
* mean basic inclusion. |
||||||
|
*/ |
||||||
|
INCLUDE_AND_INHERIT_IF_INHERITED, |
||||||
|
|
||||||
|
/** |
||||||
|
* Value that indicates that annotation is to be included in results; and |
||||||
|
* values from overridden members are also inherited if not overridden |
||||||
|
* by members of subtypes. |
||||||
|
* Note that inheritance only matters with member methods; for other types |
||||||
|
* it just means "include". |
||||||
|
*/ |
||||||
|
INCLUDE_AND_INHERIT |
||||||
|
; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.util.ClassKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface for object that can provide mix-ins to override annotations. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public abstract class AnnotationOverrides implements Serializable |
||||||
|
{ |
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Public API |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to find out which class(es) are to be used as source |
||||||
|
* for annotations to mix in for given type. |
||||||
|
* |
||||||
|
* @return List of mix-in sources (starting with highest priority); |
||||||
|
* can be null or empty list if no mix-ins are to be used. |
||||||
|
*/ |
||||||
|
public List<Class<?>> mixInsFor(Class<?> beanClass) { |
||||||
|
return mixInsFor(new ClassKey(beanClass)); |
||||||
|
} |
||||||
|
|
||||||
|
public abstract List<Class<?>> mixInsFor(ClassKey beanClass); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for constructing builder for creating simple overrides provider |
||||||
|
* that just uses direct assignments (target-to-override classes) |
||||||
|
*/ |
||||||
|
public static StdBuilder builder() { |
||||||
|
return new StdBuilder(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* To make it easy to use simple override implementation (where overrides |
||||||
|
* are direct and explicit), here is a build that allow constructing |
||||||
|
* such override instance. |
||||||
|
*/ |
||||||
|
public static class StdBuilder |
||||||
|
{ |
||||||
|
protected final HashMap<ClassKey,List<Class<?>>> _targetsToOverrides = new HashMap<ClassKey,List<Class<?>>>(); |
||||||
|
|
||||||
|
public StdBuilder() { } |
||||||
|
|
||||||
|
public StdBuilder add(Class<?> target, Class<?> mixin) { |
||||||
|
return add(new ClassKey(target), mixin); |
||||||
|
} |
||||||
|
|
||||||
|
public StdBuilder add(ClassKey target, Class<?> mixin) |
||||||
|
{ |
||||||
|
List<Class<?>> mixins = _targetsToOverrides.get(target); |
||||||
|
if (mixins == null) { |
||||||
|
mixins = new ArrayList<Class<?>>(); |
||||||
|
_targetsToOverrides.put(target, mixins); |
||||||
|
} |
||||||
|
mixins.add(mixin); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that will construct a {@link AnnotationOverrides} instance using |
||||||
|
* mappings that have been added using this builder |
||||||
|
*/ |
||||||
|
public AnnotationOverrides build() { |
||||||
|
return new StdImpl(_targetsToOverrides); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple implementation configured with explicit associations with |
||||||
|
* target class as key, and overrides as ordered list of classes |
||||||
|
* (with first entry having precedence over later ones). |
||||||
|
*/ |
||||||
|
public static class StdImpl extends AnnotationOverrides |
||||||
|
{ |
||||||
|
protected final HashMap<ClassKey,List<Class<?>>> _targetsToOverrides; |
||||||
|
|
||||||
|
public StdImpl(HashMap<ClassKey,List<Class<?>>> overrides) { |
||||||
|
_targetsToOverrides = new HashMap<ClassKey,List<Class<?>>>(overrides); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<Class<?>> mixInsFor(ClassKey target) { |
||||||
|
return _targetsToOverrides.get(target); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,132 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Container class used for storing set of annotations resolved for types (classes) |
||||||
|
* as members (methods, fields, constructors). |
||||||
|
* |
||||||
|
* @author tatu |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public class Annotations implements Serializable, Iterable<Annotation> |
||||||
|
{ |
||||||
|
private final Annotation[] NO_ANNOTATIONS = new Annotation[0]; |
||||||
|
|
||||||
|
protected LinkedHashMap<Class<? extends Annotation>,Annotation> _annotations; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life-cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public Annotations() { } |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for adding specified annotation, overriding existing value |
||||||
|
* for the annotation type. |
||||||
|
*/ |
||||||
|
public void add(Annotation override) |
||||||
|
{ |
||||||
|
if (_annotations == null) { |
||||||
|
_annotations = new LinkedHashMap<Class<? extends Annotation>,Annotation>(); |
||||||
|
} |
||||||
|
_annotations.put(override.annotationType(), override); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for adding all annotations from specified set, as overrides |
||||||
|
* to annotations this set has |
||||||
|
*/ |
||||||
|
public void addAll(Annotations overrides) |
||||||
|
{ |
||||||
|
if (_annotations == null) { |
||||||
|
_annotations = new LinkedHashMap<Class<? extends Annotation>,Annotation>(); |
||||||
|
} |
||||||
|
for (Annotation override : overrides._annotations.values()) { |
||||||
|
_annotations.put(override.annotationType(), override); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for adding specified annotation if and only if no value |
||||||
|
* exists for the annotation type. |
||||||
|
*/ |
||||||
|
public void addAsDefault(Annotation defValue) |
||||||
|
{ |
||||||
|
Class<? extends Annotation> type = defValue.annotationType(); |
||||||
|
if (_annotations == null) { |
||||||
|
_annotations = new LinkedHashMap<Class<? extends Annotation>,Annotation>(); |
||||||
|
_annotations.put(type, defValue); |
||||||
|
} else if (!_annotations.containsKey(type)) { |
||||||
|
_annotations.put(type, defValue); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterator<Annotation> iterator() |
||||||
|
{ |
||||||
|
if (_annotations == null) { |
||||||
|
_annotations = new LinkedHashMap<Class<? extends Annotation>,Annotation>(); |
||||||
|
} |
||||||
|
return _annotations.values().iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
public int size() { |
||||||
|
return (_annotations == null) ? 0 : _annotations.size(); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public <A extends Annotation> A get(Class<A> cls) |
||||||
|
{ |
||||||
|
if (_annotations == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return (A) _annotations.get(cls); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 1.1.1 |
||||||
|
*/ |
||||||
|
public Annotation[] asArray() { |
||||||
|
if (_annotations == null || _annotations.isEmpty()) { |
||||||
|
return NO_ANNOTATIONS; |
||||||
|
} |
||||||
|
return _annotations.values().toArray(new Annotation[_annotations.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 1.1.1 |
||||||
|
*/ |
||||||
|
public List<Annotation> asList() { |
||||||
|
if (_annotations == null || _annotations.isEmpty()) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
List<Annotation> l = new ArrayList<Annotation>(_annotations.size()); |
||||||
|
l.addAll(_annotations.values()); |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard method overrides |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public String toString() |
||||||
|
{ |
||||||
|
if (_annotations == null) { |
||||||
|
return "[null]"; |
||||||
|
} |
||||||
|
return _annotations.toString(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface that defines API for basic filtering objects, used to prune set |
||||||
|
* of things to include in result sets like flattened member lists. |
||||||
|
*/ |
||||||
|
public interface Filter<T> |
||||||
|
{ |
||||||
|
public boolean include(T element); |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is used to pass full generics type information, and |
||||||
|
* avoid problems with type erasure (that basically removes most |
||||||
|
* usable type references from runtime Class objects). |
||||||
|
* It is based on ideas from |
||||||
|
* <a href="http://gafter.blogspot.com/2006/12/super-type-tokens.html" |
||||||
|
* >http://gafter.blogspot.com/2006/12/super-type-tokens.html</a>,
|
||||||
|
*<p> |
||||||
|
* Usage is by sub-classing: here is one way to instantiate reference |
||||||
|
* to generic type <code>List<Integer></code>: |
||||||
|
*<pre> |
||||||
|
* GenericType type = new GenericType<List<Integer>>() { }; |
||||||
|
*</pre> |
||||||
|
* which can be passed to methods that accept <code>GenericReference</code>. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public abstract class GenericType<T> |
||||||
|
implements Serializable, java.lang.reflect.Type |
||||||
|
{ |
||||||
|
protected GenericType() { } |
||||||
|
} |
@ -0,0 +1,235 @@ |
|||||||
|
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 {@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) |
||||||
|
*/ |
||||||
|
protected final TypeResolver _typeResolver; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Modifiable configuration |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
protected Filter<RawField> _fieldFilter; |
||||||
|
|
||||||
|
/** |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
protected Filter<RawConstructor> _constructorFilter; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle (construct and config) |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 <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. |
||||||
|
* |
||||||
|
* @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) |
||||||
|
{ |
||||||
|
// First: flatten basic type hierarchy (highest to lowest precedence)
|
||||||
|
HashSet<ClassKey> seenTypes = new HashSet<ClassKey>(); |
||||||
|
ArrayList<ResolvedType> 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[typesWithMixins.size()]); |
||||||
|
} |
||||||
|
// 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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,399 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.members.*; |
||||||
|
|
||||||
|
public abstract class ResolvedType |
||||||
|
implements Type |
||||||
|
{ |
||||||
|
public final static ResolvedType[] NO_TYPES = new ResolvedType[0]; |
||||||
|
|
||||||
|
protected final static RawConstructor[] NO_CONSTRUCTORS = new RawConstructor[0]; |
||||||
|
protected final static RawField[] NO_FIELDS = new RawField[0]; |
||||||
|
protected final static RawMethod[] NO_METHODS = new RawMethod[0]; |
||||||
|
|
||||||
|
protected final Class<?> _erasedType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Type bindings active when resolving members (methods, fields, |
||||||
|
* constructors) of this type |
||||||
|
*/ |
||||||
|
protected final TypeBindings _typeBindings; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected ResolvedType(Class<?> cls, TypeBindings bindings) |
||||||
|
{ |
||||||
|
_erasedType = cls; |
||||||
|
_typeBindings = (bindings == null) ? TypeBindings.emptyBindings() : bindings; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)} |
||||||
|
* may ever succeed; if false, it will fail with an exception, if true, it may succeed. |
||||||
|
*/ |
||||||
|
public abstract boolean canCreateSubtypes(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that can be used to check if call to {@link TypeResolver#resolveSubtype(ResolvedType, Class)} |
||||||
|
* will succeed for specific type; if false, it will fail with an exception; if tru it |
||||||
|
* will succeed. |
||||||
|
*/ |
||||||
|
public final boolean canCreateSubtype(Class<?> subtype) { |
||||||
|
return canCreateSubtypes() && _erasedType.isAssignableFrom(subtype); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns type-erased Class<?> that this resolved type has. |
||||||
|
*/ |
||||||
|
public Class<?> getErasedType() { return _erasedType; } |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns parent class of this type, if it has one; primitive types |
||||||
|
* and interfaces have no parent class, nor does Object type |
||||||
|
* {@link java.lang.Object}. |
||||||
|
* Also, placeholders for cyclic (recursive) types return null for |
||||||
|
* this method. |
||||||
|
*/ |
||||||
|
public abstract ResolvedType getParentClass(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Accessor that must be used to find out actual type in |
||||||
|
* case of "self-reference"; case where type refers |
||||||
|
* recursive to itself (like, <code>T implements Comparable<T></code>). |
||||||
|
* For all other types returns null but for self-references "real" type. |
||||||
|
* Separate accessor is provided to avoid accidental infinite loops. |
||||||
|
*/ |
||||||
|
public abstract ResolvedType getSelfReferencedType(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that can be used to access element type of array types; will return |
||||||
|
* null for non-array types, and non-null type for array types. |
||||||
|
*/ |
||||||
|
public abstract ResolvedType getArrayElementType(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns ordered list of interfaces (in declaration order) that this type |
||||||
|
* implements. |
||||||
|
* |
||||||
|
* @return List of interfaces this type implements, if any; empty list if none |
||||||
|
*/ |
||||||
|
public abstract List<ResolvedType> getImplementedInterfaces(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns list of generic type declarations for this type, in order they |
||||||
|
* are declared in class description. |
||||||
|
*/ |
||||||
|
public List<ResolvedType> getTypeParameters() { |
||||||
|
return _typeBindings.getTypeParameters(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for accessing bindings of type variables to resolved types in context |
||||||
|
* of this type. It has same number of entries as return List of |
||||||
|
* {@link #getTypeParameters}, accessible using declared name to which they |
||||||
|
* bind; for example, {@link java.util.Map} has 2 type bindings; one for |
||||||
|
* key type (name "K", from Map.java) and one for value type |
||||||
|
* (name "V", from Map.java). |
||||||
|
*/ |
||||||
|
public TypeBindings getTypeBindings() { return _typeBindings; } |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that will try to find type parameterization this type |
||||||
|
* has for specified super type |
||||||
|
* |
||||||
|
* @return List of type parameters for specified supertype (which may |
||||||
|
* be empty, if supertype is not a parametric type); null if specified |
||||||
|
* type is not a super type of this type |
||||||
|
*/ |
||||||
|
public List<ResolvedType> typeParametersFor(Class<?> erasedSupertype) |
||||||
|
{ |
||||||
|
ResolvedType type = findSupertype(erasedSupertype); |
||||||
|
if (type != null) { |
||||||
|
return type.getTypeParameters(); |
||||||
|
} |
||||||
|
// nope; doesn't look like we extend or implement super type in question
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for finding super type of this type that has specified type |
||||||
|
* erased signature. If supertype is an interface which is implemented |
||||||
|
* using multiple inheritance paths, preference is given to interfaces |
||||||
|
* implemented "highest up the stack" (directly implemented interfaces |
||||||
|
* over interfaces superclass implements). |
||||||
|
*/ |
||||||
|
public ResolvedType findSupertype(Class<?> erasedSupertype) |
||||||
|
{ |
||||||
|
if (erasedSupertype == _erasedType) { |
||||||
|
return this; |
||||||
|
} |
||||||
|
// Check super interfaces first:
|
||||||
|
if (erasedSupertype.isInterface()) { |
||||||
|
for (ResolvedType it : getImplementedInterfaces()) { |
||||||
|
ResolvedType type = it.findSupertype(erasedSupertype); |
||||||
|
if (type != null) { |
||||||
|
return type; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// and if not found, super class and its supertypes
|
||||||
|
ResolvedType pc = getParentClass(); |
||||||
|
if (pc != null) { |
||||||
|
ResolvedType type = pc.findSupertype(erasedSupertype); |
||||||
|
if (type != null) { |
||||||
|
return type; |
||||||
|
} |
||||||
|
} |
||||||
|
// nope; doesn't look like we extend or implement super type in question
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for simple properties |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public abstract boolean isInterface(); |
||||||
|
public final boolean isConcrete() { return !isAbstract(); } |
||||||
|
public abstract boolean isAbstract(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that indicates whether this type is an array type. |
||||||
|
*/ |
||||||
|
public abstract boolean isArray(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that indicates whether this type is one of small number of primitive |
||||||
|
* Java types; not including array types of primitive types but just basic |
||||||
|
* primitive types. |
||||||
|
*/ |
||||||
|
public abstract boolean isPrimitive(); |
||||||
|
|
||||||
|
public final boolean isInstanceOf(Class<?> type) { |
||||||
|
return type.isAssignableFrom(_erasedType); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public List<RawConstructor> getConstructors() { return Collections.emptyList(); } |
||||||
|
public List<RawField> getMemberFields() { return Collections.emptyList(); } |
||||||
|
public List<RawMethod> getMemberMethods() { return Collections.emptyList(); } |
||||||
|
public List<RawField> getStaticFields() { return Collections.emptyList(); } |
||||||
|
public List<RawMethod> getStaticMethods() { return Collections.emptyList(); } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that returns full generic signature of the type; suitable |
||||||
|
* as signature for things like ASM package. |
||||||
|
*/ |
||||||
|
public String getSignature() { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
return appendSignature(sb).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that returns type erased signature of the type; suitable |
||||||
|
* as non-generic signature some packages need |
||||||
|
*/ |
||||||
|
public String getErasedSignature() { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
return appendErasedSignature(sb).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Human-readable full description of type, which includes specification |
||||||
|
* of super types (in brief format) |
||||||
|
*/ |
||||||
|
public String getFullDescription() { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
return appendFullDescription(sb).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Human-readable brief description of type, which does not include |
||||||
|
* information about super types. |
||||||
|
*/ |
||||||
|
public String getBriefDescription() { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
return appendBriefDescription(sb).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public abstract StringBuilder appendBriefDescription(StringBuilder sb); |
||||||
|
public abstract StringBuilder appendFullDescription(StringBuilder sb); |
||||||
|
public abstract StringBuilder appendSignature(StringBuilder sb); |
||||||
|
public abstract StringBuilder appendErasedSignature(StringBuilder sb); |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public String toString() { |
||||||
|
return getBriefDescription(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public int hashCode() { |
||||||
|
return _erasedType.getName().hashCode() + _typeBindings.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
// sub-types must be same:
|
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
// Should be possible to actually implement here...
|
||||||
|
ResolvedType other = (ResolvedType) o; |
||||||
|
if (other._erasedType != _erasedType) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
// and type bindings must match as well
|
||||||
|
return _typeBindings.equals(other._typeBindings); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper methods for sub-classes; string construction |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected StringBuilder _appendClassSignature(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb.append('L'); |
||||||
|
sb = _appendClassName(sb); |
||||||
|
int count = _typeBindings.size(); |
||||||
|
if (count > 0) { |
||||||
|
sb.append('<'); |
||||||
|
for (int i = 0; i < count; ++i) { |
||||||
|
sb = _typeBindings.getBoundType(i).appendErasedSignature(sb); |
||||||
|
} |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
sb.append(';'); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
protected StringBuilder _appendErasedClassSignature(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb.append('L'); |
||||||
|
sb = _appendClassName(sb); |
||||||
|
sb.append(';'); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
protected StringBuilder _appendClassDescription(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb.append(_erasedType.getName()); |
||||||
|
int count = _typeBindings.size(); |
||||||
|
if (count > 0) { |
||||||
|
sb.append('<'); |
||||||
|
for (int i = 0; i < count; ++i) { |
||||||
|
if (i > 0) { |
||||||
|
sb.append(','); |
||||||
|
} |
||||||
|
sb = _typeBindings.getBoundType(i).appendBriefDescription(sb); |
||||||
|
} |
||||||
|
sb.append('>'); |
||||||
|
} |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
protected StringBuilder _appendClassName(StringBuilder sb) |
||||||
|
{ |
||||||
|
String name = _erasedType.getName(); |
||||||
|
for (int i = 0, len = name.length(); i < len; ++i) { |
||||||
|
char c = name.charAt(i); |
||||||
|
if (c == '.') c = '/'; |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper methods for sub-classes; gathering members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* @param statics Whether to return static methods (true) or member methods (false) |
||||||
|
*/ |
||||||
|
protected RawField[] _getFields(boolean statics) |
||||||
|
{ |
||||||
|
ArrayList<RawField> fields = new ArrayList<RawField>(); |
||||||
|
for (Field f : _erasedType.getDeclaredFields()) { |
||||||
|
// Only skip synthetic fields, which should not really be exposed
|
||||||
|
if (!f.isSynthetic()) { |
||||||
|
if (Modifier.isStatic(f.getModifiers()) == statics) { |
||||||
|
fields.add(new RawField(this, f)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (fields.isEmpty()) { |
||||||
|
return NO_FIELDS; |
||||||
|
} |
||||||
|
return fields.toArray(new RawField[fields.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param statics Whether to return static methods (true) or member methods (false) |
||||||
|
*/ |
||||||
|
protected RawMethod[] _getMethods(boolean statics) |
||||||
|
{ |
||||||
|
ArrayList<RawMethod> methods = new ArrayList<RawMethod>(); |
||||||
|
for (Method m : _erasedType.getDeclaredMethods()) { |
||||||
|
// Only skip synthetic fields, which should not really be exposed
|
||||||
|
if (!m.isSynthetic()) { |
||||||
|
if (Modifier.isStatic(m.getModifiers()) == statics) { |
||||||
|
methods.add(new RawMethod(this, m)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (methods.isEmpty()) { |
||||||
|
return NO_METHODS; |
||||||
|
} |
||||||
|
return methods.toArray(new RawMethod[methods.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
protected RawConstructor[] _getConstructors() |
||||||
|
{ |
||||||
|
ArrayList<RawConstructor> ctors = new ArrayList<RawConstructor>(); |
||||||
|
for (Constructor<?> c : _erasedType.getDeclaredConstructors()) { |
||||||
|
// Only skip synthetic fields, which should not really be exposed
|
||||||
|
if (!c.isSynthetic()) { |
||||||
|
ctors.add(new RawConstructor(this, c)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (ctors.isEmpty()) { |
||||||
|
return NO_CONSTRUCTORS; |
||||||
|
} |
||||||
|
return ctors.toArray(new RawConstructor[ctors.size()]); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,715 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.lang.annotation.Inherited; |
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Type; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.members.*; |
||||||
|
import com.fasterxml.classmate.util.MethodKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* Class that contains information about fully resolved members of a |
||||||
|
* type; resolution meaning that masking is handled for methods, and |
||||||
|
* all inheritable annotations are flattened using optional overrides |
||||||
|
* as well ("mix-in annotations"). |
||||||
|
* Instances are created by {@link com.fasterxml.classmate.MemberResolver}. |
||||||
|
*<p> |
||||||
|
* Note that instances are not thread-safe, as the expectation is that instances |
||||||
|
* will not be shared (unlike raw members or resolved types) |
||||||
|
*/ |
||||||
|
public class ResolvedTypeWithMembers |
||||||
|
{ |
||||||
|
private final static ResolvedType[] NO_RESOLVED_TYPES = new ResolvedType[0]; |
||||||
|
|
||||||
|
private final static ResolvedMethod[] NO_RESOLVED_METHODS = new ResolvedMethod[0]; |
||||||
|
private final static ResolvedField[] NO_RESOLVED_FIELDS = new ResolvedField[0]; |
||||||
|
private final static ResolvedConstructor[] NO_RESOLVED_CONSTRUCTORS = new ResolvedConstructor[0]; |
||||||
|
|
||||||
|
/** |
||||||
|
* Default annotation configuration is to ignore all annotations types. |
||||||
|
*/ |
||||||
|
protected final static AnnotationConfiguration DEFAULT_ANNOTATION_CONFIG |
||||||
|
= new AnnotationConfiguration.StdConfiguration(AnnotationInclusion.DONT_INCLUDE); |
||||||
|
|
||||||
|
/** |
||||||
|
* Need to be able to resolve member types still |
||||||
|
*/ |
||||||
|
protected final TypeResolver _typeResolver; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handler for resolving annotation information |
||||||
|
*/ |
||||||
|
protected final AnnotationHandler _annotationHandler; |
||||||
|
|
||||||
|
/** |
||||||
|
* Leaf of the type hierarchy, i.e. type from which this hierarchy |
||||||
|
* was generated. |
||||||
|
*/ |
||||||
|
protected final HierarchicType _mainType; |
||||||
|
|
||||||
|
/** |
||||||
|
* All types that hierarchy contains, in order of increasing precedence |
||||||
|
* (that is, later entries override members of earlier members) |
||||||
|
*/ |
||||||
|
protected final HierarchicType[] _types; |
||||||
|
|
||||||
|
/** |
||||||
|
* Filter to use for selecting fields to include |
||||||
|
*/ |
||||||
|
protected Filter<RawField> _fieldFilter; |
||||||
|
|
||||||
|
/** |
||||||
|
* Filter to use for selecting constructors to include |
||||||
|
*/ |
||||||
|
protected Filter<RawConstructor> _constructorFilter; |
||||||
|
|
||||||
|
/** |
||||||
|
* Filter to use for selecting methods to include |
||||||
|
*/ |
||||||
|
protected Filter<RawMethod> _methodFilter; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Lazily constructed members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected ResolvedMethod[] _staticMethods = null; |
||||||
|
|
||||||
|
protected ResolvedField[] _staticFields = null; |
||||||
|
|
||||||
|
protected ResolvedMethod[] _memberMethods = null; |
||||||
|
|
||||||
|
protected ResolvedField[] _memberFields = null; |
||||||
|
|
||||||
|
protected ResolvedConstructor[] _constructors = null; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle at this point |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedTypeWithMembers(TypeResolver typeResolver, AnnotationConfiguration annotationConfig, |
||||||
|
HierarchicType mainType, HierarchicType[] types, |
||||||
|
Filter<RawConstructor> constructorFilter, Filter<RawField> fieldFilter, Filter<RawMethod> methodFilter) |
||||||
|
{ |
||||||
|
_typeResolver = typeResolver; |
||||||
|
_mainType = mainType; |
||||||
|
_types = types; |
||||||
|
if (annotationConfig == null) { |
||||||
|
annotationConfig = DEFAULT_ANNOTATION_CONFIG; |
||||||
|
} |
||||||
|
_annotationHandler = new AnnotationHandler(annotationConfig); |
||||||
|
_constructorFilter = constructorFilter; |
||||||
|
_fieldFilter = fieldFilter; |
||||||
|
_methodFilter = methodFilter; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Public API, access to component types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public int size() { return _types.length; } |
||||||
|
|
||||||
|
/** |
||||||
|
* Accessor for getting full type hierarchy as priority-ordered list, from |
||||||
|
* the lowest precedence to highest precedence (main type, its mix-in overrides) |
||||||
|
*/ |
||||||
|
public List<HierarchicType> allTypesAndOverrides() { |
||||||
|
return Arrays.asList(_types); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Accessor for getting subset of type hierarchy which only contains main type |
||||||
|
* and possible overrides (mix-ins) it has, but not supertypes or their overrides. |
||||||
|
*/ |
||||||
|
public List<HierarchicType> mainTypeAndOverrides() |
||||||
|
{ |
||||||
|
List<HierarchicType> l = Arrays.asList(_types); |
||||||
|
int end = _mainType.getPriority() + 1; |
||||||
|
if (end < l.size()) { |
||||||
|
l = l.subList(0, end); |
||||||
|
} |
||||||
|
return l; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Accessor for finding just overrides for the main type (if any). |
||||||
|
*/ |
||||||
|
public List<HierarchicType> overridesOnly() |
||||||
|
{ |
||||||
|
int index = _mainType.getPriority(); |
||||||
|
if (index == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
List<HierarchicType> l = Arrays.asList(_types); |
||||||
|
return l.subList(0, index); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Public API, actual resolution of members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for finding all static fields of the main type (except for ones |
||||||
|
* possibly filtered out by filter) and applying annotation overrides, if any, |
||||||
|
* to annotations. |
||||||
|
* |
||||||
|
* @since 1.2.0 |
||||||
|
*/ |
||||||
|
public ResolvedField[] getStaticFields() |
||||||
|
{ |
||||||
|
if (_staticFields == null) { |
||||||
|
_staticFields = resolveStaticFields(); |
||||||
|
} |
||||||
|
return _staticFields; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for finding all static methods of the main type (except for ones |
||||||
|
* possibly filtered out by filter) and applying annotation overrides, if any, |
||||||
|
* to annotations. |
||||||
|
*/ |
||||||
|
public ResolvedMethod[] getStaticMethods() |
||||||
|
{ |
||||||
|
if (_staticMethods == null) { |
||||||
|
_staticMethods = resolveStaticMethods(); |
||||||
|
} |
||||||
|
return _staticMethods; |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedField[] getMemberFields() |
||||||
|
{ |
||||||
|
if (_memberFields == null) { |
||||||
|
_memberFields = resolveMemberFields(); |
||||||
|
} |
||||||
|
return _memberFields; |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedMethod[] getMemberMethods() |
||||||
|
{ |
||||||
|
if (_memberMethods == null) { |
||||||
|
_memberMethods = resolveMemberMethods(); |
||||||
|
} |
||||||
|
return _memberMethods; |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedConstructor[] getConstructors() |
||||||
|
{ |
||||||
|
if (_constructors == null) { |
||||||
|
_constructors = resolveConstructors(); |
||||||
|
} |
||||||
|
return _constructors; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Internal methods: actual resolution |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that will actually resolve full information (types, annotations) |
||||||
|
* for constructors of the main type. |
||||||
|
*/ |
||||||
|
protected ResolvedConstructor[] resolveConstructors() |
||||||
|
{ |
||||||
|
// First get static methods for main type, filter
|
||||||
|
LinkedHashMap<MethodKey, ResolvedConstructor> constructors = new LinkedHashMap<MethodKey, ResolvedConstructor>(); |
||||||
|
for (RawConstructor constructor : _mainType.getType().getConstructors()) { |
||||||
|
// no filter for constructors (yet?)
|
||||||
|
if (_constructorFilter == null || _constructorFilter.include(constructor)) { |
||||||
|
constructors.put(constructor.createKey(), resolveConstructor(constructor)); |
||||||
|
} |
||||||
|
} |
||||||
|
// then apply overrides (mix-ins):
|
||||||
|
for (HierarchicType type : overridesOnly()) { |
||||||
|
for (RawConstructor raw : type.getType().getConstructors()) { |
||||||
|
ResolvedConstructor constructor = constructors.get(raw.createKey()); |
||||||
|
// must override something, otherwise to ignore
|
||||||
|
if (constructor != null) { |
||||||
|
for (Annotation ann : raw.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeMethodAnnotation(ann)) { |
||||||
|
constructor.applyOverride(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// and parameter annotations
|
||||||
|
Annotation[][] params = raw.getRawMember().getParameterAnnotations(); |
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
for (Annotation annotation : params[i]) { |
||||||
|
if (_annotationHandler.includeParameterAnnotation(annotation)) { |
||||||
|
constructor.applyParamOverride(i, annotation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (constructors.size() == 0) { |
||||||
|
return NO_RESOLVED_CONSTRUCTORS; |
||||||
|
} |
||||||
|
return constructors.values().toArray(new ResolvedConstructor[constructors.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for fully resolving field definitions and associated annotations. |
||||||
|
* Neither field definitions nor associated annotations inherit, but we may |
||||||
|
* still need to add annotation overrides, as well as filter out filters |
||||||
|
* and annotations that caller is not interested in. |
||||||
|
*/ |
||||||
|
protected ResolvedField[] resolveMemberFields() |
||||||
|
{ |
||||||
|
LinkedHashMap<String, ResolvedField> fields = new LinkedHashMap<String, ResolvedField>(); |
||||||
|
|
||||||
|
/* Fields need different handling: must start from bottom; and annotations only get added |
||||||
|
* as overrides, never as defaults. And sub-classes fully mask fields. This makes |
||||||
|
* handling bit simpler than that of member methods. |
||||||
|
*/ |
||||||
|
for (int typeIndex = _types.length; --typeIndex >= 0; ) { |
||||||
|
HierarchicType thisType = _types[typeIndex]; |
||||||
|
// If it's just a mix-in, add annotations as overrides
|
||||||
|
if (thisType.isMixin()) { |
||||||
|
for (RawField raw : thisType.getType().getMemberFields()) { |
||||||
|
if ((_fieldFilter != null) && !_fieldFilter.include(raw)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
ResolvedField field = fields.get(raw.getName()); |
||||||
|
if (field != null) { |
||||||
|
for (Annotation ann : raw.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeMethodAnnotation(ann)) { |
||||||
|
field.applyOverride(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else { // If actual type, add fields, masking whatever might have existed before:
|
||||||
|
for (RawField field : thisType.getType().getMemberFields()) { |
||||||
|
if ((_fieldFilter != null) && !_fieldFilter.include(field)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
fields.put(field.getName(), resolveField(field)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// and that's it?
|
||||||
|
if (fields.size() == 0) { |
||||||
|
return NO_RESOLVED_FIELDS; |
||||||
|
} |
||||||
|
return fields.values().toArray(new ResolvedField[fields.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
protected ResolvedMethod[] resolveMemberMethods() |
||||||
|
{ |
||||||
|
LinkedHashMap<MethodKey, ResolvedMethod> methods = new LinkedHashMap<MethodKey, ResolvedMethod>(); |
||||||
|
LinkedHashMap<MethodKey, Annotations> overrides = new LinkedHashMap<MethodKey, Annotations>(); |
||||||
|
LinkedHashMap<MethodKey, Annotations[]> paramOverrides = new LinkedHashMap<MethodKey, Annotations[]>(); |
||||||
|
|
||||||
|
/* Member methods are handled from top to bottom; and annotations are tracked |
||||||
|
* alongside (for overrides), as well as "merged down" for inheritable |
||||||
|
* annotations. |
||||||
|
*/ |
||||||
|
for (HierarchicType type : allTypesAndOverrides()) { |
||||||
|
for (RawMethod method : type.getType().getMemberMethods()) { |
||||||
|
// First: ignore methods caller is not interested
|
||||||
|
if (_methodFilter != null && !_methodFilter.include(method)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
MethodKey key = method.createKey(); |
||||||
|
ResolvedMethod old = methods.get(key); |
||||||
|
|
||||||
|
// Ok, now, mix-ins only contribute annotations; whereas 'real' types methods
|
||||||
|
if (type.isMixin()) { // mix-in: only get annotations
|
||||||
|
for (Annotation ann : method.getAnnotations()) { |
||||||
|
// If already have a method, must be inheritable to include
|
||||||
|
if (old != null) { |
||||||
|
if (!methodCanInherit(ann)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
// and if so, apply as default (i.e. do not override)
|
||||||
|
old.applyDefault(ann); |
||||||
|
} else { // If no method, need to add to annotation override map
|
||||||
|
Annotations oldAnn = overrides.get(key); |
||||||
|
if (oldAnn == null) { |
||||||
|
oldAnn = new Annotations(); |
||||||
|
oldAnn.add(ann); |
||||||
|
overrides.put(key, oldAnn); |
||||||
|
} else { |
||||||
|
oldAnn.addAsDefault(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// override argument annotations
|
||||||
|
final Annotation[][] argAnnotations = method.getRawMember().getParameterAnnotations(); |
||||||
|
if (old == null) { // no method (yet), add argument annotations to override map
|
||||||
|
Annotations[] oldParamAnns = paramOverrides.get(key); |
||||||
|
if (oldParamAnns == null) { // no existing argument annotations for method
|
||||||
|
oldParamAnns = new Annotations[argAnnotations.length]; |
||||||
|
for (int i = 0; i < argAnnotations.length; i++) { |
||||||
|
oldParamAnns[i] = new Annotations(); |
||||||
|
for (final Annotation annotation : argAnnotations[i]) { |
||||||
|
if (parameterCanInherit(annotation)) { |
||||||
|
oldParamAnns[i].add(annotation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
paramOverrides.put(key, oldParamAnns); |
||||||
|
} else { |
||||||
|
for (int i = 0; i < argAnnotations.length; i++) { |
||||||
|
for (final Annotation annotation : argAnnotations[i]) { |
||||||
|
if (parameterCanInherit(annotation)) { |
||||||
|
oldParamAnns[i].addAsDefault(annotation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else { // already have a method, apply argument annotations as defaults
|
||||||
|
for (int i = 0; i < argAnnotations.length; i++) { |
||||||
|
for (final Annotation annotation : argAnnotations[i]) { |
||||||
|
if (parameterCanInherit(annotation)) { |
||||||
|
old.applyParamDefault(i, annotation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} else { // "real" methods; add if not present, possibly add defaults as well
|
||||||
|
if (old == null) { // new one to add
|
||||||
|
ResolvedMethod newMethod = resolveMethod(method); |
||||||
|
methods.put(key, newMethod); |
||||||
|
// But we may also have annotation overrides, so:
|
||||||
|
Annotations overrideAnn = overrides.get(key); |
||||||
|
if (overrideAnn != null) { |
||||||
|
newMethod.applyOverrides(overrideAnn); |
||||||
|
} |
||||||
|
// and apply parameter annotation overrides
|
||||||
|
Annotations[] annotations = paramOverrides.get(key); |
||||||
|
if (annotations != null) { |
||||||
|
for (int i = 0; i < annotations.length; i++) { |
||||||
|
newMethod.applyParamOverrides(i, annotations[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { // method masked by something else? can only contribute annotations
|
||||||
|
for (Annotation ann : method.getAnnotations()) { |
||||||
|
if (methodCanInherit(ann)) { |
||||||
|
old.applyDefault(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
// and parameter annotations
|
||||||
|
final Annotation[][] parameterAnnotations = method.getRawMember().getParameterAnnotations(); |
||||||
|
for (int i = 0; i < parameterAnnotations.length; i++) { |
||||||
|
for (final Annotation annotation : parameterAnnotations[i]) { |
||||||
|
if (parameterCanInherit(annotation)) { |
||||||
|
old.applyParamDefault(i, annotation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (methods.size() == 0) { |
||||||
|
return NO_RESOLVED_METHODS; |
||||||
|
} |
||||||
|
return methods.values().toArray(new ResolvedMethod[methods.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for fully resolving static field definitions and associated annotations. |
||||||
|
* Neither field definitions nor associated annotations inherit, but we may |
||||||
|
* still need to add annotation overrides, as well as filter out filters |
||||||
|
* and annotations that caller is not interested in. |
||||||
|
* |
||||||
|
* @since 1.2.0 |
||||||
|
*/ |
||||||
|
protected ResolvedField[] resolveStaticFields() |
||||||
|
{ |
||||||
|
// First get static methods for main type, filter
|
||||||
|
LinkedHashMap<String, ResolvedField> fields = new LinkedHashMap<String, ResolvedField>(); |
||||||
|
for (RawField field : _mainType.getType().getStaticFields()) { |
||||||
|
if (_fieldFilter == null || _fieldFilter.include(field)) { |
||||||
|
fields.put(field.getName(), resolveField(field)); |
||||||
|
} |
||||||
|
} |
||||||
|
// then apply overrides (mix-ins):
|
||||||
|
for (HierarchicType type : overridesOnly()) { |
||||||
|
for (RawField raw : type.getType().getStaticFields()) { |
||||||
|
ResolvedField field = fields.get(raw.getName()); |
||||||
|
// must override something, otherwise to ignore
|
||||||
|
if (field != null) { |
||||||
|
for (Annotation ann : raw.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeFieldAnnotation(ann)) { |
||||||
|
field.applyOverride(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// and that's it?
|
||||||
|
if (fields.isEmpty()) { |
||||||
|
return NO_RESOLVED_FIELDS; |
||||||
|
} |
||||||
|
return fields.values().toArray(new ResolvedField[ fields.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method that will actually resolve full information (types, annotations) |
||||||
|
* for static methods, using configured filter. |
||||||
|
*/ |
||||||
|
protected ResolvedMethod[] resolveStaticMethods() |
||||||
|
{ |
||||||
|
// First get static methods for main type, filter
|
||||||
|
LinkedHashMap<MethodKey, ResolvedMethod> methods = new LinkedHashMap<MethodKey, ResolvedMethod>(); |
||||||
|
for (RawMethod method : _mainType.getType().getStaticMethods()) { |
||||||
|
if (_methodFilter == null || _methodFilter.include(method)) { |
||||||
|
methods.put(method.createKey(), resolveMethod(method)); |
||||||
|
} |
||||||
|
} |
||||||
|
// then apply overrides (mix-ins):
|
||||||
|
for (HierarchicType type : overridesOnly()) { |
||||||
|
for (RawMethod raw : type.getType().getStaticMethods()) { |
||||||
|
ResolvedMethod method = methods.get(raw.createKey()); |
||||||
|
// must override something, otherwise to ignore
|
||||||
|
if (method != null) { |
||||||
|
for (Annotation ann : raw.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeMethodAnnotation(ann)) { |
||||||
|
method.applyOverride(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (methods.size() == 0) { |
||||||
|
return NO_RESOLVED_METHODS; |
||||||
|
} |
||||||
|
return methods.values().toArray(new ResolvedMethod[methods.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for resolving individual constructor completely |
||||||
|
*/ |
||||||
|
protected ResolvedConstructor resolveConstructor(RawConstructor raw) |
||||||
|
{ |
||||||
|
final ResolvedType context = raw.getDeclaringType(); |
||||||
|
final TypeBindings bindings = context.getTypeBindings(); |
||||||
|
Constructor<?> ctor = raw.getRawMember(); |
||||||
|
Type[] rawTypes = ctor.getGenericParameterTypes(); |
||||||
|
ResolvedType[] argTypes; |
||||||
|
if (rawTypes == null || rawTypes.length == 0) { |
||||||
|
argTypes = NO_RESOLVED_TYPES; |
||||||
|
} else { |
||||||
|
argTypes = new ResolvedType[rawTypes.length]; |
||||||
|
for (int i = 0, len = rawTypes.length; i < len; ++i) { |
||||||
|
argTypes[i] = _typeResolver.resolve(bindings, rawTypes[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
// And then annotations
|
||||||
|
Annotations anns = new Annotations(); |
||||||
|
for (Annotation ann : ctor.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeConstructorAnnotation(ann)) { |
||||||
|
anns.add(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ResolvedConstructor constructor = new ResolvedConstructor(context, anns, ctor, argTypes); |
||||||
|
|
||||||
|
// and parameter annotations
|
||||||
|
Annotation[][] annotations = ctor.getParameterAnnotations(); |
||||||
|
for (int i = 0; i < argTypes.length; i++) { |
||||||
|
for (Annotation ann : annotations[i]) { |
||||||
|
constructor.applyParamOverride(i, ann); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return constructor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for resolving individual field completely |
||||||
|
*/ |
||||||
|
protected ResolvedField resolveField(RawField raw) |
||||||
|
{ |
||||||
|
final ResolvedType context = raw.getDeclaringType(); |
||||||
|
Field field = raw.getRawMember(); |
||||||
|
ResolvedType type = _typeResolver.resolve(context.getTypeBindings(), field.getGenericType()); |
||||||
|
// And then annotations
|
||||||
|
Annotations anns = new Annotations(); |
||||||
|
for (Annotation ann : field.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeFieldAnnotation(ann)) { |
||||||
|
anns.add(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
return new ResolvedField(context, anns, field, type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for resolving individual method completely |
||||||
|
*/ |
||||||
|
protected ResolvedMethod resolveMethod(RawMethod raw) |
||||||
|
{ |
||||||
|
final ResolvedType context = raw.getDeclaringType(); |
||||||
|
final TypeBindings bindings = context.getTypeBindings(); |
||||||
|
Method m = raw.getRawMember(); |
||||||
|
Type rawType = m.getGenericReturnType(); |
||||||
|
ResolvedType rt = (rawType == Void.TYPE) ? null : _typeResolver.resolve(bindings, rawType); |
||||||
|
Type[] rawTypes = m.getGenericParameterTypes(); |
||||||
|
ResolvedType[] argTypes; |
||||||
|
if (rawTypes == null || rawTypes.length == 0) { |
||||||
|
argTypes = NO_RESOLVED_TYPES; |
||||||
|
} else { |
||||||
|
argTypes = new ResolvedType[rawTypes.length]; |
||||||
|
for (int i = 0, len = rawTypes.length; i < len; ++i) { |
||||||
|
argTypes[i] = _typeResolver.resolve(bindings, rawTypes[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
// And then annotations
|
||||||
|
Annotations anns = new Annotations(); |
||||||
|
for (Annotation ann : m.getAnnotations()) { |
||||||
|
if (_annotationHandler.includeMethodAnnotation(ann)) { |
||||||
|
anns.add(ann); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ResolvedMethod method = new ResolvedMethod(context, anns, m, rt, argTypes); |
||||||
|
|
||||||
|
// and argument annotations
|
||||||
|
Annotation[][] annotations = m.getParameterAnnotations(); |
||||||
|
for (int i = 0; i < argTypes.length; i++) { |
||||||
|
for (Annotation ann : annotations[i]) { |
||||||
|
method.applyParamOverride(i, ann); |
||||||
|
} |
||||||
|
} |
||||||
|
return method; |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean methodCanInherit(Annotation annotation) { |
||||||
|
AnnotationInclusion annotationInclusion = _annotationHandler.methodInclusion(annotation); |
||||||
|
if (annotationInclusion == AnnotationInclusion.INCLUDE_AND_INHERIT_IF_INHERITED) { |
||||||
|
return annotation.annotationType().isAnnotationPresent(Inherited.class); |
||||||
|
} |
||||||
|
return (annotationInclusion == AnnotationInclusion.INCLUDE_AND_INHERIT); |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean parameterCanInherit(Annotation annotation) { |
||||||
|
AnnotationInclusion annotationInclusion = _annotationHandler.parameterInclusion(annotation); |
||||||
|
if (annotationInclusion == AnnotationInclusion.INCLUDE_AND_INHERIT_IF_INHERITED) { |
||||||
|
return annotation.annotationType().isAnnotationPresent(Inherited.class); |
||||||
|
} |
||||||
|
return (annotationInclusion == AnnotationInclusion.INCLUDE_AND_INHERIT); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper class we use to reduce number of calls to {@link AnnotationConfiguration}; |
||||||
|
* mostly because determination may be expensive. |
||||||
|
*/ |
||||||
|
private final static class AnnotationHandler |
||||||
|
{ |
||||||
|
private final AnnotationConfiguration _annotationConfig; |
||||||
|
|
||||||
|
private HashMap<Class<? extends Annotation>, AnnotationInclusion> _fieldInclusions; |
||||||
|
private HashMap<Class<? extends Annotation>, AnnotationInclusion> _constructorInclusions; |
||||||
|
private HashMap<Class<? extends Annotation>, AnnotationInclusion> _methodInclusions; |
||||||
|
private HashMap<Class<? extends Annotation>, AnnotationInclusion> _parameterInclusions; |
||||||
|
|
||||||
|
public AnnotationHandler(AnnotationConfiguration annotationConfig) { |
||||||
|
_annotationConfig = annotationConfig; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean includeConstructorAnnotation(Annotation ann) |
||||||
|
{ |
||||||
|
Class<? extends Annotation> annType = ann.annotationType(); |
||||||
|
if (_constructorInclusions == null) { |
||||||
|
_constructorInclusions = new HashMap<Class<? extends Annotation>, AnnotationInclusion>(); |
||||||
|
} else { |
||||||
|
AnnotationInclusion incl = _constructorInclusions.get(annType); |
||||||
|
if (incl != null) { |
||||||
|
return (incl != AnnotationInclusion.DONT_INCLUDE); |
||||||
|
} |
||||||
|
} |
||||||
|
AnnotationInclusion incl = _annotationConfig.getInclusionForConstructor(annType); |
||||||
|
_constructorInclusions.put(annType, incl); |
||||||
|
return (incl != AnnotationInclusion.DONT_INCLUDE); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean includeFieldAnnotation(Annotation ann) |
||||||
|
{ |
||||||
|
Class<? extends Annotation> annType = ann.annotationType(); |
||||||
|
if (_fieldInclusions == null) { |
||||||
|
_fieldInclusions = new HashMap<Class<? extends Annotation>, AnnotationInclusion>(); |
||||||
|
} else { |
||||||
|
AnnotationInclusion incl = _fieldInclusions.get(annType); |
||||||
|
if (incl != null) { |
||||||
|
return (incl != AnnotationInclusion.DONT_INCLUDE); |
||||||
|
} |
||||||
|
} |
||||||
|
AnnotationInclusion incl = _annotationConfig.getInclusionForField(annType); |
||||||
|
_fieldInclusions.put(annType, incl); |
||||||
|
return (incl != AnnotationInclusion.DONT_INCLUDE); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean includeMethodAnnotation(Annotation ann) |
||||||
|
{ |
||||||
|
return methodInclusion(ann) != AnnotationInclusion.DONT_INCLUDE; |
||||||
|
} |
||||||
|
|
||||||
|
public AnnotationInclusion methodInclusion(Annotation ann) |
||||||
|
{ |
||||||
|
Class<? extends Annotation> annType = ann.annotationType(); |
||||||
|
if (_methodInclusions == null) { |
||||||
|
_methodInclusions = new HashMap<Class<? extends Annotation>, AnnotationInclusion>(); |
||||||
|
} else { |
||||||
|
AnnotationInclusion incl = _methodInclusions.get(annType); |
||||||
|
if (incl != null) { |
||||||
|
return incl; |
||||||
|
} |
||||||
|
} |
||||||
|
AnnotationInclusion incl = _annotationConfig.getInclusionForMethod(annType); |
||||||
|
_methodInclusions.put(annType, incl); |
||||||
|
return incl; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean includeParameterAnnotation(Annotation ann) |
||||||
|
{ |
||||||
|
return parameterInclusion(ann) != AnnotationInclusion.DONT_INCLUDE; |
||||||
|
} |
||||||
|
|
||||||
|
public AnnotationInclusion parameterInclusion(Annotation ann) |
||||||
|
{ |
||||||
|
Class<? extends Annotation> annType = ann.annotationType(); |
||||||
|
if (_parameterInclusions == null) { |
||||||
|
_parameterInclusions = new HashMap<Class<? extends Annotation>, AnnotationInclusion>(); |
||||||
|
} else { |
||||||
|
AnnotationInclusion incl = _parameterInclusions.get(annType); |
||||||
|
if (incl != null) { |
||||||
|
return incl; |
||||||
|
} |
||||||
|
} |
||||||
|
AnnotationInclusion incl = _annotationConfig.getInclusionForParameter(annType); |
||||||
|
_parameterInclusions.put(annType, incl); |
||||||
|
return incl; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,237 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.lang.reflect.TypeVariable; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper class used for storing binding of local type variables to |
||||||
|
* matching resolved types, in context of a single class. |
||||||
|
*/ |
||||||
|
public final class TypeBindings |
||||||
|
{ |
||||||
|
private final static String[] NO_STRINGS = new String[0]; |
||||||
|
|
||||||
|
private final static ResolvedType[] NO_TYPES = new ResolvedType[0]; |
||||||
|
|
||||||
|
private final static TypeBindings EMPTY = new TypeBindings(NO_STRINGS, NO_TYPES, null); |
||||||
|
|
||||||
|
/** |
||||||
|
* Array of type (type variable) names. |
||||||
|
*/ |
||||||
|
private final String[] _names; |
||||||
|
|
||||||
|
/** |
||||||
|
* Types matching names |
||||||
|
*/ |
||||||
|
private final ResolvedType[] _types; |
||||||
|
|
||||||
|
/** |
||||||
|
* Names of potentially unresolved type variables. |
||||||
|
* |
||||||
|
* @since 2.3 |
||||||
|
*/ |
||||||
|
private final String[] _unboundVariables; |
||||||
|
|
||||||
|
private final int _hashCode; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Construction |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
private TypeBindings(String[] names, ResolvedType[] types, String[] uvars) |
||||||
|
{ |
||||||
|
_names = (names == null) ? NO_STRINGS : names; |
||||||
|
_types = (types == null) ? NO_TYPES : types; |
||||||
|
if (_names.length != _types.length) { |
||||||
|
throw new IllegalArgumentException("Mismatching names ("+_names.length+"), types ("+_types.length+")"); |
||||||
|
} |
||||||
|
int h = 1; |
||||||
|
for (int i = 0, len = _types.length; i < len; ++i) { |
||||||
|
h += _types[i].hashCode(); |
||||||
|
} |
||||||
|
_unboundVariables = uvars; |
||||||
|
_hashCode = h; |
||||||
|
} |
||||||
|
|
||||||
|
public static TypeBindings emptyBindings() { |
||||||
|
return EMPTY; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for constructing bindings for given class using specified type |
||||||
|
* parameters. |
||||||
|
*/ |
||||||
|
public static TypeBindings create(Class<?> erasedType, List<ResolvedType> typeList) |
||||||
|
{ |
||||||
|
ResolvedType[] types = (typeList == null || typeList.isEmpty()) ? |
||||||
|
NO_TYPES : typeList.toArray(new ResolvedType[typeList.size()]); |
||||||
|
return create(erasedType, types); |
||||||
|
} |
||||||
|
|
||||||
|
public static TypeBindings create(Class<?> erasedType, ResolvedType[] types) |
||||||
|
{ |
||||||
|
if (types == null) { |
||||||
|
types = NO_TYPES; |
||||||
|
} |
||||||
|
TypeVariable<?>[] vars = erasedType.getTypeParameters(); |
||||||
|
String[] names; |
||||||
|
if (vars == null || vars.length == 0) { |
||||||
|
names = NO_STRINGS; |
||||||
|
} else { |
||||||
|
int len = vars.length; |
||||||
|
names = new String[len]; |
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
names[i] = vars[i].getName(); |
||||||
|
} |
||||||
|
} |
||||||
|
// Check here to give better error message
|
||||||
|
if (names.length != types.length) { |
||||||
|
throw new IllegalArgumentException("Can not create TypeBinding for class "+erasedType.getName() |
||||||
|
+" with "+types.length+" type parameter" |
||||||
|
+((types.length == 1) ? "" : "s")+": class expects "+names.length); |
||||||
|
} |
||||||
|
return new TypeBindings(names, types, null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method for creating an instance that has same bindings as this object, |
||||||
|
* plus an indicator for additional type variable that may be unbound within |
||||||
|
* this context; this is needed to resolve recursive self-references. |
||||||
|
* |
||||||
|
* @since 1.3 (renamed from "withAdditionalBinding" in 1.2) |
||||||
|
*/ |
||||||
|
public TypeBindings withUnboundVariable(String name) |
||||||
|
{ |
||||||
|
int len = (_unboundVariables == null) ? 0 : _unboundVariables.length; |
||||||
|
String[] names = (len == 0) |
||||||
|
? new String[1] : Arrays.copyOf(_unboundVariables, len+1); |
||||||
|
names[len] = name; |
||||||
|
return new TypeBindings(_names, _types, names); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Find type bound to specified name, if there is one; returns bound type if so, null if not. |
||||||
|
*/ |
||||||
|
public ResolvedType findBoundType(String name) |
||||||
|
{ |
||||||
|
for (int i = 0, len = _names.length; i < len; ++i) { |
||||||
|
if (name.equals(_names[i])) { |
||||||
|
return _types[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEmpty() { |
||||||
|
return (_types.length == 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns number of bindings contained |
||||||
|
*/ |
||||||
|
public int size() { |
||||||
|
return _types.length; |
||||||
|
} |
||||||
|
|
||||||
|
public String getBoundName(int index) |
||||||
|
{ |
||||||
|
if (index < 0 || index >= _names.length) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return _names[index]; |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedType getBoundType(int index) |
||||||
|
{ |
||||||
|
if (index < 0 || index >= _types.length) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return _types[index]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Accessor for getting bound types in declaration order |
||||||
|
*/ |
||||||
|
public List<ResolvedType> getTypeParameters() |
||||||
|
{ |
||||||
|
if (_types.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_types); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @since 2.3 |
||||||
|
*/ |
||||||
|
public boolean hasUnbound(String name) { |
||||||
|
if (_unboundVariables != null) { |
||||||
|
for (int i = _unboundVariables.length; --i >= 0; ) { |
||||||
|
if (name.equals(_unboundVariables[i])) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public String toString() |
||||||
|
{ |
||||||
|
if (_types.length == 0) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
sb.append('<'); |
||||||
|
for (int i = 0, len = _types.length; i < len; ++i) { |
||||||
|
if (i > 0) { |
||||||
|
sb.append(','); |
||||||
|
} |
||||||
|
sb = _types[i].appendBriefDescription(sb); |
||||||
|
} |
||||||
|
sb.append('>'); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public int hashCode() { return _hashCode; } |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
TypeBindings other = (TypeBindings) o; |
||||||
|
int len = _types.length; |
||||||
|
if (len != other.size()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
ResolvedType[] otherTypes = other._types; |
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
if (!otherTypes[i].equals(_types[i])) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Package accessible methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected ResolvedType[] typeParameterArray() { |
||||||
|
return _types; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,547 @@ |
|||||||
|
package com.fasterxml.classmate; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.types.*; |
||||||
|
import com.fasterxml.classmate.util.ClassKey; |
||||||
|
import com.fasterxml.classmate.util.ClassStack; |
||||||
|
import com.fasterxml.classmate.util.ResolvedTypeCache; |
||||||
|
|
||||||
|
/** |
||||||
|
* Object that is used for resolving generic type information of a class
|
||||||
|
* so that it is accessible using simple API. Resolved types are also starting |
||||||
|
* point for accessing resolved (generics aware) return and argument types |
||||||
|
* of class members (methods, fields, constructors). |
||||||
|
*<p> |
||||||
|
* Note that resolver instances are stateful in that resolvers cache resolved |
||||||
|
* types for efficiency. Since this is internal state and not directly visible |
||||||
|
* to callers, access to state is fully synchronized so that access from |
||||||
|
* multiple threads is safe. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public class TypeResolver implements Serializable |
||||||
|
{ |
||||||
|
private final static ResolvedType[] NO_TYPES = new ResolvedType[0]; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Pre-created instances |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* We will also need to return "unknown" type for cases where type variable binding |
||||||
|
* is not found ('raw' instances of generic types); easiest way is to |
||||||
|
* pre-create type for <code>java.lang.Object</code> |
||||||
|
*/ |
||||||
|
private final static ResolvedObjectType sJavaLangObject = |
||||||
|
ResolvedObjectType.create(Object.class, null, null, null); |
||||||
|
|
||||||
|
/** |
||||||
|
* Since number of primitive types is small, and they are frequently needed, |
||||||
|
* let's actually pre-create them for efficient reuse. Same goes for limited number |
||||||
|
* of other "standard" types... |
||||||
|
*/ |
||||||
|
protected final static HashMap<ClassKey, ResolvedType> _primitiveTypes; |
||||||
|
static { |
||||||
|
_primitiveTypes = new HashMap<ClassKey, ResolvedType>(16); |
||||||
|
for (ResolvedPrimitiveType type : ResolvedPrimitiveType.all()) { |
||||||
|
_primitiveTypes.put(new ClassKey(type.getErasedType()), type); |
||||||
|
} |
||||||
|
// should we include "void"? might as well...
|
||||||
|
_primitiveTypes.put(new ClassKey(Void.TYPE), ResolvedPrimitiveType.voidType()); |
||||||
|
// and at least java.lang.Object should be added too.
|
||||||
|
_primitiveTypes.put(new ClassKey(Object.class), sJavaLangObject); |
||||||
|
// but most other types can be added dynamically
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Caching |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple cache of types resolved by this resolved; capped to last 200 resolved types. |
||||||
|
* Caching works because type instances themselves are mostly immutable; |
||||||
|
* and properly synchronized in cases where transient data (raw members) are |
||||||
|
* accessed. |
||||||
|
*/ |
||||||
|
protected final ResolvedTypeCache _resolvedTypes = new ResolvedTypeCache(200); |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public TypeResolver() { } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Factory methods, with explicit parameterization |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for resolving given base type |
||||||
|
* using specified types as type parameters. |
||||||
|
* Sample usage would be: |
||||||
|
*<pre> |
||||||
|
* ResolvedType type = TypeResolver.resolve(List.class, Integer.class); |
||||||
|
*</pre> |
||||||
|
* which would be equivalent to |
||||||
|
*<pre> |
||||||
|
* ResolvedType type = TypeResolver.resolve(new GenericType<List<Integer>>() { }); |
||||||
|
*</pre> |
||||||
|
* Note that you can mix different types of type parameters, whether already |
||||||
|
* resolved ({@link ResolvedType}), type-erased ({@link java.lang.Class}) or |
||||||
|
* generic type reference ({@link GenericType}). |
||||||
|
*/ |
||||||
|
public ResolvedType resolve(Type type, Type... typeParameters) |
||||||
|
{ |
||||||
|
boolean noParams = (typeParameters == null || typeParameters.length == 0); |
||||||
|
TypeBindings bindings; |
||||||
|
Class<?> rawBase; |
||||||
|
|
||||||
|
if (type instanceof Class<?>) { |
||||||
|
bindings = TypeBindings.emptyBindings(); |
||||||
|
if (noParams) { |
||||||
|
return _fromClass(null, (Class<?>) type, bindings); |
||||||
|
} |
||||||
|
rawBase = (Class<?>) type; |
||||||
|
} else if (type instanceof GenericType<?>) { |
||||||
|
bindings = TypeBindings.emptyBindings(); |
||||||
|
if (noParams) { |
||||||
|
return _fromGenericType(null, (GenericType<?>) type, bindings); |
||||||
|
} |
||||||
|
ResolvedType rt = _fromAny(null, type, bindings); |
||||||
|
rawBase = rt.getErasedType(); |
||||||
|
} else if (type instanceof ResolvedType) { |
||||||
|
ResolvedType rt = (ResolvedType) type; |
||||||
|
if (noParams) { |
||||||
|
return rt; |
||||||
|
} |
||||||
|
bindings = rt.getTypeBindings(); |
||||||
|
rawBase = rt.getErasedType(); |
||||||
|
} else { |
||||||
|
bindings = TypeBindings.emptyBindings(); |
||||||
|
if (noParams) { |
||||||
|
return resolve(bindings, type); |
||||||
|
} |
||||||
|
// Quite convoluted... but necessary to find Class<?> underlying it all
|
||||||
|
ResolvedType rt = _fromAny(null, type, bindings); |
||||||
|
rawBase = rt.getErasedType(); |
||||||
|
} |
||||||
|
|
||||||
|
// Next: resolve type parameters
|
||||||
|
int len = typeParameters.length; |
||||||
|
ResolvedType[] resolvedParams = new ResolvedType[len]; |
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
resolvedParams[i] = _fromAny(null, typeParameters[i], bindings); |
||||||
|
} |
||||||
|
return _fromClass(null, rawBase, TypeBindings.create(rawBase, resolvedParams)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for constructing array type of given element type. |
||||||
|
*/ |
||||||
|
public ResolvedArrayType arrayType(Type elementType) |
||||||
|
{ |
||||||
|
ResolvedType resolvedElementType = resolve(TypeBindings.emptyBindings(), elementType); |
||||||
|
// Arrays are cumbersome for some reason:
|
||||||
|
Object emptyArray = Array.newInstance(resolvedElementType.getErasedType(), 0); |
||||||
|
// Should we try to use cache? It's bit tricky, so let's not bother yet
|
||||||
|
return new ResolvedArrayType(emptyArray.getClass(), TypeBindings.emptyBindings(), |
||||||
|
resolvedElementType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for resolving specified Java {@link java.lang.reflect.Type}, given |
||||||
|
* {@link TypeBindings} needed to resolve any type variables. |
||||||
|
*<p> |
||||||
|
* Use of this method is discouraged (use if and only if you really know what you |
||||||
|
* are doing!); but if used, type bindings passed should come from {@link ResolvedType} |
||||||
|
* instance of declaring class (or interface). |
||||||
|
*<p> |
||||||
|
* NOTE: order of arguments was reversed for 0.8, to avoid problems with |
||||||
|
* overload varargs method. |
||||||
|
*/ |
||||||
|
public ResolvedType resolve(TypeBindings typeBindings, Type jdkType) |
||||||
|
{ |
||||||
|
return _fromAny(null, jdkType, typeBindings); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for constructing sub-classing specified type; class specified |
||||||
|
* as sub-class must be compatible according to basic Java inheritance rules |
||||||
|
* (subtype must properly extend or implement specified supertype). |
||||||
|
*<p> |
||||||
|
* A typical use case here is to refine a generic type; for example, given |
||||||
|
* that we have generic type like <code>List<Integer></code>, but we want |
||||||
|
* a more specific implementation type like |
||||||
|
* class <code>ArrayList</code> but with same parameterization (here just <code>Integer</code>), |
||||||
|
* we could achieve it by: |
||||||
|
*<pre> |
||||||
|
* ResolvedType mapType = typeResolver.resolve(List.class, Integer.class); |
||||||
|
* ResolveType concreteMapType = typeResolver.resolveSubType(mapType, ArrayList.class); |
||||||
|
*</pre> |
||||||
|
* (in this case, it would have been simpler to resolve directly; but in some |
||||||
|
* cases we are handled supertype and want to refine it, in which case steps |
||||||
|
* would be the same but separated by other code) |
||||||
|
*<p> |
||||||
|
* Note that this method will fail if extension can not succeed; either because |
||||||
|
* this type is not extendable (sub-classable) -- which is true for primitive |
||||||
|
* and array types -- or because given class is not a subtype of this type. |
||||||
|
* To check whether subtyping could succeed, you can call |
||||||
|
* {@link ResolvedType#canCreateSubtypes()} to see if supertype can ever |
||||||
|
* be extended. |
||||||
|
* |
||||||
|
* @param supertype Type to subtype (extend) |
||||||
|
* @param subtype Type-erased sub-class or sub-interface
|
||||||
|
* |
||||||
|
* @return Resolved subtype |
||||||
|
* |
||||||
|
* @throws IllegalArgumentException If this type can be extended in general, but not into specified sub-class
|
||||||
|
* @throws UnsupportedOperationException If this type can not be sub-classed |
||||||
|
*/ |
||||||
|
public ResolvedType resolveSubtype(ResolvedType supertype, Class<?> subtype) |
||||||
|
throws IllegalArgumentException, UnsupportedOperationException |
||||||
|
{ |
||||||
|
// first: if it's a recursive reference, find out referred-to type
|
||||||
|
ResolvedType refType = supertype.getSelfReferencedType(); |
||||||
|
if (refType != null) { |
||||||
|
supertype = refType; |
||||||
|
} |
||||||
|
// Then, trivial check for case where subtype is supertype...
|
||||||
|
if (supertype.getErasedType() == subtype) { |
||||||
|
return supertype; |
||||||
|
} |
||||||
|
|
||||||
|
if (!supertype.canCreateSubtypes()) { |
||||||
|
throw new UnsupportedOperationException("Can not subtype primitive or array types (type "+supertype.getFullDescription()+")"); |
||||||
|
} |
||||||
|
// In general, must be able to subtype as per JVM rules:
|
||||||
|
Class<?> superclass = supertype.getErasedType(); |
||||||
|
if (!superclass.isAssignableFrom(subtype)) { |
||||||
|
throw new IllegalArgumentException("Can not sub-class "+supertype.getBriefDescription() |
||||||
|
+" into "+subtype.getName()); |
||||||
|
} |
||||||
|
// Ok, then, let us instantiate type with placeholders
|
||||||
|
ResolvedType resolvedSubtype; |
||||||
|
int paramCount = subtype.getTypeParameters().length; |
||||||
|
TypePlaceHolder[] placeholders; |
||||||
|
|
||||||
|
if (paramCount == 0) { // no generics
|
||||||
|
placeholders = null; |
||||||
|
resolvedSubtype = resolve(subtype); |
||||||
|
} else { |
||||||
|
placeholders = new TypePlaceHolder[paramCount]; |
||||||
|
for (int i = 0; i < paramCount; ++i) { |
||||||
|
placeholders[i] = new TypePlaceHolder(i); |
||||||
|
} |
||||||
|
resolvedSubtype = resolve(subtype, placeholders); |
||||||
|
} |
||||||
|
ResolvedType rawSupertype = resolvedSubtype.findSupertype(superclass); |
||||||
|
if (rawSupertype == null) { // sanity check, should never occur
|
||||||
|
throw new IllegalArgumentException("Internal error: unable to locate supertype ("+subtype.getName()+") for type "+supertype.getBriefDescription()); |
||||||
|
} |
||||||
|
// Ok, then, let's find and verify type assignments
|
||||||
|
_resolveTypePlaceholders(supertype, rawSupertype); |
||||||
|
|
||||||
|
// And then re-construct, if necessary
|
||||||
|
if (paramCount == 0) { // if no type parameters, fine as is
|
||||||
|
return resolvedSubtype; |
||||||
|
} |
||||||
|
// but with type parameters, need to reconstruct
|
||||||
|
ResolvedType[] typeParams = new ResolvedType[paramCount]; |
||||||
|
for (int i = 0; i < paramCount; ++i) { |
||||||
|
ResolvedType t = placeholders[i].actualType(); |
||||||
|
/* Is it ok for it to be left unassigned? For now let's not |
||||||
|
* allow that |
||||||
|
*/ |
||||||
|
if (t == null) { |
||||||
|
throw new IllegalArgumentException("Failed to find type parameter #"+(i+1)+"/" |
||||||
|
+paramCount+" for "+subtype.getName()); |
||||||
|
} |
||||||
|
typeParams[i] = t; |
||||||
|
} |
||||||
|
return resolve(subtype, typeParams); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Misc other methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method that can be used to checked whether given resolved type |
||||||
|
* (with erased type of <code>java.lang.Object</code>) is a placeholder |
||||||
|
* for "self-reference"; these are nasty recursive ("self") types |
||||||
|
* needed with some interfaces |
||||||
|
*/ |
||||||
|
public static boolean isSelfReference(ResolvedType type) |
||||||
|
{ |
||||||
|
return (type instanceof ResolvedRecursiveType); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Internal methods, second-level factory methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
private ResolvedType _fromAny(ClassStack context, Type mainType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
if (mainType instanceof Class<?>) { |
||||||
|
return _fromClass(context, (Class<?>) mainType, typeBindings); |
||||||
|
} |
||||||
|
if (mainType instanceof ResolvedType) { |
||||||
|
return (ResolvedType) mainType; |
||||||
|
} |
||||||
|
if (mainType instanceof ParameterizedType) { |
||||||
|
return _fromParamType(context, (ParameterizedType) mainType, typeBindings); |
||||||
|
} |
||||||
|
if (mainType instanceof GenericType<?>) { |
||||||
|
return _fromGenericType(context, (GenericType<?>) mainType, typeBindings); |
||||||
|
} |
||||||
|
if (mainType instanceof GenericArrayType) { |
||||||
|
return _fromArrayType(context, (GenericArrayType) mainType, typeBindings); |
||||||
|
} |
||||||
|
if (mainType instanceof TypeVariable<?>) { |
||||||
|
return _fromVariable(context, (TypeVariable<?>) mainType, typeBindings); |
||||||
|
} |
||||||
|
if (mainType instanceof WildcardType) { |
||||||
|
return _fromWildcard(context, (WildcardType) mainType, typeBindings); |
||||||
|
} |
||||||
|
// should never get here...
|
||||||
|
throw new IllegalArgumentException("Unrecognized type class: "+mainType.getClass().getName()); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _fromClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
// First: a primitive type perhaps?
|
||||||
|
ResolvedType type = _primitiveTypes.get(new ClassKey(rawType)); |
||||||
|
if (type != null) { |
||||||
|
return type; |
||||||
|
} |
||||||
|
// Second: recursive reference?
|
||||||
|
if (context == null) { |
||||||
|
context = new ClassStack(rawType); |
||||||
|
} else { |
||||||
|
ClassStack prev = context.find(rawType); |
||||||
|
if (prev != null) { |
||||||
|
// Self-reference: needs special handling, then...
|
||||||
|
ResolvedRecursiveType selfRef = new ResolvedRecursiveType(rawType, typeBindings); |
||||||
|
prev.addSelfReference(selfRef); |
||||||
|
return selfRef; |
||||||
|
} |
||||||
|
// no, can just add
|
||||||
|
context = context.child(rawType); |
||||||
|
} |
||||||
|
|
||||||
|
// If not, already recently resolved?
|
||||||
|
ResolvedType[] typeParameters = typeBindings.typeParameterArray(); |
||||||
|
ResolvedTypeCache.Key key = _resolvedTypes.key(rawType, typeParameters); |
||||||
|
|
||||||
|
type = _resolvedTypes.find(key); |
||||||
|
if (type == null) { |
||||||
|
type = _constructType(context, rawType, typeBindings); |
||||||
|
_resolvedTypes.put(key, type); |
||||||
|
} |
||||||
|
context.resolveSelfReferences(type); |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Factory method for resolving given generic type, defined by using sub-class
|
||||||
|
* instance of {@link GenericType} |
||||||
|
*/ |
||||||
|
private ResolvedType _fromGenericType(ClassStack context, GenericType<?> generic, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
/* To allow multiple levels of inheritance (just in case someone |
||||||
|
* wants to go to town with inheritance of GenericType), |
||||||
|
* we better resolve the whole thing; then dig out |
||||||
|
* type parameterization... |
||||||
|
*/ |
||||||
|
ResolvedType type = _fromClass(context, generic.getClass(), typeBindings); |
||||||
|
ResolvedType genType = type.findSupertype(GenericType.class); |
||||||
|
if (genType == null) { // sanity check; shouldn't occur
|
||||||
|
throw new IllegalArgumentException("Unparameterized GenericType instance ("+generic.getClass().getName()+")"); |
||||||
|
} |
||||||
|
TypeBindings b = genType.getTypeBindings(); |
||||||
|
ResolvedType[] params = b.typeParameterArray(); |
||||||
|
if (params.length == 0) { |
||||||
|
throw new IllegalArgumentException("Unparameterized GenericType instance ("+generic.getClass().getName()+")"); |
||||||
|
} |
||||||
|
return params[0]; |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _constructType(ClassStack context, Class<?> rawType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
// Ok: no easy shortcut, let's figure out type of type...
|
||||||
|
if (rawType.isArray()) { |
||||||
|
ResolvedType elementType = _fromAny(context, rawType.getComponentType(), typeBindings); |
||||||
|
return new ResolvedArrayType(rawType, typeBindings, elementType); |
||||||
|
} |
||||||
|
// For other types super interfaces are needed...
|
||||||
|
if (rawType.isInterface()) { |
||||||
|
return new ResolvedInterfaceType(rawType, typeBindings, |
||||||
|
_resolveSuperInterfaces(context, rawType, typeBindings)); |
||||||
|
|
||||||
|
} |
||||||
|
return new ResolvedObjectType(rawType, typeBindings, |
||||||
|
_resolveSuperClass(context, rawType, typeBindings), |
||||||
|
_resolveSuperInterfaces(context, rawType, typeBindings)); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType[] _resolveSuperInterfaces(ClassStack context, Class<?> rawType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
Type[] types = rawType.getGenericInterfaces(); |
||||||
|
if (types == null || types.length == 0) { |
||||||
|
return NO_TYPES; |
||||||
|
} |
||||||
|
int len = types.length; |
||||||
|
ResolvedType[] resolved = new ResolvedType[len]; |
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
resolved[i] = _fromAny(context, types[i], typeBindings); |
||||||
|
} |
||||||
|
return resolved; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* NOTE: return type changed in 1.0.1 from {@link ResolvedObjectType} to |
||||||
|
* {@link ResolvedType}, since it was found that other types may |
||||||
|
* be returned... |
||||||
|
* |
||||||
|
* @return Usually a {@link ResolvedObjectType}, but possibly also |
||||||
|
* {@link ResolvedRecursiveType} |
||||||
|
*/ |
||||||
|
private ResolvedType _resolveSuperClass(ClassStack context, Class<?> rawType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
Type parent = rawType.getGenericSuperclass(); |
||||||
|
if (parent == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return _fromAny(context, parent, typeBindings); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _fromParamType(ClassStack context, ParameterizedType ptype, TypeBindings parentBindings) |
||||||
|
{ |
||||||
|
/* First: what is the actual base type? One odd thing is that 'getRawType' |
||||||
|
* returns Type, not Class<?> as one might expect. But let's assume it is |
||||||
|
* always of type Class: if not, need to add more code to resolve it... |
||||||
|
*/ |
||||||
|
Class<?> rawType = (Class<?>) ptype.getRawType(); |
||||||
|
Type[] params = ptype.getActualTypeArguments(); |
||||||
|
int len = params.length; |
||||||
|
ResolvedType[] types = new ResolvedType[len]; |
||||||
|
|
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
types[i] = _fromAny(context, params[i], parentBindings); |
||||||
|
} |
||||||
|
// Ok: this gives us current bindings for this type:
|
||||||
|
TypeBindings newBindings = TypeBindings.create(rawType, types); |
||||||
|
return _fromClass(context, rawType, newBindings); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _fromArrayType(ClassStack context, GenericArrayType arrayType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
ResolvedType elementType = _fromAny(context, arrayType.getGenericComponentType(), typeBindings); |
||||||
|
// Figuring out raw class for generic array is actually bit tricky...
|
||||||
|
Object emptyArray = Array.newInstance(elementType.getErasedType(), 0); |
||||||
|
return new ResolvedArrayType(emptyArray.getClass(), typeBindings, elementType); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _fromWildcard(ClassStack context, WildcardType wildType, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
/* Similar to challenges with TypeVariable, we may have multiple upper bounds. |
||||||
|
* But it is also possible that if upper bound defaults to Object, we might want to |
||||||
|
* consider lower bounds instead? |
||||||
|
* For now, we won't try anything more advanced; above is just for future reference. |
||||||
|
*/ |
||||||
|
return _fromAny(context, wildType.getUpperBounds()[0], typeBindings); |
||||||
|
} |
||||||
|
|
||||||
|
private ResolvedType _fromVariable(ClassStack context, TypeVariable<?> variable, TypeBindings typeBindings) |
||||||
|
{ |
||||||
|
// ideally should find it via bindings:
|
||||||
|
String name = variable.getName(); |
||||||
|
ResolvedType type = typeBindings.findBoundType(name); |
||||||
|
|
||||||
|
if (type != null) { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/* but if not, use bounds... note that approach here is simplistic; not taking |
||||||
|
* into account possible multiple bounds, nor consider upper bounds. |
||||||
|
*/ |
||||||
|
/* 02-Mar-2011, tatu: As per issue#4, need to avoid self-reference cycles here; |
||||||
|
* can be handled by (temporarily) adding binding: |
||||||
|
*/ |
||||||
|
if (typeBindings.hasUnbound(name)) { |
||||||
|
return sJavaLangObject; |
||||||
|
} |
||||||
|
typeBindings = typeBindings.withUnboundVariable(name); |
||||||
|
|
||||||
|
Type[] bounds = variable.getBounds(); |
||||||
|
return _fromAny(context, bounds[0], typeBindings); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Internal methods, replacing and verifying type placeholders |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to verify that types match; and if there are |
||||||
|
*/ |
||||||
|
private void _resolveTypePlaceholders(ResolvedType expectedType, ResolvedType actualType) |
||||||
|
throws IllegalArgumentException |
||||||
|
{ |
||||||
|
List<ResolvedType> expectedTypes = expectedType.getTypeParameters(); |
||||||
|
List<ResolvedType> actualTypes = actualType.getTypeParameters(); |
||||||
|
for (int i = 0, len = expectedTypes.size(); i < len; ++i) { |
||||||
|
ResolvedType exp = expectedTypes.get(i); |
||||||
|
ResolvedType act = actualTypes.get(i); |
||||||
|
if (!_typesMatch(exp, act)) { |
||||||
|
throw new IllegalArgumentException("Type parameter #"+(i+1)+"/"+len+" differs; expected " |
||||||
|
+exp.getBriefDescription()+", got "+act.getBriefDescription()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean _typesMatch(ResolvedType exp, ResolvedType act) |
||||||
|
{ |
||||||
|
// Simple equality check, except for one thing: place holders for 'act'
|
||||||
|
if (act instanceof TypePlaceHolder) { |
||||||
|
((TypePlaceHolder) act).actualType(exp); |
||||||
|
return true; |
||||||
|
} |
||||||
|
// but due to recursive nature can't call equality...
|
||||||
|
if (exp.getErasedType() != act.getErasedType()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
// But we can check type parameters "blindly"
|
||||||
|
List<ResolvedType> expectedTypes = exp.getTypeParameters(); |
||||||
|
List<ResolvedType> actualTypes = act.getTypeParameters(); |
||||||
|
for (int i = 0, len = expectedTypes.size(); i < len; ++i) { |
||||||
|
ResolvedType exp2 = expectedTypes.get(i); |
||||||
|
ResolvedType act2 = actualTypes.get(i); |
||||||
|
if (!_typesMatch(exp2, act2)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper classes |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.ResolvedTypeWithMembers; |
||||||
|
|
||||||
|
/** |
||||||
|
* Container class used to enclose information about a single {@link ResolvedType} |
||||||
|
* that is part of {@link ResolvedTypeWithMembers}. |
||||||
|
*/ |
||||||
|
public final class HierarchicType |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Whether this type instance represents a mix-in; if so, it can only result in |
||||||
|
* addition of annotations but not in addition of actual members. |
||||||
|
*/ |
||||||
|
protected final boolean _isMixin; |
||||||
|
|
||||||
|
protected final ResolvedType _type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Relative priority of this type in hierarchy; higher priority members can override |
||||||
|
* lower priority members. Priority values are unique and are based on type index |
||||||
|
* (starting from 0), although they are not to be used for indexing. |
||||||
|
*/ |
||||||
|
protected final int _priority; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public HierarchicType(ResolvedType type, boolean mixin, int priority) |
||||||
|
{ |
||||||
|
_type = type; |
||||||
|
_isMixin = mixin; |
||||||
|
_priority = priority; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedType getType() { return _type; } |
||||||
|
public Class<?> getErasedType() { return _type.getErasedType(); } |
||||||
|
public boolean isMixin() { return _isMixin; } |
||||||
|
public int getPriority() { return _priority; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public String toString() { return _type.toString(); } |
||||||
|
@Override public int hashCode() { return _type.hashCode(); } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
HierarchicType other = (HierarchicType) o; |
||||||
|
return _type.equals(other._type); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.util.MethodKey; |
||||||
|
|
||||||
|
public final class RawConstructor extends RawMember |
||||||
|
{ |
||||||
|
protected final Constructor<?> _constructor; |
||||||
|
|
||||||
|
protected final int _hashCode; |
||||||
|
|
||||||
|
public RawConstructor(ResolvedType context, Constructor<?> constructor) |
||||||
|
{ |
||||||
|
super(context); |
||||||
|
_constructor = constructor; |
||||||
|
_hashCode = (_constructor == null ? 0 : _constructor.hashCode()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Although constructors are different from other methods, we can use |
||||||
|
* {@link MethodKey} easily. |
||||||
|
*/ |
||||||
|
public MethodKey createKey() |
||||||
|
{ |
||||||
|
String name = "<init>"; // do not use _constructor.getName() to allow for 'mix-ins'
|
||||||
|
Class<?>[] argTypes = _constructor.getParameterTypes(); // return of Constructor#getParameterTypes will never be null
|
||||||
|
return new MethodKey(name, argTypes); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public Constructor<?> getRawMember() { |
||||||
|
return _constructor; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public int hashCode() |
||||||
|
{ |
||||||
|
return _hashCode; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
RawConstructor other = (RawConstructor) o; |
||||||
|
return (other._constructor == _constructor); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
public final class RawField extends RawMember |
||||||
|
{ |
||||||
|
protected final Field _field; |
||||||
|
|
||||||
|
private final int _hashCode; |
||||||
|
|
||||||
|
public RawField(ResolvedType context, Field field) |
||||||
|
{ |
||||||
|
super(context); |
||||||
|
_field = field; |
||||||
|
_hashCode = (_field == null ? 0 : _field.hashCode()); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public Field getRawMember() { |
||||||
|
return _field; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isTransient() { |
||||||
|
return Modifier.isTransient(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isVolatile() { |
||||||
|
return Modifier.isVolatile(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
RawField other = (RawField) o; |
||||||
|
return (other._field == _field); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public int hashCode() |
||||||
|
{ |
||||||
|
return _hashCode; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.lang.reflect.AnnotatedElement; |
||||||
|
import java.lang.reflect.Member; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Base class for all "raw" member (field, method, constructor) types; raw means that |
||||||
|
* actual types are not yet resolved, but relationship to declaring type is |
||||||
|
* retained for eventual resolution. |
||||||
|
* Instances are typically created by {@link com.fasterxml.classmate.ResolvedType} |
||||||
|
* when requested, and form the input to eventual full flattening of type members. |
||||||
|
*/ |
||||||
|
public abstract class RawMember |
||||||
|
{ |
||||||
|
/** |
||||||
|
* {@link ResolvedType} (class with generic type parameters) that declared |
||||||
|
* this member |
||||||
|
*/ |
||||||
|
protected final ResolvedType _declaringType; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected RawMember(ResolvedType context) |
||||||
|
{ |
||||||
|
_declaringType = context; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public final ResolvedType getDeclaringType() { |
||||||
|
return _declaringType; |
||||||
|
} |
||||||
|
|
||||||
|
public abstract Member getRawMember(); |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return getRawMember().getName(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isStatic() { |
||||||
|
return Modifier.isStatic(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isFinal() { |
||||||
|
return Modifier.isFinal(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isPrivate() { |
||||||
|
return Modifier.isPrivate(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isProtected() { |
||||||
|
return Modifier.isProtected(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isPublic() { |
||||||
|
return Modifier.isPublic(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public Annotation[] getAnnotations() { |
||||||
|
return ((AnnotatedElement) getRawMember()).getAnnotations(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard method overrides |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
// make abstract to force implementation by sub-class
|
||||||
|
@Override public abstract boolean equals(Object o); |
||||||
|
|
||||||
|
@Override public abstract int hashCode(); |
||||||
|
|
||||||
|
@Override public String toString() { |
||||||
|
return getName(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Package methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected final int getModifiers() { return getRawMember().getModifiers(); } |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.util.MethodKey; |
||||||
|
|
||||||
|
public final class RawMethod extends RawMember |
||||||
|
{ |
||||||
|
protected final Method _method; |
||||||
|
|
||||||
|
protected final int _hashCode; |
||||||
|
|
||||||
|
public RawMethod(ResolvedType context, Method method) |
||||||
|
{ |
||||||
|
super(context); |
||||||
|
_method = method; |
||||||
|
_hashCode = (_method == null ? 0 : _method.hashCode()); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public Method getRawMember() { |
||||||
|
return _method; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isAbstract() { |
||||||
|
return Modifier.isAbstract(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isStrict() { |
||||||
|
return Modifier.isStrict(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isNative() { |
||||||
|
return Modifier.isNative(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isSynchronized() { |
||||||
|
return Modifier.isSynchronized(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public MethodKey createKey() |
||||||
|
{ |
||||||
|
String name = _method.getName(); |
||||||
|
Class<?>[] argTypes = _method.getParameterTypes(); // return of Method#getParameterTypes will never be null
|
||||||
|
return new MethodKey(name, argTypes); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public int hashCode() |
||||||
|
{ |
||||||
|
return _hashCode; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
RawMethod other = (RawMethod) o; |
||||||
|
return (other._method == _method); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.Annotations; |
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Class that represents a constructor that has fully resolved generic |
||||||
|
* type information and annotation information. |
||||||
|
*/ |
||||||
|
public final class ResolvedConstructor extends ResolvedParameterizedMember<Constructor<?>> |
||||||
|
{ |
||||||
|
public ResolvedConstructor(ResolvedType context, Annotations ann, Constructor<?> constructor, |
||||||
|
ResolvedType[] argumentTypes) |
||||||
|
{ |
||||||
|
super(context, ann, constructor, null, argumentTypes); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.Annotations; |
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
public final class ResolvedField extends ResolvedMember<Field> |
||||||
|
implements Comparable<ResolvedField> |
||||||
|
{ |
||||||
|
public ResolvedField(ResolvedType context, Annotations ann, |
||||||
|
Field field, ResolvedType type) |
||||||
|
{ |
||||||
|
super(context, ann, field, type); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public boolean isTransient() { |
||||||
|
return Modifier.isTransient(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isVolatile() { |
||||||
|
return Modifier.isVolatile(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compareTo(ResolvedField other) { |
||||||
|
return getName().compareTo(other.getName()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,156 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.lang.reflect.Member; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.Annotations; |
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Fully type-resolved equivalent of {@link RawMember}. Only members "that matter" (ones not |
||||||
|
* overridden, or filtered out) are resolved, since resolution process can add non-trivial |
||||||
|
* overhead. |
||||||
|
*/ |
||||||
|
public abstract class ResolvedMember<T extends Member> |
||||||
|
{ |
||||||
|
/** |
||||||
|
* {@link ResolvedType} (class with generic type parameters) that declared |
||||||
|
* this member |
||||||
|
*/ |
||||||
|
protected final ResolvedType _declaringType; |
||||||
|
|
||||||
|
protected final Annotations _annotations; |
||||||
|
|
||||||
|
protected final T _member; |
||||||
|
|
||||||
|
protected final ResolvedType _type; |
||||||
|
|
||||||
|
protected final int _hashCode; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected ResolvedMember(ResolvedType context, Annotations ann, T member, ResolvedType type) |
||||||
|
{ |
||||||
|
_declaringType = context; |
||||||
|
_annotations = ann; |
||||||
|
_member = member; |
||||||
|
_type = type; |
||||||
|
_hashCode = (_member == null ? 0 : _member.hashCode()); |
||||||
|
} |
||||||
|
|
||||||
|
public void applyOverride(Annotation override) |
||||||
|
{ |
||||||
|
_annotations.add(override); |
||||||
|
} |
||||||
|
|
||||||
|
public void applyOverrides(Annotations overrides) |
||||||
|
{ |
||||||
|
_annotations.addAll(overrides); |
||||||
|
} |
||||||
|
|
||||||
|
public void applyDefault(Annotation override) |
||||||
|
{ |
||||||
|
_annotations.addAsDefault(override); |
||||||
|
} |
||||||
|
|
||||||
|
public <A extends Annotation> A get(Class<A> cls) |
||||||
|
{ |
||||||
|
return _annotations.get(cls); |
||||||
|
} |
||||||
|
|
||||||
|
public Annotations getAnnotations() |
||||||
|
{ |
||||||
|
return _annotations; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public final ResolvedType getDeclaringType() { |
||||||
|
return _declaringType; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns type of this member; if it has one, for methods this is the |
||||||
|
* return type, for fields field type, and for constructors null. |
||||||
|
*/ |
||||||
|
public ResolvedType getType() { |
||||||
|
return _type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns JDK object that represents member. |
||||||
|
*/ |
||||||
|
public T getRawMember() { |
||||||
|
return _member; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return getRawMember().getName(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isStatic() { |
||||||
|
return Modifier.isStatic(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isFinal() { |
||||||
|
return Modifier.isFinal(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isPrivate() { |
||||||
|
return Modifier.isPrivate(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isProtected() { |
||||||
|
return Modifier.isProtected(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isPublic() { |
||||||
|
return Modifier.isPublic(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard method overrides |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public String toString() { |
||||||
|
return getName(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Package methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected final int getModifiers() { return getRawMember().getModifiers(); } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override public int hashCode() { |
||||||
|
return _hashCode; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
ResolvedMember<?> other = (ResolvedMember<?>) o; |
||||||
|
return (other._member == _member); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.Annotations; |
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
public final class ResolvedMethod extends ResolvedParameterizedMember<Method> |
||||||
|
implements Comparable<ResolvedMethod> |
||||||
|
{ |
||||||
|
public ResolvedMethod(ResolvedType context, Annotations ann, Method method, |
||||||
|
ResolvedType returnType, ResolvedType[] argumentTypes) |
||||||
|
{ |
||||||
|
super(context, ann, method, returnType, argumentTypes); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple accessors from base class
|
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public boolean isAbstract() { |
||||||
|
return Modifier.isAbstract(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isStrict() { |
||||||
|
return Modifier.isStrict(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isNative() { |
||||||
|
return Modifier.isNative(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isSynchronized() { |
||||||
|
return Modifier.isSynchronized(getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Extended API |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedType getReturnType() { return getType(); } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard method override |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compareTo(ResolvedMethod other) |
||||||
|
{ |
||||||
|
// primary sort by name (alphabetic); secondary by arg count (ascending)
|
||||||
|
int diff = getName().compareTo(other.getName()); |
||||||
|
if (diff == 0) { |
||||||
|
// subtract fine, no fear of overflow here
|
||||||
|
diff = getArgumentCount() - other.getArgumentCount(); |
||||||
|
} |
||||||
|
return diff; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
package com.fasterxml.classmate.members; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.Annotations; |
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.lang.reflect.Member; |
||||||
|
|
||||||
|
/** |
||||||
|
* Base type for resolved members that take some parameters (e.g. methods and constructors). |
||||||
|
*/ |
||||||
|
public abstract class ResolvedParameterizedMember<T extends Member> extends ResolvedMember<T> { |
||||||
|
|
||||||
|
protected final ResolvedType[] _paramTypes; |
||||||
|
|
||||||
|
protected final Annotations[] _paramAnnotations; |
||||||
|
|
||||||
|
protected ResolvedParameterizedMember(ResolvedType context, Annotations ann, |
||||||
|
T member, ResolvedType type, ResolvedType[] argumentTypes) { |
||||||
|
super(context, ann, member, type); |
||||||
|
_paramTypes = argumentTypes == null ? ResolvedType.NO_TYPES : argumentTypes; |
||||||
|
_paramAnnotations = new Annotations[_paramTypes.length]; |
||||||
|
} |
||||||
|
|
||||||
|
public Annotations getParameterAnnotations(int index) { |
||||||
|
if (index >= _paramTypes.length) |
||||||
|
throw new IndexOutOfBoundsException("No parameter at index " + index + ", this is greater than the total number of parameters"); |
||||||
|
|
||||||
|
if (_paramAnnotations[index] == null) { |
||||||
|
_paramAnnotations[index] = new Annotations(); |
||||||
|
} |
||||||
|
return _paramAnnotations[index]; |
||||||
|
} |
||||||
|
|
||||||
|
public void applyParamOverride(int index, Annotation override) |
||||||
|
{ |
||||||
|
if (index >= _paramAnnotations.length) |
||||||
|
return; |
||||||
|
|
||||||
|
getParameterAnnotations(index).add(override); |
||||||
|
} |
||||||
|
|
||||||
|
public void applyParamOverrides(int index, Annotations overrides) |
||||||
|
{ |
||||||
|
if (index >= _paramAnnotations.length) |
||||||
|
return; |
||||||
|
|
||||||
|
getParameterAnnotations(index).addAll(overrides); |
||||||
|
} |
||||||
|
|
||||||
|
public void applyParamDefault(int index, Annotation defaultValue) |
||||||
|
{ |
||||||
|
if (index >= _paramAnnotations.length) |
||||||
|
return; |
||||||
|
|
||||||
|
getParameterAnnotations(index).addAsDefault(defaultValue); |
||||||
|
} |
||||||
|
|
||||||
|
public <A extends Annotation> A getParam(int index, Class<A> cls) |
||||||
|
{ |
||||||
|
if (index >= _paramAnnotations.length) |
||||||
|
return null; |
||||||
|
|
||||||
|
return _paramAnnotations[index].get(cls); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns number of arguments method takes. |
||||||
|
*/ |
||||||
|
public int getArgumentCount() { |
||||||
|
return _paramTypes.length; |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedType getArgumentType(int index) |
||||||
|
{ |
||||||
|
if (index < 0 || index >= _paramTypes.length) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return _paramTypes[index]; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
/** |
||||||
|
* Package that contains implementations of various member types |
||||||
|
* (methods, fields, constructors) |
||||||
|
*/ |
||||||
|
package com.fasterxml.classmate.members; |
@ -0,0 +1,13 @@ |
|||||||
|
/** |
||||||
|
* Package that contains main public interface of ClassMate |
||||||
|
* package. |
||||||
|
*<p> |
||||||
|
* Most commonly resolution starts with {@link com.fasterxml.classmate.TypeResolver}, |
||||||
|
* using its <code>resolve()</code> method, which returns a |
||||||
|
* {@link com.fasterxml.classmate.ResolvedType} instance. |
||||||
|
* These type objects contain all necessary information about type itself; |
||||||
|
* but if type information on members (fields, methods, constructors, static |
||||||
|
* members) is needed, {@link com.fasterxml.classmate.MemberResolver} can |
||||||
|
* resolve types for members: it takes {@link com.fasterxml.classmate.ResolvedType}s. |
||||||
|
*/ |
||||||
|
package com.fasterxml.classmate; |
@ -0,0 +1,108 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
|
||||||
|
public final class ResolvedArrayType extends ResolvedType |
||||||
|
{ |
||||||
|
protected final ResolvedType _elementType; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedArrayType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedType elementType) |
||||||
|
{ |
||||||
|
super(erased, bindings); |
||||||
|
_elementType = elementType; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getParentClass() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInterface() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getArrayElementType() { return _elementType; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isArray() { return true; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPrimitive() { return false; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
// defaults are fine (nothing to access)
|
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
sb.append('['); |
||||||
|
return _elementType.appendSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
sb.append('['); |
||||||
|
return _elementType.appendErasedSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb = _elementType.appendBriefDescription(sb); |
||||||
|
sb.append("[]"); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) { |
||||||
|
return appendBriefDescription(sb); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,162 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
import com.fasterxml.classmate.members.RawField; |
||||||
|
import com.fasterxml.classmate.members.RawMethod; |
||||||
|
|
||||||
|
public class ResolvedInterfaceType extends ResolvedType |
||||||
|
{ |
||||||
|
|
||||||
|
/** |
||||||
|
* List of interfaces this type implements; may be empty but never null |
||||||
|
*/ |
||||||
|
protected final ResolvedType[] _superInterfaces; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interfaces can have static final (constant) fields. |
||||||
|
*/ |
||||||
|
protected RawField[] _constantFields; |
||||||
|
|
||||||
|
/** |
||||||
|
* Interface methods are all public and abstract. |
||||||
|
*/ |
||||||
|
protected RawMethod[] _memberMethods; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedInterfaceType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedType[] superInterfaces) |
||||||
|
{ |
||||||
|
super(erased, bindings); |
||||||
|
_superInterfaces = (superInterfaces == null ? NO_TYPES : superInterfaces); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getParentClass() { |
||||||
|
// interfaces do not have parent class, just interfaces
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { |
||||||
|
return (_superInterfaces.length == 0) ? |
||||||
|
Collections.<ResolvedType>emptyList() : Arrays.asList(_superInterfaces); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getArrayElementType() { // interfaces are never arrays, so:
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInterface() { return true; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { return true; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isArray() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPrimitive() { return false; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawField> getStaticFields() |
||||||
|
{ |
||||||
|
// Interfaces can have static fields, but only as static constants...
|
||||||
|
if (_constantFields == null) { |
||||||
|
_constantFields = _getFields(true); |
||||||
|
} |
||||||
|
if (_constantFields.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_constantFields); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawMethod> getMemberMethods() |
||||||
|
{ |
||||||
|
if (_memberMethods == null) { |
||||||
|
_memberMethods = _getMethods(false); |
||||||
|
} |
||||||
|
if (_memberMethods.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_memberMethods); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
return _appendClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
return _appendErasedClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) { |
||||||
|
return _appendClassDescription(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb = _appendClassDescription(sb); |
||||||
|
// interfaces 'extend' other interfaces...
|
||||||
|
int count = _superInterfaces.length; |
||||||
|
if (count > 0) { |
||||||
|
sb.append(" extends "); |
||||||
|
for (int i = 0; i < count; ++i) { |
||||||
|
if (i > 0) { |
||||||
|
sb.append(","); |
||||||
|
} |
||||||
|
sb = _superInterfaces[i].appendBriefDescription(sb); |
||||||
|
} |
||||||
|
} |
||||||
|
return sb; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,287 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
import com.fasterxml.classmate.members.RawConstructor; |
||||||
|
import com.fasterxml.classmate.members.RawField; |
||||||
|
import com.fasterxml.classmate.members.RawMethod; |
||||||
|
|
||||||
|
/** |
||||||
|
* Type implementation for classes that do not represent interfaces, |
||||||
|
* primitive or array types. |
||||||
|
*/ |
||||||
|
public class ResolvedObjectType extends ResolvedType |
||||||
|
{ |
||||||
|
/** |
||||||
|
* While fundamentally super class has to be {@link ResolvedObjectType} |
||||||
|
* (or null for {@link java.lang.Object}), we may need to hold on to |
||||||
|
* a {@link ResolvedRecursiveType} occasionally. |
||||||
|
*/ |
||||||
|
protected final ResolvedType _superClass; |
||||||
|
|
||||||
|
/** |
||||||
|
* List of interfaces this type implements; may be empty but never null |
||||||
|
*/ |
||||||
|
protected final ResolvedType[] _superInterfaces; |
||||||
|
|
||||||
|
/** |
||||||
|
* Modifiers of the underlying class. |
||||||
|
*/ |
||||||
|
protected final int _modifiers; |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructors declared by the resolved Object class. |
||||||
|
*/ |
||||||
|
protected RawConstructor[] _constructors; |
||||||
|
|
||||||
|
protected RawField[] _memberFields; |
||||||
|
protected RawField[] _staticFields; |
||||||
|
|
||||||
|
protected RawMethod[] _memberMethods; |
||||||
|
protected RawMethod[] _staticMethods; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedObjectType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedType superClass, List<ResolvedType> interfaces) |
||||||
|
{ |
||||||
|
this(erased, bindings, superClass, |
||||||
|
(interfaces == null || interfaces.isEmpty()) ? NO_TYPES : |
||||||
|
interfaces.toArray(new ResolvedType[interfaces.size()])); |
||||||
|
} |
||||||
|
|
||||||
|
public ResolvedObjectType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedType superClass, ResolvedType[] interfaces) |
||||||
|
{ |
||||||
|
super(erased, bindings); |
||||||
|
/* 19-Aug-2014, tatu: bit unclean, but has to do for now. |
||||||
|
* Problem is, there is no common super-type, nor can we yet |
||||||
|
* force or coerce recursive types. Rather, they may only get |
||||||
|
* resolved only slightly after construction. So... need to |
||||||
|
* keep a reference. |
||||||
|
*/ |
||||||
|
if (superClass != null) { |
||||||
|
if (!(superClass instanceof ResolvedObjectType) |
||||||
|
&& !(superClass instanceof ResolvedRecursiveType) |
||||||
|
) { |
||||||
|
throw new IllegalArgumentException("Unexpected parent type for " |
||||||
|
+erased.getName()+": "+superClass.getClass().getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_superClass = superClass; |
||||||
|
_superInterfaces = (interfaces == null) ? NO_TYPES : interfaces; |
||||||
|
_modifiers = erased.getModifiers(); |
||||||
|
} |
||||||
|
|
||||||
|
@Deprecated // since 1.1; removed from 1.2 -- kept for binary backwards compatibility
|
||||||
|
public ResolvedObjectType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedObjectType superClass, List<ResolvedType> interfaces) |
||||||
|
{ |
||||||
|
this(erased, bindings, (ResolvedType) superClass, interfaces); |
||||||
|
} |
||||||
|
|
||||||
|
@Deprecated // since 1.1; removed from 1.2 -- kept for binary backwards compatibility
|
||||||
|
public ResolvedObjectType(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedObjectType superClass, ResolvedType[] interfaces) |
||||||
|
{ |
||||||
|
this(erased, bindings, (ResolvedType) superClass, interfaces); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResolvedObjectType create(Class<?> erased, TypeBindings bindings, |
||||||
|
ResolvedType superClass, List<ResolvedType> interfaces) |
||||||
|
{ |
||||||
|
return new ResolvedObjectType(erased, bindings, superClass, interfaces); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedObjectType getParentClass() { |
||||||
|
|
||||||
|
/* 19-Aug-2014, tatu: Ugly does it... sigh. |
||||||
|
* But can't be helped because ResolvedRecursiveType is typically only |
||||||
|
* resolved after instances of this type have been constructed. |
||||||
|
* This means that resolution will need to be done somewhat dynamically. |
||||||
|
*/ |
||||||
|
if (_superClass == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (_superClass instanceof ResolvedObjectType) { |
||||||
|
return (ResolvedObjectType) _superClass; |
||||||
|
} |
||||||
|
ResolvedType rt = ((ResolvedRecursiveType) _superClass).getSelfReferencedType(); |
||||||
|
if (!(rt instanceof ResolvedObjectType)) { |
||||||
|
throw new IllegalStateException("Internal error: self-referential parent type (" |
||||||
|
+_superClass+") does not resolve into proper ResolvedObjectType, but instead to: " |
||||||
|
+rt); |
||||||
|
} |
||||||
|
return (ResolvedObjectType) rt; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { |
||||||
|
return (_superInterfaces.length == 0) ? |
||||||
|
Collections.<ResolvedType>emptyList() : Arrays.asList(_superInterfaces); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public final ResolvedType getArrayElementType() { return null; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public final boolean isInterface() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { |
||||||
|
return Modifier.isAbstract(_modifiers); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public final boolean isArray() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public final boolean isPrimitive() { return false; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawField> getMemberFields() |
||||||
|
{ |
||||||
|
if (_memberFields == null) { |
||||||
|
_memberFields = _getFields(false); |
||||||
|
} |
||||||
|
if (_memberFields.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_memberFields); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawField> getStaticFields() |
||||||
|
{ |
||||||
|
if (_staticFields == null) { |
||||||
|
_staticFields = _getFields(true); |
||||||
|
} |
||||||
|
if (_staticFields.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_staticFields); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawMethod> getMemberMethods() |
||||||
|
{ |
||||||
|
if (_memberMethods == null) { |
||||||
|
_memberMethods = _getMethods(false); |
||||||
|
} |
||||||
|
if (_memberMethods.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_memberMethods); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized List<RawMethod> getStaticMethods() |
||||||
|
{ |
||||||
|
if (_staticMethods == null) { |
||||||
|
_staticMethods = _getMethods(true); |
||||||
|
} |
||||||
|
if (_staticMethods.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_staticMethods); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<RawConstructor> getConstructors() |
||||||
|
{ |
||||||
|
if (_constructors == null) { |
||||||
|
_constructors = _getConstructors(); |
||||||
|
} |
||||||
|
if (_constructors.length == 0) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return Arrays.asList(_constructors); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
return _appendClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
return _appendErasedClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) { |
||||||
|
return _appendClassDescription(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) |
||||||
|
{ |
||||||
|
sb = _appendClassDescription(sb); |
||||||
|
if (_superClass != null) { |
||||||
|
sb.append(" extends "); |
||||||
|
sb = _superClass.appendBriefDescription(sb); |
||||||
|
} |
||||||
|
// interfaces 'extend' other interfaces...
|
||||||
|
int count = _superInterfaces.length; |
||||||
|
if (count > 0) { |
||||||
|
sb.append(" implements "); |
||||||
|
for (int i = 0; i < count; ++i) { |
||||||
|
if (i > 0) { |
||||||
|
sb.append(","); |
||||||
|
} |
||||||
|
sb = _superInterfaces[i].appendBriefDescription(sb); |
||||||
|
} |
||||||
|
} |
||||||
|
return sb; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,157 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
|
||||||
|
/** |
||||||
|
* Type used for Java primitive types (which does not include arrays here). |
||||||
|
*<p> |
||||||
|
* Since set of primitive types is bounded, constructor is defined as protected, |
||||||
|
* and class final; that is, new primitive types are not to be constructed |
||||||
|
* by calling applications. |
||||||
|
*/ |
||||||
|
public final class ResolvedPrimitiveType extends ResolvedType |
||||||
|
{ |
||||||
|
private final static ResolvedPrimitiveType VOID = new ResolvedPrimitiveType(Void.TYPE, 'V', "void"); |
||||||
|
|
||||||
|
/** |
||||||
|
* Primitive types have single-character Signature, easy and efficient |
||||||
|
* to just store here |
||||||
|
*/ |
||||||
|
protected final String _signature; |
||||||
|
|
||||||
|
/** |
||||||
|
* Human-readable description should be simple as well |
||||||
|
*/ |
||||||
|
protected final String _description; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
protected ResolvedPrimitiveType(Class<?> erased, char sig, String desc) |
||||||
|
{ |
||||||
|
super(erased, TypeBindings.emptyBindings()); |
||||||
|
_signature = String.valueOf(sig); |
||||||
|
_description = desc; |
||||||
|
} |
||||||
|
|
||||||
|
public static List<ResolvedPrimitiveType> all() |
||||||
|
{ |
||||||
|
ArrayList<ResolvedPrimitiveType> all = new ArrayList<ResolvedPrimitiveType>(); |
||||||
|
all.add(new ResolvedPrimitiveType(Boolean.TYPE, 'Z', "boolean")); |
||||||
|
all.add(new ResolvedPrimitiveType(Byte.TYPE, 'B', "byte")); |
||||||
|
all.add(new ResolvedPrimitiveType(Short.TYPE, 'S', "short")); |
||||||
|
all.add(new ResolvedPrimitiveType(Character.TYPE, 'C', "char")); |
||||||
|
all.add(new ResolvedPrimitiveType(Integer.TYPE, 'I', "int")); |
||||||
|
all.add(new ResolvedPrimitiveType(Long.TYPE, 'J', "long")); |
||||||
|
all.add(new ResolvedPrimitiveType(Float.TYPE, 'F', "float")); |
||||||
|
all.add(new ResolvedPrimitiveType(Double.TYPE, 'D', "double")); |
||||||
|
return all; |
||||||
|
} |
||||||
|
|
||||||
|
public static ResolvedPrimitiveType voidType() |
||||||
|
{ |
||||||
|
return VOID; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getParentClass() { return null; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInterface() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getArrayElementType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isArray() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPrimitive() { return true; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
// Primitive types are simple; no fields, no methods, no constructors
|
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getSignature() { |
||||||
|
return _signature; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getErasedSignature() { |
||||||
|
return _signature; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getFullDescription() { |
||||||
|
return _description; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
sb.append(_signature); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
sb.append(_signature); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) { |
||||||
|
sb.append(_description); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) { |
||||||
|
sb.append(_description); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,149 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
import com.fasterxml.classmate.members.RawConstructor; |
||||||
|
import com.fasterxml.classmate.members.RawField; |
||||||
|
import com.fasterxml.classmate.members.RawMethod; |
||||||
|
|
||||||
|
/** |
||||||
|
* Specialized type placeholder used in cases where type definition is |
||||||
|
* recursive; to avoid infinite loop, reference that would be "back" in |
||||||
|
* hierarchy is represented by an instance of this class. |
||||||
|
* Underlying information is achievable (for full resolution), but |
||||||
|
* not exposed using super type (parent) accessors; and has special |
||||||
|
* handling when used for constructing descriptions. |
||||||
|
*/ |
||||||
|
public class ResolvedRecursiveType extends ResolvedType |
||||||
|
{ |
||||||
|
/** |
||||||
|
* Actual fully resolved type; assigned once resolution is complete |
||||||
|
*/ |
||||||
|
protected ResolvedType _referencedType; |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Life cycle |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public ResolvedRecursiveType(Class<?> erased, TypeBindings bindings) |
||||||
|
{ |
||||||
|
super(erased, bindings); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { |
||||||
|
return _referencedType.canCreateSubtypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setReference(ResolvedType ref) |
||||||
|
{ |
||||||
|
// sanity check; should not be called multiple times
|
||||||
|
if (_referencedType != null) { |
||||||
|
throw new IllegalStateException("Trying to re-set self reference; old value = "+_referencedType+", new = "+ref); |
||||||
|
} |
||||||
|
_referencedType = ref; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* To avoid infinite loops, will return null; |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ResolvedType getParentClass() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return _referencedType; } |
||||||
|
|
||||||
|
/** |
||||||
|
* To avoid infinite loops, will return empty list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { |
||||||
|
return Collections.<ResolvedType>emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* To avoid infinite loops, will return null type |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public ResolvedType getArrayElementType() { // interfaces are never arrays, so:
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInterface() { return _erasedType.isInterface(); } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { return Modifier.isAbstract(_erasedType.getModifiers()); } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isArray() { return _erasedType.isArray(); } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPrimitive() { return false; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<RawField> getMemberFields() { return _referencedType.getMemberFields(); } |
||||||
|
@Override |
||||||
|
public List<RawField> getStaticFields() { return _referencedType.getStaticFields(); } |
||||||
|
@Override |
||||||
|
public List<RawMethod> getStaticMethods() { return _referencedType.getStaticMethods(); } |
||||||
|
@Override |
||||||
|
public List<RawMethod> getMemberMethods() { return _referencedType.getMemberMethods(); } |
||||||
|
@Override |
||||||
|
public List<RawConstructor> getConstructors() { return _referencedType.getConstructors(); } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
// to avoid infinite recursion, only print type erased version
|
||||||
|
return appendErasedSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
return _appendErasedClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) { |
||||||
|
return _appendClassDescription(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) |
||||||
|
{ |
||||||
|
// should never get called, but just in case, only print brief description
|
||||||
|
return appendBriefDescription(sb); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
package com.fasterxml.classmate.types; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.TypeBindings; |
||||||
|
|
||||||
|
/** |
||||||
|
* Placeholder used for resolving type assignments to figure out |
||||||
|
* type parameters for subtypes. |
||||||
|
*/ |
||||||
|
public class TypePlaceHolder extends ResolvedType |
||||||
|
{ |
||||||
|
protected final int _ordinal; |
||||||
|
|
||||||
|
/** |
||||||
|
* Type assigned during wildcard resolution |
||||||
|
*/ |
||||||
|
protected ResolvedType _actualType; |
||||||
|
|
||||||
|
public TypePlaceHolder(int ordinal) |
||||||
|
{ |
||||||
|
super(Object.class, TypeBindings.emptyBindings()); |
||||||
|
_ordinal = ordinal; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean canCreateSubtypes() { return false; } |
||||||
|
|
||||||
|
public ResolvedType actualType() { return _actualType; } |
||||||
|
public void actualType(ResolvedType t) { _actualType = t; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for related types |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getParentClass() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getSelfReferencedType() { return null; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<ResolvedType> getImplementedInterfaces() { return Collections.<ResolvedType>emptyList(); } |
||||||
|
|
||||||
|
@Override |
||||||
|
public ResolvedType getArrayElementType() { return null; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Simple property accessors |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInterface() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAbstract() { return true; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isArray() { return false; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isPrimitive() { return false; } |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Accessors for raw (minimally procesed) members |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* String representations |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendSignature(StringBuilder sb) { |
||||||
|
return _appendClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendErasedSignature(StringBuilder sb) { |
||||||
|
return _appendErasedClassSignature(sb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendBriefDescription(StringBuilder sb) { |
||||||
|
sb.append('<').append(_ordinal).append('>'); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public StringBuilder appendFullDescription(StringBuilder sb) { |
||||||
|
return appendBriefDescription(sb); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
/** |
||||||
|
* Package that contains {@link com.fasterxml.classmate.ResolvedType} |
||||||
|
* implementation classes. |
||||||
|
*/ |
||||||
|
package com.fasterxml.classmate.types; |
@ -0,0 +1,69 @@ |
|||||||
|
package com.fasterxml.classmate.util; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper class used as key when we need efficient Class-to-value lookups. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public class ClassKey |
||||||
|
implements Comparable<ClassKey>, Serializable |
||||||
|
{ |
||||||
|
private final String _className; |
||||||
|
|
||||||
|
private final Class<?> _class; |
||||||
|
|
||||||
|
/** |
||||||
|
* Let's cache hash code straight away, since we are almost certain to need it. |
||||||
|
*/ |
||||||
|
private final int _hashCode; |
||||||
|
|
||||||
|
public ClassKey(Class<?> clz) |
||||||
|
{ |
||||||
|
_class = clz; |
||||||
|
_className = clz.getName(); |
||||||
|
_hashCode = _className.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Comparable |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compareTo(ClassKey other) |
||||||
|
{ |
||||||
|
// Just need to sort by name, ok to collide (unless used in TreeMap/Set!)
|
||||||
|
return _className.compareTo(other._className); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null) return false; |
||||||
|
if (o.getClass() != getClass()) return false; |
||||||
|
ClassKey other = (ClassKey) o; |
||||||
|
|
||||||
|
/* Is it possible to have different Class object for same name + class loader combo? |
||||||
|
* Let's assume answer is no: if this is wrong, will need to uncomment following functionality |
||||||
|
*/ |
||||||
|
/* |
||||||
|
return (other._className.equals(_className)) |
||||||
|
&& (other._class.getClassLoader() == _class.getClassLoader()); |
||||||
|
*/ |
||||||
|
return other._class == _class; |
||||||
|
} |
||||||
|
|
||||||
|
@Override public int hashCode() { return _hashCode; } |
||||||
|
|
||||||
|
@Override public String toString() { return _className; } |
||||||
|
|
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
package com.fasterxml.classmate.util; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
import com.fasterxml.classmate.types.ResolvedRecursiveType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple helper class used to keep track of 'call stack' for classes being referenced |
||||||
|
* (as well as unbound variables) |
||||||
|
*/ |
||||||
|
public final class ClassStack |
||||||
|
{ |
||||||
|
protected final ClassStack _parent; |
||||||
|
protected final Class<?> _current; |
||||||
|
|
||||||
|
private ArrayList<ResolvedRecursiveType> _selfRefs; |
||||||
|
|
||||||
|
public ClassStack(Class<?> rootType) { |
||||||
|
this(null, rootType); |
||||||
|
} |
||||||
|
|
||||||
|
private ClassStack(ClassStack parent, Class<?> curr) { |
||||||
|
_parent = parent; |
||||||
|
_current = curr; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return New stack frame, if addition is ok; null if not |
||||||
|
*/ |
||||||
|
public ClassStack child(Class<?> cls) |
||||||
|
{ |
||||||
|
return new ClassStack(this, cls); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called to indicate that there is a self-reference from |
||||||
|
* deeper down in stack pointing into type this stack frame represents. |
||||||
|
*/ |
||||||
|
public void addSelfReference(ResolvedRecursiveType ref) |
||||||
|
{ |
||||||
|
if (_selfRefs == null) { |
||||||
|
_selfRefs = new ArrayList<ResolvedRecursiveType>(); |
||||||
|
} |
||||||
|
_selfRefs.add(ref); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method called when type that this stack frame represents is |
||||||
|
* fully resolved, allowing self-references to be completed |
||||||
|
* (if there are any) |
||||||
|
*/ |
||||||
|
public void resolveSelfReferences(ResolvedType resolved) |
||||||
|
{ |
||||||
|
if (_selfRefs != null) { |
||||||
|
for (ResolvedRecursiveType ref : _selfRefs) { |
||||||
|
ref.setReference(resolved); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public ClassStack find(Class<?> cls) |
||||||
|
{ |
||||||
|
if (_current == cls) return this; |
||||||
|
for (ClassStack curr = _parent; curr != null; curr = curr._parent) { |
||||||
|
if (curr._current == cls) { |
||||||
|
return curr; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
package com.fasterxml.classmate.util; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper class needed when storing methods in maps. |
||||||
|
* Immutable. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public class MethodKey implements Serializable |
||||||
|
{ |
||||||
|
private static final Class<?>[] NO_CLASSES = new Class[0]; |
||||||
|
|
||||||
|
private final String _name; |
||||||
|
|
||||||
|
private final Class<?>[] _argumentTypes; |
||||||
|
|
||||||
|
private final int _hashCode; |
||||||
|
|
||||||
|
public MethodKey(String name) |
||||||
|
{ |
||||||
|
_name = name; |
||||||
|
_argumentTypes = NO_CLASSES; |
||||||
|
_hashCode = name.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public MethodKey(String name, Class<?>[] argTypes) |
||||||
|
{ |
||||||
|
_name = name; |
||||||
|
_argumentTypes = argTypes; |
||||||
|
_hashCode = name.hashCode() + argTypes.length; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Standard methods |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Equality means name is the same and argument type erasures as well. |
||||||
|
*/ |
||||||
|
@Override public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
MethodKey other = (MethodKey) o; |
||||||
|
Class<?>[] otherArgs = other._argumentTypes; |
||||||
|
int len = _argumentTypes.length; |
||||||
|
if (otherArgs.length != len) return false; |
||||||
|
for (int i = 0; i < len; ++i) { |
||||||
|
if (otherArgs[i] != _argumentTypes[i]) return false; |
||||||
|
} |
||||||
|
return _name.equals(other._name); |
||||||
|
} |
||||||
|
|
||||||
|
@Override public int hashCode() { return _hashCode; } |
||||||
|
|
||||||
|
@Override public String toString() |
||||||
|
{ |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
sb.append(_name); |
||||||
|
sb.append('('); |
||||||
|
for (int i = 0, len = _argumentTypes.length; i < len; ++i) { |
||||||
|
if (i > 0) sb.append(','); |
||||||
|
sb.append(_argumentTypes[i].getName()); |
||||||
|
} |
||||||
|
sb.append(')'); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,141 @@ |
|||||||
|
package com.fasterxml.classmate.util; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fasterxml.classmate.ResolvedType; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple LRU cache used for storing up to specified number of most recently accessed |
||||||
|
* {@link ResolvedType} instances. |
||||||
|
* Since usage pattern is such that caller needs synchronization, cache access methods |
||||||
|
* are fully synchronized so that caller need not do explicit synchronization. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("serial") |
||||||
|
public class ResolvedTypeCache implements Serializable |
||||||
|
{ |
||||||
|
protected final CacheMap _map; |
||||||
|
|
||||||
|
public ResolvedTypeCache(int maxEntries) { |
||||||
|
_map = new CacheMap(maxEntries); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method for constructing reusable cache keys |
||||||
|
*/ |
||||||
|
public Key key(Class<?> simpleType) { |
||||||
|
return new Key(simpleType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method for constructing reusable cache keys |
||||||
|
*/ |
||||||
|
public Key key(Class<?> simpleType, ResolvedType[] tp) { |
||||||
|
return new Key(simpleType, tp); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized ResolvedType find(Key key) { |
||||||
|
return _map.get(key); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized int size() { |
||||||
|
return _map.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void put(Key key, ResolvedType type) { |
||||||
|
_map.put(key, type); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Methods for unit tests |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
public void add(ResolvedType type) |
||||||
|
{ |
||||||
|
List<ResolvedType> tp = type.getTypeParameters(); |
||||||
|
ResolvedType[] tpa = tp.toArray(new ResolvedType[tp.size()]); |
||||||
|
put(key(type.getErasedType(), tpa), type); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
/********************************************************************** |
||||||
|
/* Helper classes |
||||||
|
/********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Key used for type entries. |
||||||
|
*/ |
||||||
|
public static class Key |
||||||
|
{ |
||||||
|
private final Class<?> _erasedType; |
||||||
|
|
||||||
|
private final ResolvedType[] _typeParameters; |
||||||
|
|
||||||
|
private final int _hashCode; |
||||||
|
|
||||||
|
public Key(Class<?> simpleType) { |
||||||
|
this(simpleType, null); |
||||||
|
} |
||||||
|
|
||||||
|
public Key(Class<?> erasedType, ResolvedType[] tp) |
||||||
|
{ |
||||||
|
// let's not hold on type empty arrays
|
||||||
|
if (tp != null && tp.length == 0) { |
||||||
|
tp = null; |
||||||
|
} |
||||||
|
_erasedType = erasedType; |
||||||
|
_typeParameters = tp; |
||||||
|
int h = erasedType.getName().hashCode(); |
||||||
|
if (tp != null) { |
||||||
|
h += tp.length; |
||||||
|
} |
||||||
|
_hashCode = h; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { return _hashCode; } |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object o) |
||||||
|
{ |
||||||
|
if (o == this) return true; |
||||||
|
if (o == null || o.getClass() != getClass()) return false; |
||||||
|
Key other = (Key) o; |
||||||
|
if (other._erasedType != _erasedType) return false; |
||||||
|
ResolvedType[] otherTP = other._typeParameters; |
||||||
|
if (_typeParameters == null) { |
||||||
|
return (otherTP == null); |
||||||
|
} |
||||||
|
if (otherTP == null || otherTP.length != _typeParameters.length) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
for (int i = 0, len = _typeParameters.length; i < len; ++i) { |
||||||
|
if (!_typeParameters[i].equals(otherTP[i])) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple sub-class to get LRU cache |
||||||
|
*/ |
||||||
|
private final static class CacheMap |
||||||
|
extends LinkedHashMap<ResolvedTypeCache.Key, ResolvedType> |
||||||
|
{ |
||||||
|
protected final int _maxEntries; |
||||||
|
|
||||||
|
public CacheMap(int maxEntries) { |
||||||
|
_maxEntries = maxEntries; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean removeEldestEntry(Map.Entry<Key, ResolvedType> eldest) { |
||||||
|
return size() > _maxEntries; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
/** |
||||||
|
* Various utility classes used by ClassMate. |
||||||
|
*/ |
||||||
|
package com.fasterxml.classmate.util; |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue