package org.hivedb.util.classgen;
import org.hivedb.HiveRuntimeException;
import org.hivedb.util.functional.*;
import org.hivedb.util.functional.Joiner.ConcatStrings;
import org.hivedb.util.PropertyAccessor;
import org.hivedb.util.PrimitiveUtils;
import java.lang.reflect.*;
import java.util.*;
public class ReflectionTools {
public interface SetterWrapper {
void invoke(Object instance, Object value);
Method getRealSetter();
}
public static final class Descriptor {
private final Class<?> clazz;
private final Collection<Method> deepMethods;
private final Collection<Method> declaredPublicMethods;
private final Map<Method, SetterWrapper> accessors;
private final Map<Method, String> propertyByGetter;
private final Map<String, Method> getterByProperty;
private final Map<String, Class<?>> ownerByProperty;
private final Map<Method, Map<Class<?>, SetterWrapper>> settersByGetter;
private final Map<SetterWrapper, String> propertyBySetter;
private Method rawSetter;
Descriptor(final Class<?> clazz) {
this.clazz = clazz;
deepMethods = Collections.unmodifiableCollection(ReflectionTools.getDeepMethods(clazz));
declaredPublicMethods = new HashSet<Method>();
for (Method method : clazz.getDeclaredMethods()) {
if ((method.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC) {
declaredPublicMethods.add(method);
}
}
Map<String, Class<?>> cache = new HashMap<String, Class<?>>();
accessors = new HashMap<Method, SetterWrapper>();
for (final Method method : clazz.getMethods()) {
if (ReflectionTools.isGetter(method)) {
final String propertyName = formPropertyNameFromGetter(method);
if (cache.containsKey(propertyName)) {
// We always want to return the most derived version of the same method
if (method.getDeclaringClass().isAssignableFrom(cache.get(propertyName))) {
continue;
}
}
cache.put(propertyName, method.getDeclaringClass());
// Interface has no setter, create a wrapper setter
SetterWrapper propertySetterWrapper = new SetterWrapper() {
public void invoke(Object instance, Object value) {
Method setter = getRealSetter();
if (setter != null)
try {
setter.invoke(instance, new Object[] {value});
} catch (Exception e) {
new RuntimeException(e);
}
else if (instance instanceof PropertyAccessor)
((PropertyAccessor)instance).set(propertyName, value);
else
throw new HiveRuntimeException(String.format("No way to inoke setter of class %s, property %s", instance.getClass(), propertyName));
}
public Method getRealSetter() {
try {
return clazz.getMethod(makeSetterName(propertyName), new Class[] {method.getReturnType()});
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException em) {
return null;
}
}
};
try {
accessors.put(method, propertySetterWrapper);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
propertyByGetter = new HashMap<Method, String>();
getterByProperty = new HashMap<String, Method>();
for (Method method : accessors.keySet()) {
String property = formPropertyNameFromGetter(method);
propertyByGetter.put(method, property);
getterByProperty.put(property, method);
}
ownerByProperty = new HashMap<String, Class<?>>();
for (Method getter : accessors.keySet()) {
String property = getPropertyName(getter);
Class<?> owner = ReflectionTools.getOwnerOfMethod(clazz, getter.getName(), new Class[] {});
ownerByProperty.put(property, owner);
}
settersByGetter = new HashMap<Method, Map<Class<?>, SetterWrapper>>();
for (Method getter : accessors.keySet()) {
Map<Class<?>, SetterWrapper> setters = new HashMap<Class<?>, SetterWrapper>();
setters.put(getter.getReturnType(), accessors.get(getter));
for (Method method : clazz.getMethods()) {
if (method.getName().equals(getter.getName())) {
setters.put(method.getReturnType(), accessors.get(getter));
}
}
settersByGetter.put(getter, setters);
}
propertyBySetter = new HashMap<SetterWrapper, String>();
for (Method getter : accessors.keySet()) {
String property = formPropertyNameFromGetter(getter);
propertyByGetter.put(getter, property);
for (SetterWrapper setterWrapper : settersByGetter.get(getter).values()) {
propertyBySetter.put(setterWrapper, property);
}
}
try {
for (Class<?> c = clazz; !c.equals(Object.class) && rawSetter == null; c = c.getSuperclass()) {
rawSetter = clazz.getDeclaredMethod("set", String.class, Object.class);
}
} catch (Exception ex) {
}
}
private String formPropertyNameFromGetter(Method getter) {
String name = getter.getName();
if (name.startsWith("is")) {
return name.substring(2, 3).toLowerCase().concat(name.length() > 3 ? name.substring(3) : "");
}
return name.substring(3, 4).toLowerCase().concat(name.length() > 4 ? name.substring(4) : "");
}
public Collection<Method> getDeepMethods() {
return deepMethods;
}
public Class<?> getRepresentedClass() {
return clazz;
}
public Collection<Method> getGetters() {
return accessors.keySet();
}
public String getPropertyName(Method method) {
return propertyByGetter.get(method);
}
public boolean doesSetterExist(Method getter) {
return accessors.get(getter).getRealSetter() != null;
}
public SetterWrapper getCorrespondingSetter(String getterName, Class<?> argument) {
return getSetterOfProperty(toProperty(getterName), argument);
}
public SetterWrapper getCorrespondingSetter(Method getter) {
return accessors.get(getter);
}
public Method getCorrespondingGetter(String setterName) {
return getterByProperty.get(toProperty(setterName));
}
public Method getGetterOfProperty(String property) {
return getterByProperty.get(property);
}
public boolean hasGetterOfProperty(String property) {
return getterByProperty.get(property) != null;
}
public SetterWrapper getSetterOfProperty(String property) {
return accessors.get(getterByProperty.get(property));
}
public SetterWrapper getSetterOfProperty(String property, Class<?> argument) {
return accessors.get(getterByProperty.get(property));
}
public Collection<Method> getDeclaredPublicMethods() {
return declaredPublicMethods;
}
public Method getRawSetter() {
return rawSetter;
}
public Collection<String> getPropertiesOfGetters() {
return getterByProperty.keySet();
}
public Class<?> getOwnerOfMethod(String property) {
return ownerByProperty.get(property);
}
private String toProperty(String accessor) {
return accessor.substring(3, 4).toLowerCase().concat(accessor.length() > 4 ? accessor.substring(4) : "");
}
}
private static Map<Class<?>, Descriptor> descriptors = new HashMap<Class<?>, Descriptor>();
private static void checkInitialized(Class<?> clazz) {
if (! descriptors.containsKey(clazz)) {
descriptors.put(clazz, new Descriptor(clazz));
}
}
/**
* Creates a hash code based on the getters of an interface
* @param clazz
* @return
*/
public static <T> int getInterfaceHashCode(T instance, Class<T> basedUponThisInterface) {
return Amass.makeHashCode(invokeGetters(instance, basedUponThisInterface));
}
// Since Java has dumb getters and setters, this helps match
// a private field to it's corresponding getter and/or setter
public static String capitalize(String s) {
if (s.length() == 0) return s;
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
public static boolean isGetter(String s) {
return s.startsWith("get");
}
public static String makeGetterName(String propertyName) {
return "get"+capitalize(propertyName);
}
public static boolean isSetter(String s) {
return s.startsWith("set");
}
public static String makeSetterName(String propertyName) {
return "set"+capitalize(propertyName);
}
/*
* Strip the get or set off a getter or setter and lower case
* the name to reveal the underlying property name
*
*/
public static String getPropertyNameOfAccessor(Method accessor) {
Class<?> clazz = accessor.getDeclaringClass();
checkInitialized(clazz);
return descriptors.get(clazz).getPropertyName(accessor);
}
public static boolean isGetter(Method method) {
return
(method.getName().startsWith("is") || method.getName().startsWith("get")) &&
method.getReturnType() != void.class &&
method.getParameterTypes().length == 0;
}
public static boolean isSetter(Method method) {
return
method.getName().startsWith("set") &&
method.getReturnType() == void.class &&
method.getParameterTypes().length == 1;
}
public static boolean doesRealSetterExist(Method getter) {
Class<?> clazz = getter.getDeclaringClass();
checkInitialized(clazz);
return descriptors.get(clazz).doesSetterExist(getter);
}
public static SetterWrapper getCorrespondingSetterWrapper(Object instance, String getterName, Class argumentType) {
Class<?> clazz = instance.getClass();
checkInitialized(clazz);
return descriptors.get(clazz).getCorrespondingSetter(getterName, argumentType);
}
public static SetterWrapper getCorrespondingSetterWrapper(Method getter) {
Class<?> clazz = getter.getDeclaringClass();
checkInitialized(clazz);
return descriptors.get(clazz).getCorrespondingSetter(getter);
}
public static Method getCorrespondingGetter(Object instance, String setterName) {
Class<?> clazz = instance.getClass();
checkInitialized(clazz);
return descriptors.get(clazz).getCorrespondingGetter(setterName);
}
public static Method getGetterOfProperty(Class ofInterface, final String property) {
checkInitialized(ofInterface);
return descriptors.get(ofInterface).getGetterOfProperty(property);
}
public static boolean hasGetterOfProperty(Class ofInterface, final String property) {
checkInitialized(ofInterface);
return descriptors.get(ofInterface).hasGetterOfProperty(property);
}
public static SetterWrapper getSetterWrapperOfProperty(Class ofInterface, String property) {
checkInitialized(ofInterface);
return descriptors.get(ofInterface).getSetterOfProperty(property);
}
public static Method getSetterOfProperty(Class ofInterface, String property) {
checkInitialized(ofInterface);
return descriptors.get(ofInterface).getSetterOfProperty(property).getRealSetter();
}
public static Collection<Method> getDeclaredPublicMethods(Class subject) {
checkInitialized(subject);
return descriptors.get(subject).getDeclaredPublicMethods();
}
public static boolean doesImplementOrExtend(Class doesClass, Class implementOrExtendThisClass) {
return implementOrExtendThisClass.isAssignableFrom(doesClass);
}
public static boolean doesImplementOrExtend(final Class[] doesOneOfThese, final Class matchOrImplementThisInterface) {
for (Class clazz : doesOneOfThese) {
if (doesImplementOrExtend(clazz, matchOrImplementThisInterface)){
return true;
}
}
return false;
}
/**
* Returns the interface in the list that is mostly closest to the given class/interface.
* The order of search is 1) see if the class matches one of the given interfaces,
* 2) see if one of the class's implemented interfaces and interfaces of those interfaces implements
* one of the given interfaces, 3) rerun this method on the given class's parent class.
*
* This test should be used when there is one obvious answer, not when the answer may be ambiguous,
* in which case the returned class will not be meaningful.
* @param doesClassOrInterface
* @param implementOneOfTheseInterfaces
* @return
*/
public static Class whichIsImplemented(final Class doesClassOrInterface, final Collection<? extends Class> implementOneOfTheseInterfaces)
{
Class answer = Filter.grepSingleOrNull(new Predicate<Class>() {
public boolean f(Class implementThisInterface) {
return doesClassOrInterface.equals(implementThisInterface);
}},
implementOneOfTheseInterfaces);
if (answer != null)
return answer;
answer = Filter.grepSingleOrNull(new Filter.NotNullPredicate<Class>(),
Transform.map(new Unary<Class, Class>() {
public Class f(Class anInterface) {
return whichIsImplemented(anInterface, implementOneOfTheseInterfaces);
}},
Arrays.asList(doesClassOrInterface.getInterfaces())));
if (answer != null)
return answer;
return
(doesClassOrInterface.getSuperclass() != null && !doesClassOrInterface.getSuperclass().equals(Object.class))
? whichIsImplemented(doesClassOrInterface.getSuperclass(), implementOneOfTheseInterfaces)
: null;
}
public static<T> Collection<Method> getNullFields(final T checkMembersOfThis, Class<T> basedUponThisInterface) {
return
new MethodGrepper<T>() {
public boolean invokableMemberPredicate(Method getter) {
try {
return getter.invoke(checkMembersOfThis) == null;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}.grepGetters(basedUponThisInterface);
}
public static<T> Collection<Object> invokeGetters(final T instance, Class<T> basedUponThisInterface) {
checkInitialized(basedUponThisInterface);
return invokeGetters(instance, descriptors.get(basedUponThisInterface).getGetters());
}
public static<T> Collection<Object> invokeGetters(final T instance, Collection<Method> getters) {
return Transform.map(new Unary<Method, Object>() {
public Object f(Method method) {
try {
return method.invoke(instance, new Object[] {});
} catch (Exception e) {
throw new RuntimeException(e);
}
}},
getters);
}
public static Object invokeGetter(Object instance, String propertyName)
{
Class<?> clazz = instance.getClass();
checkInitialized(clazz);
Method getter = descriptors.get(clazz).getGetterOfProperty(propertyName);
// try to match on the value's type
try {
return getter.invoke(instance, new Object[] {});
}
catch (Exception e) {
throw new RuntimeException(String.format("Error invoking %s of class %s", getter.getName(), instance.getClass()), e);
}
}
public static void invokeSetter(Object instance, String propertyName, Object value)
{
Class<?> clazz = instance.getClass();
checkInitialized(clazz);
// try to match on the value's type - for now we only have standard accessors (no need to match value Class)
SetterWrapper setterWrapper = descriptors.get(clazz).getSetterOfProperty(propertyName);
// PropertySetterWrapper setterWrapper = descriptors.get(clazz).getSetterOfProperty(propertyName, value.getClass()); causes NPE if value == null
if (setterWrapper != null) {
try {
// Invoke our SetterWrapper
setterWrapper.invoke(instance, value);
return;
} catch (Exception ex) {
throw new RuntimeException("Exception calling method " + makeSetterName(propertyName) + " with a value of type " + (value == null || value.getClass() == null ? "null" : value.getClass().getName()), ex);
}
}
}
public static<T> Collection<Method> getGetters(final Class<T> ofThisInterface) {
checkInitialized(ofThisInterface);
return descriptors.get(ofThisInterface).getGetters();
}
public static<T> Collection<String> getPropertiesOfGetters(final Class<T> ofThisInterface) {
checkInitialized(ofThisInterface);
return descriptors.get(ofThisInterface).getPropertiesOfGetters();
}
public static<T> DiffCollection getEqualFields(final T expected, final T actual, Class<T> basedUponThisInterface) {
return compareFields(expected, actual, basedUponThisInterface, new Filter.EqualFunction<Object>());
}
public static<T> DiffCollection getDifferingFields(final T expected, final T actual, Class<T> basedUponThisInterface) {
return compareFields(expected, actual, basedUponThisInterface, new Filter.UnequalFunction<Object>());
}
public static class Diff
{
private Method method;
private Object fieldValueOfInstance1;
private Object fieldValueOfInstance2;
public Diff(Method method, Object fieldValueOfInstance1, Object fieldValueOfInstance2)
{
this.method = method;
this.fieldValueOfInstance1 = fieldValueOfInstance1;
this.fieldValueOfInstance2 = fieldValueOfInstance2;
}
public Object getFieldOfInstance1() {
return fieldValueOfInstance1;
}
public Object getFieldOfInstance2() {
return fieldValueOfInstance2;
}
public Method getMethod() {
return method;
}
public String toString() {
return String.format("Method: %s, FieldValue1: %s (hash: %s), FieldValue2: %s (hash: %s)", method, fieldValueOfInstance1!=null?fieldValueOfInstance1:"null", fieldValueOfInstance1!=null?fieldValueOfInstance1.hashCode():0, fieldValueOfInstance2!=null?fieldValueOfInstance2:"null", fieldValueOfInstance2!=null?fieldValueOfInstance2.hashCode():0);
}
}
public static class DiffCollection extends ArrayList<Diff>
{
private static final long serialVersionUID = 1L;
public DiffCollection(Collection<Diff> c) {
super(c);
}
public boolean containsGetter(final String getterName)
{
return Filter.isMatch(new Predicate<Diff>() {
public boolean f(Diff diff) {
return diff.getMethod().getName().equals(getterName);
}
}, this);
}
@Override
public String toString() {
return String.format("The following fields differ %s", Amass.joinByToString(new ConcatStrings<Diff>(", "), this));
}
}
private static <T> DiffCollection compareFields(final T expected, final T actual, Class<T> basedUponThisInterface, final Filter.BinaryPredicate<Object, Object> compare) {
if (expected == null || actual == null)
throw new RuntimeException(String.format("Expected and/or actual instance are/is null. Expected null? %s, Actual null? %s", expected==null, actual==null ));
return new DiffCollection(Transform.map(new Unary<Method, Diff>() {
public Diff f(Method getter) {
try {
return new Diff(getter, wrapIfNeeded(getter.invoke(expected)), wrapIfNeeded(getter.invoke(actual)));
} catch(Exception e) {
throw new RuntimeException(e);
}
}},
new MethodGrepper<T>() {
public boolean invokableMemberPredicate(Method getter) {
try {
final Object expectedWrapped = wrapIfNeeded(getter.invoke(expected));
final Object actualWrapped = wrapIfNeeded(getter.invoke((actual)));
if (expectedWrapped == null || actualWrapped == null)
return (expectedWrapped==null ^ actualWrapped==null);
return compare.f(expectedWrapped, actualWrapped);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}.grepGetters(basedUponThisInterface)));
}
@SuppressWarnings("unchecked")
private static Object wrapIfNeeded(Object fieldValue)
{
if (fieldValue instanceof Collection)
return new HashSet((Collection)fieldValue);
return fieldValue;
}
private static class MethodGrepper<T> {
public Collection<Method> grepGetters(Class<T> basedUponThisInterface) {
checkInitialized(basedUponThisInterface);
Collection<Method> deepMethods = descriptors.get(basedUponThisInterface).getDeepMethods();
Collection<Method> getters = Filter.grep(new Predicate<Method>() {
public boolean f(Method method) {
try {
return
!method.getDeclaringClass().equals(Object.class) &&
isGetter(method) &&
invokableMemberPredicate(method);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}, deepMethods);
return getters;
}
/**
* Override this to filter for specific methods
* @param getter
* @return
*/
public boolean invokableMemberPredicate(Method getter) { return true; }
}
// Returns uniquely named methods belong to the given class and its ancestors.
private static Collection<Method> getDeepMethods(Class<?> clazz) {
return Filter.grepUnique(
new Unary<Method, String>() {
public String f(Method method) {
return method.getName();
}
}, Transform.flatMap(new Unary<Class<?>, Collection<Method>>() {
public Collection<Method> f(Class<?> clazz) {
return Arrays.asList(clazz.getMethods());
}
}, Transform.flatten(Arrays.asList((Class<?>[])new Class[] { clazz }), getAncestors(clazz))));
}
public static Class<?> getPropertyType(final Class<?> ofThisInterface, String propertyName) {
checkInitialized(ofThisInterface);
return descriptors.get(ofThisInterface).getGetterOfProperty(propertyName).getReturnType();
}
public static Class<?> getCollectionItemType(final Class<?> clazz, final String propertyName) {
checkInitialized(clazz);
Class ofThisInterface = descriptors.get(clazz).getOwnerOfMethod(propertyName);
final Method getter = descriptors.get(ofThisInterface).getGetterOfProperty(propertyName);
Type type = getter.getGenericReturnType();
if (type instanceof ParameterizedType) {
Type typeArgument = Atom.getFirstOrThrow(((ParameterizedType)type).getActualTypeArguments());
try {
return (Class)(typeArgument instanceof WildcardType
? Atom.getFirstOrThrow(((WildcardType)typeArgument).getUpperBounds())
: (typeArgument instanceof ParameterizedType)
? ((ParameterizedType)typeArgument).getRawType()
: typeArgument);
}
catch (ClassCastException e) {
throw new RuntimeException(String.format("For Interface: %s, Property Name %s, expected ParameterizedType or WildcardType but got %s", ofThisInterface, propertyName, typeArgument), e);
}
}
else
throw new RuntimeException(String.format("For Interface: %s, Property Name %s, expected ParameterizedType or WildcardType but got %s", ofThisInterface, propertyName, type));
}
public static Class getOwnerOfMethod(final Class<?> clazz, final String propertyName) {
checkInitialized(clazz);
// Java magically erases generic information when referencing a method from a subclass,
// extended interface, or implementation (naturally)
// Extract the first owning interface or superclass if it exists
return descriptors.get(clazz).getOwnerOfMethod(propertyName);
}
public static Method getMethodOfOwner(Method method) {
Class owner = getOwnerOfMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes());
try {
return owner.getMethod(method.getName(), method.getParameterTypes());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Class getOwnerOfMethod(final Class<?> clazz, final String methodName, final Class[] parameterTypes) {
final List<Class> classes = new ArrayList(getAncestors(clazz));
Class ofThisInterface;
ofThisInterface =
Filter.grepSingleOrNull(new Predicate<Class>() {
public boolean f(Class c) {
try {
c.getDeclaredMethod(methodName, parameterTypes);
return true;
}
catch (Exception e) {
return false;
}
}
}, classes);
if (ofThisInterface == null)
ofThisInterface = clazz;
return ofThisInterface;
}
private static Collection<Class<?>> getAncestors(Class<?> clazz) {
return Transform.flatten(new Collection[] {
clazz.getSuperclass() != null ? getAncestors(clazz.getSuperclass()) : new ArrayList<Class<?>>(),
Transform.flatMap(new Unary<Class<?>, Collection<Class<?>>>() {
public Collection<Class<?>> f(Class<?> interfaceClass) {
return Transform.flatten(new Collection[] {Collections.singleton(interfaceClass), getAncestors(interfaceClass)});
}
}, Arrays.asList((Class<?>[])clazz.getInterfaces()))});
}
/**
* Returns the given property's return type or the type of item in the collection if its return type
* is a collection.
*/
public static Class<?> getPropertyTypeOrPropertyCollectionItemType(final Class<?> ofThisInterface, String propertyName) {
return isCollectionProperty(ofThisInterface, propertyName)
? getCollectionItemType(ofThisInterface, propertyName)
: getPropertyType(ofThisInterface, propertyName);
}
public static boolean isCollectionProperty(final Class<?> ofThisInterface, String propertyName) {
return ReflectionTools.doesImplementOrExtend(
ReflectionTools.getPropertyType(ofThisInterface, propertyName),
Collection.class);
}
public static Collection<String> getPropertiesOfScalarGetters(final Class<?> ofThisInterface) {
return Filter.grep(new Predicate<String>() {
public boolean f(String propertyName) {
return !isCollectionProperty(ofThisInterface, propertyName);
}},
getPropertiesOfGetters(ofThisInterface));
}
public static Collection<String> getPropertiesOfCollectionGetters(final Class<?> ofThisInterface) {
return Filter.grep(new Predicate<String>() {
public boolean f(String propertyName) {
return isCollectionProperty(ofThisInterface, propertyName);
}},
getPropertiesOfGetters(ofThisInterface));
}
public static Collection<Method> getCollectionGetters(final Class<?> ofThisInterface) {
return Filter.grep(new Predicate<Method>() {
public boolean f(Method getter) {
return isCollectionProperty(ofThisInterface, getPropertyNameOfAccessor(getter));
}},
getGetters(ofThisInterface));
}
public static Collection<String> getPropertiesOfPrimitiveGetters(final Class<?> ofThisInterface) {
return Filter.grep(new Predicate<String>() {
public boolean f(String propertyName) {
final Class<?> propertyType = getPropertyType(ofThisInterface, propertyName);
return !ReflectionTools.getOwnerOfMethod(ofThisInterface, propertyName).equals(Object.class) &&
!PrimitiveUtils.isClass(propertyType) &&
PrimitiveUtils.isPrimitiveClass(propertyType);
}},
getPropertiesOfGetters(ofThisInterface));
}
public static Collection<String> getPropertiesOfComplexGetters(final Class<?> ofThisInterface) {
return Transform.map(new Unary<Method,String>() {
public String f(Method method) {
return ReflectionTools.getPropertyNameOfAccessor(method);
}},
getComplexGetters(ofThisInterface));
}
public static Collection<Method> getComplexGetters(final Class<?> ofThisInterface) {
return Filter.grep(new Predicate<Method>() {
public boolean f(Method getter) {
return !PrimitiveUtils.isPrimitiveClass(getPropertyType(ofThisInterface, ReflectionTools.getPropertyNameOfAccessor(getter)));
}},
getGetters(ofThisInterface));
}
public static Collection<String> getPropertiesOfGivenType(final Class<?> representedInterface, final Class<?> propertyType) {
return Filter.grep(new Predicate<String>() {
public boolean f(String propertyName) {
return propertyType.equals(ReflectionTools.getPropertyType(representedInterface, propertyName));
}
}, ReflectionTools.getPropertiesOfGetters(representedInterface));
}
/**
* Gets all non-primitive classes nested in the given classes.
* @param representedInterfaces
* @return The given classes and nested classes.
*/
@SuppressWarnings("unchecked")
public static Collection<Class<?>> getUniqueComplexPropertyTypes(final Collection representedInterfaces) {
if (representedInterfaces.size() == 0)
return Collections.emptyList();
final Collection<Class<?>> uniqueComplexPropertyTypes = getUniqueComplexPropertyTypes(
Filter.getUnique(
Transform.flatten(Transform.map(new Unary<Class<?>, Collection<Class<?>>>() {
public Collection<Class<?>> f(Class<?> representedInterface) {
return getInterfacesOfComplexGetters(representedInterface);
}}, representedInterfaces))));
// Return a unique collection of the given representedInterfaces merged with the
// flattened deep collection of all their contained complex property types
return Filter.getUnique(Transform.flatten((Collection<Class<?>>[])new Collection[] {
representedInterfaces,
uniqueComplexPropertyTypes}));
}
// Get the return types of getters or the underlying type of a collection getter for types that are not primitive
public static Collection<Class<?>> getInterfacesOfComplexGetters(final Class representedInterface) {
return Filter.getUnique(
Transform.map(new Unary<String,Class<?>>() {
public Class<?> f(String propertyName) {
return ReflectionTools.getPropertyTypeOrPropertyCollectionItemType(representedInterface, propertyName);
}},
Filter.grep(new Predicate<String>() {
public boolean f(String property) {
return !(ReflectionTools.isCollectionProperty(representedInterface, property)) ||
!PrimitiveUtils.isPrimitiveClass(ReflectionTools.getCollectionItemType(representedInterface, property));
}
},
ReflectionTools.getPropertiesOfComplexGetters(representedInterface))));
}
public static boolean isComplexCollectionItemProperty(final Class representedInterface, String property) {
return ReflectionTools.isCollectionProperty(representedInterface, property) &&
!PrimitiveUtils.isPrimitiveClass(ReflectionTools.getCollectionItemType(representedInterface, property));
}
/**
* I'm not sure if this done any good since getMethods should only return the owned methods
* @param clazz
* @return
*/
public static Collection<Method> getOwnedMethods(final Class<?> clazz) {
return Filter.grep(new Predicate<Method>() {
public boolean f(Method method) {
return method.getDeclaringClass().equals(clazz);
}}, Arrays.asList(clazz.getMethods()));
}
}