package org.etk.reflect.api.introspection; import java.beans.Introspector; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.etk.reflect.api.ClassTypeInfo; import org.etk.reflect.api.MethodInfo; import org.etk.reflect.api.ParameterizedTypeInfo; import org.etk.reflect.api.TypeInfo; import org.etk.reflect.api.visit.HierarchyScope; import org.etk.reflect.api.visit.HierarchyVisitor; import org.etk.reflect.api.visit.HierarchyVisitorStrategy; import org.etk.reflect.core.AnnotationType; public class MethodIntrospector { /** . */ private final HierarchyVisitorStrategy strategy; /** . */ private final boolean removeOverrides; /** * Creates an introspector with the specified hierarchy visitor strategy and the specified removeOverrides parameter. * * @param strategy the hierarchy visitor strategy * @param removeOverrides the remove overrides * @throws NullPointerException if the hierarchy scope is null */ public MethodIntrospector(HierarchyVisitorStrategy strategy, boolean removeOverrides) throws NullPointerException { if (strategy == null) { throw new NullPointerException(); } // OK I think this.strategy = strategy; this.removeOverrides = removeOverrides; } /** * Creates an introspector with the specified hierarchy scope and the specified removeOverrides parameter. * * @param hierarchyScope the hierarchy scope * @param removeOverrides the remove overrides * @throws NullPointerException if the hierarchy scope is null */ public MethodIntrospector(HierarchyScope hierarchyScope, boolean removeOverrides) throws NullPointerException { if (hierarchyScope == null) { throw new NullPointerException(); } // this.strategy = hierarchyScope.<AbstractScopedHierarchyVisitor>get(); this.removeOverrides = removeOverrides; } /** * Builds a new introspector with the specified hierarchy scope and a removeOverrides parameter set to false. * * @param hierarchyScope the hierarchy scope * @throws NullPointerException if the hierarchy scope is null */ public MethodIntrospector(HierarchyScope hierarchyScope) throws NullPointerException { this(hierarchyScope, false); } /** * Builds a new introspector with the specified hierarchy visitor strategy and a removeOverrides parameter set to false. * * @param strategy the hierarchy visitor strategy * @throws NullPointerException if the hierarchy scope is null */ public MethodIntrospector(HierarchyVisitorStrategy strategy) throws NullPointerException { this(strategy, false); } public <A> Collection<AnnotationTarget<MethodInfo, A>> resolveMethods(ClassTypeInfo cti, AnnotationType<A, ?> annotationClass) { ArrayList<AnnotationTarget<MethodInfo, A>> methods = new ArrayList<AnnotationTarget<MethodInfo, A>>(); AnnotationIntrospector<A> introspector = new AnnotationIntrospector<A>(annotationClass); for (MethodInfo method : getMethods(cti)) { AnnotationTarget<MethodInfo, A> annotation = introspector.resolve(method); if (annotation != null) { methods.add(annotation); } } return methods; } /** * Returns a map of all method info getters on the specified class type info. * * @param classTypeInfo the class type info * @return an iterable of the method info getters * @throws NullPointerException if the specified class type info is null */ public Map<String, MethodInfo> getGetterMap(ClassTypeInfo classTypeInfo) throws NullPointerException { if (classTypeInfo == null) { throw new NullPointerException(); } Map<String, MethodInfo> getterMap = new LinkedHashMap<String, MethodInfo>(); for (MethodInfo getter : getGetters(classTypeInfo)) { String getterName = getter.getName(); String name; if (getterName.startsWith("get")) { name = Introspector.decapitalize(getterName.substring(3)); } else { name = Introspector.decapitalize(getterName.substring(2)); } getterMap.put(name, getter); } return getterMap; } /** * Find all method info getters on the specified class type info. * * @param classTypeInfo the class type info * @return an iterable of the method info getters * @throws NullPointerException if the specified class type info is null */ public Iterable<MethodInfo> getGetters(ClassTypeInfo classTypeInfo) throws NullPointerException { if (classTypeInfo == null) { throw new NullPointerException(); } final MethodContainer getters = new MethodContainer(); HierarchyVisitor visitor = new AbstractScopedHierarchyVisitor(classTypeInfo) { public void leave(ClassTypeInfo type) { if (!type.getName().equals(Object.class.getName())) { for (MethodInfo method : type.getDeclaredMethods()) { String methodName = method.getName(); if ( (( methodName.startsWith("get") && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3))) || (methodName.startsWith("is") && methodName.length() > 2 && Character.isUpperCase(methodName.charAt(2)))) && method.getParameterTypes().size() == 0) { getters.add(method); } } } } }; // classTypeInfo.accept(strategy, visitor); // return getters; } /** * Returns a map of all method info setters on the specified class type info. * * @param classTypeInfo the class type info * @return an iterable of the method info setters * @throws NullPointerException if the specified class type info is null */ public Map<String, Set<MethodInfo>> getSetterMap(ClassTypeInfo classTypeInfo) throws NullPointerException { Map<String, Set<MethodInfo>> setterMap = new LinkedHashMap<String, Set<MethodInfo>>(); for (MethodInfo setter : getSetters(classTypeInfo)) { String name = Introspector.decapitalize(setter.getName().substring(3)); Set<MethodInfo> setters = setterMap.get(name); if (setters == null) { setters = new LinkedHashSet<MethodInfo>(); setterMap.put(name, setters); } setters.add(setter); } return setterMap; } /** * Find all method info setters on the specified class type info. * * @param classTypeInfo the class type info * @return an iterable of the method info setters * @throws NullPointerException if the specified class type info is null */ public Iterable<MethodInfo> getSetters(ClassTypeInfo classTypeInfo) { if (classTypeInfo == null) { throw new NullPointerException(); } final MethodContainer setters = new MethodContainer(); HierarchyVisitor visitor = new AbstractScopedHierarchyVisitor(classTypeInfo) { public void leave(ClassTypeInfo type) { if (!type.getName().equals(Object.class.getName())) { for (MethodInfo method : type.getDeclaredMethods()) { String methodName = method.getName(); if ( methodName.startsWith("set") && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3)) && method.getParameterTypes().size() == 1) { setters.add(method); } } } } }; // classTypeInfo.accept(strategy, visitor); // return setters; } /** * Returns all method on the specified type info. * * @param typeInfo the type info * @return all the methods * @throws NullPointerException if the specified type info is null */ public Set<MethodInfo> getMethods(TypeInfo typeInfo) throws NullPointerException { if (typeInfo == null) { throw new NullPointerException(); } MethodContainer container; if (removeOverrides) { container = new MethodContainer((ClassTypeInfo)typeInfo); } else { container = new MethodContainer(); } findMethods(typeInfo, container); return container.toCollection(); } private void findMethods(TypeInfo ti, final MethodContainer container) { if (ti instanceof ClassTypeInfo) { strategy.visit(ti, new HierarchyVisitor() { public boolean enter(ClassTypeInfo type) { for (MethodInfo declaredMethod : type.getDeclaredMethods()) { container.add(declaredMethod); } return true; } public void leave(ClassTypeInfo type) { } }); } else if (ti instanceof ParameterizedTypeInfo) { findMethods(((ParameterizedTypeInfo)ti).getRawType(), container); } else { throw new UnsupportedOperationException("Cannot get methods from type " + ti); } } }