package org.etk.reflect.core; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.etk.reflect.api.ClassTypeInfo; import org.etk.reflect.api.MethodInfo; import org.etk.reflect.api.MethodSignature; import org.etk.reflect.api.TypeInfo; import org.etk.reflect.api.TypeVariableInfo; import org.etk.reflect.api.definition.MethodKind; public class MethodInfoImpl<T, M, A, P, F>extends ReflectedObject<T, M, A, P, F> implements MethodInfo { private static final List<String> NO_NAMES_AVAILABLE = new ArrayList<String>(); private final M method; private final String name; private TypeInfo returnType; private List<TypeInfo> parameterTypes; private final AccessScope access; private final boolean _final; private final boolean _static; private final MethodKind type; private final ClassTypeInfo owner; private MethodSignature signature; private List<TypeVariableInfo> typeParameters; private List<String> parameterNames; private AnnotatedDelegate<T, M, A, P, F, M> annotatedDelegate; private List<ClassTypeInfo> thrownTypes; public MethodInfoImpl(ClassTypeInfo owner, TypeResolverImpl<T, M, A, P, F> domain, M method) { super(domain); MethodKind type; if (domain.methodMetadata.isAbstract(method)) { type = MethodKind.ABSTRACT; } else if (domain.methodMetadata.isNative(method)) { type = MethodKind.NATIVE; } else { type = MethodKind.CONCRETE; } this.method = method; this.name = domain.methodMetadata.getName(method); this.access = domain.methodMetadata.getAccess(method); this._final = domain.methodMetadata.isFinal(method); this._static = domain.methodMetadata.isStatic(method); this.type = type; this.owner = owner; this.signature = null; this.typeParameters = null; this.parameterNames = null; this.annotatedDelegate = null; this.thrownTypes = null; } public M unwrap() { return method; } public TypeInfo getReturnType() { if (returnType == null) { T rt = domain.methodMetadata.getReturnType(method); returnType = domain.resolve(rt); } return returnType; } public List<String> getParameterNames() { if (parameterNames == null) { Iterable<String> names = domain.methodMetadata.getParameterNames(method); if (names != null) { List<String> parameterNames = new ArrayList<String>(); for(String parameterName : names) { parameterNames.add(parameterName); } this.parameterNames = Collections.unmodifiableList(parameterNames); } else { this.parameterNames = NO_NAMES_AVAILABLE; } } return parameterNames == NO_NAMES_AVAILABLE ? null : parameterNames; } public List<TypeInfo> getParameterTypes() { if (parameterTypes == null) { List<TypeInfo> parameterTypes = new ArrayList<TypeInfo>(); for (T parameterType : domain.methodMetadata.getParameterTypes(method)) { parameterTypes.add(domain.resolve(parameterType)); } this.parameterTypes = Collections.unmodifiableList(parameterTypes); } return parameterTypes; } public AccessScope getAccess() { return access; } public boolean isAbstract() { return type == MethodKind.ABSTRACT; } public boolean isNative() { return type == MethodKind.NATIVE; } public boolean isConcrete() { return type == MethodKind.CONCRETE; } public boolean isStatic() { return _static; } public boolean isFinal() { return _final; } public MethodKind getType() { return type; } public String getName() { return name; } public ClassTypeInfo getOwner() { return owner; } public List<TypeVariableInfo> getTypeParameters() { if (typeParameters == null) { ArrayList<TypeVariableInfo> typeParameters = new ArrayList<TypeVariableInfo>(); for (T tv : domain.methodMetadata.getTypeParameters(method)) { 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 MethodSignature getSignature() { if (signature == null) { signature = new MethodSignature(name, getParameterTypes()); } return signature; } public MethodSignature getSignature(ClassTypeInfo context) { List<TypeInfo> parameterTypes = getParameterTypes(); List<TypeInfo> resolvedParameterTypes = new ArrayList<TypeInfo>(parameterTypes.size()); for (TypeInfo parameterTI : parameterTypes) { TypeInfo resolvedParameterTI = context.resolve(parameterTI); resolvedParameterTypes.add(resolvedParameterTI); } return new MethodSignature(name, resolvedParameterTypes); } @Override public int hashCode() { return name.hashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof MethodInfo) { MethodInfo that = (MethodInfo)obj; String thatName = that.getName(); MethodSignature signature = getSignature(); MethodSignature thatSignature = that.getSignature(); return owner.equals(getOwner()) && name.equals(thatName) && signature.equals(thatSignature); } return false; } public <AT> AT getDeclaredAnnotation(AnnotationType<AT, ?> annotationType) { if (annotatedDelegate == null) { annotatedDelegate = new AnnotatedDelegate<T, M, A, P, F, M>(domain, domain.methodAnnotationMetadata, method); } return annotatedDelegate.getDeclaredAnnotation(method, annotationType); } public List<ClassTypeInfo> getThrownTypes() { if (thrownTypes == null) { List<ClassTypeInfo> thrownTypes = Collections.emptyList(); for (T thrownType : domain.methodMetadata.getThrownTypes(method)) { if (thrownTypes.isEmpty()) { thrownTypes = new ArrayList<ClassTypeInfo>(); } ClassTypeInfo thrownCTI = (ClassTypeInfo)domain.resolve(thrownType); thrownTypes.add(thrownCTI); } this.thrownTypes = thrownTypes; } return thrownTypes; } @Override public String toString() { return "MethodInfo[name=" + name + ",owner=" + owner + "]"; } }