package org.etk.reflect.core; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.etk.reflect.api.ClassTypeInfo; import org.etk.reflect.api.FieldInfo; import org.etk.reflect.api.MethodInfo; import org.etk.reflect.api.MethodSignature; import org.etk.reflect.api.ParameterizedTypeInfo; import org.etk.reflect.api.TypeInfo; import org.etk.reflect.api.TypeVariableInfo; import org.etk.reflect.api.definition.ClassKind; class ClassTypeInfoImpl<T, M, A, P, F> extends AbstractTypeInfo<T, M, A, P, F> implements ClassTypeInfo { private final T classType; private final String className; private List<TypeInfo> interfaces; private TypeInfo superType; private boolean superClassResolved; private List<TypeVariableInfo> typeParameters; /** * */ private List<MethodInfo> methods; /** * */ private LinkedHashMap<String, FieldInfo> fields; /** * */ private final String simpleName; /** * */ private final String packageName; /** * */ private final ClassKind kind; /** * */ private ClassTypeInfo enclosing; /** * */ private boolean enclosingResolved; private AnnotatedDelegate<T,M,A,P,F,T> annotatedDelegate; public ClassTypeInfoImpl(TypeResolverImpl<T, M, A, P, F> domain, T classType) { super(domain); String className = domain.typeMetadata.getClassName(classType); String simpleName; String packageName; int index = className.lastIndexOf('.'); if (index == -1) { simpleName = className; packageName =""; } else { simpleName = className.substring(index + 1); packageName = className.substring(0, index); } //Getting the ClassKind via the domain.typeModel.getClassKind(); ClassKind kind = domain.typeMetadata.getClassKind(classType); this.className = className; this.classType = classType; this.interfaces = null; this.superType = null; this.superClassResolved = false; this.simpleName = simpleName; this.packageName = packageName; this.kind = kind; this.annotatedDelegate = null; this.methods = null; this.fields = null; this.enclosing = null; this.enclosingResolved = false; } public String getName() { return className; } public boolean isReified() { return true; } public String getPackageName() { return packageName; } public ClassTypeInfo getEnclosing() { if (!enclosingResolved) { T enclosingType = domain.typeMetadata.getEnclosing(classType); if (enclosingType != null) { enclosing = (ClassTypeInfo)domain.resolve(enclosingType); } enclosingResolved = true; } return enclosing; } public String getSimpleName() { return simpleName; } public ClassKind getKind() { return kind; } public List<TypeVariableInfo> getTypeParameters() { if (typeParameters == null) { ArrayList<TypeVariableInfo> typeParameters = new ArrayList<TypeVariableInfo>(); for(T tv : domain.typeMetadata.getTypeParameters(classType)) { TypeVariableInfoImpl<T, M, A, P, F> typeParameter = (TypeVariableInfoImpl<T, M, A, P, F>) domain.getType(tv); typeParameters.add(typeParameter); } this.typeParameters = typeParameters; } return typeParameters; } public Iterable<TypeInfo> getInterfaces() { if (this.interfaces == null) { ArrayList<TypeInfo> interfaces = new ArrayList<TypeInfo>(); for (T interfaceType : domain.typeMetadata.getInterfaces(classType)) { TypeInfo itf = domain.resolve(interfaceType); interfaces.add(itf); } this.interfaces = interfaces; } return this.interfaces; } public TypeInfo getSuperType() { if (!superClassResolved) { T superClassType = domain.typeMetadata.getSuperClass(classType); if (superClassType != null) { superType = domain.resolve(superClassType); } superClassResolved = true; } return superType; } public TypeInfo resolve(TypeInfo type) { return Utils.resolve(this, type); } public List<MethodInfo> getDeclaredMethods() { if (methods == null) { List<MethodInfo> methods = new ArrayList<MethodInfo>(); for (M method : domain.methodMetadata.getDeclaredMethods(classType)) { MethodInfo mi = new MethodInfoImpl<T, M, A, P, F>(this, domain, method); methods.add(mi); } this.methods = methods; } return this.methods; } public MethodInfo getDeclaredMethod(MethodSignature methodSignature) { for(MethodInfo methodInfo : getDeclaredMethods()) { if (methodInfo.getSignature().equals(methodSignature)) { return methodInfo; } } return null; } private Map<String, FieldInfo> getDeclaredFieldMap() { if (fields == null) { LinkedHashMap<String, FieldInfo> fields = new LinkedHashMap<String, FieldInfo>(); for(F field : domain.fieldMetadata.getDeclaredFields(classType)) { FieldInfo fi = new FieldInfoImpl<T, M, A, P, F>(this, domain, field); fields.put(fi.getName(), fi); } this.fields = fields; } return this.fields; } public Collection<FieldInfo> getDeclaredFields() { return getDeclaredFieldMap().values(); } public FieldInfo getDeclaredField(String fieldName) { return getDeclaredFieldMap().get(fieldName); } public ClassTypeInfo getSuperClass() { TypeInfo superType = getSuperType(); if (superType == null) { return null; } else if (superType instanceof ClassTypeInfo) { return (ClassTypeInfo) superType; } else if (superType instanceof ParameterizedTypeInfo) { TypeInfo rawType = ((ParameterizedTypeInfo)superType).getRawType(); if (rawType instanceof ClassTypeInfo) { return (ClassTypeInfo) rawType; } else { throw new AssertionError("Cannot cast raw type" + rawType + " to class type."); } } else { throw new AssertionError("Cannot cast type " + superType + " to class type."); } } private boolean isAssignableFrom(TypeInfo that) { if (that instanceof ClassTypeInfo) { return isAssignableFrom((ClassTypeInfo)that); } else if (that instanceof ParameterizedTypeInfo) { return isAssignableFrom(((ParameterizedTypeInfo)that).getRawType()); } else if (that instanceof TypeVariableInfo) { return isAssignableFrom(((TypeVariableInfo)that).getBounds().get(0)); } else { return false; } } public boolean isAssignableFrom(ClassTypeInfo that) { if (className.equals("java.lang.Object")) { return true; } if (className.equals(that.getName())) { return true; } TypeInfo superType = that.getSuperType(); if (superType != null && isAssignableFrom(superType)) { return true; } for (TypeInfo itf : that.getInterfaces()) { if (isAssignableFrom(itf)) { return true; } } return false; } public T unwrap() { return classType; } public <AT> AT getDeclaredAnnotation(AnnotationType<AT, ?> annotationType) { if (annotatedDelegate == null) { annotatedDelegate = new AnnotatedDelegate<T, M, A, P, F, T>(domain, domain.typeAnnotationMetadata, classType); } return annotatedDelegate.getDeclaredAnnotation(classType, annotationType); } public int hashCode() { return className.hashCode(); } public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof ClassTypeInfo) { ClassTypeInfo that = (ClassTypeInfo) obj; String thatName = that.getName(); return className.equals(thatName); } return false; } public String toString() { return "ClassTypeInfo[className=" + className + "]"; } }