/*
* Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org Use is subject to license terms. See
* license.txt.
*/
// TODO javadoc - remove this comment only when the class and all non-public
// methods and fields are documented
package org.beanfabrics.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Michael Karneim
*/
public class SupportUtil {
private static class Entry<M extends Member> {
private final M member;
private final int level;
public Entry(M member, int level) {
this.member = member;
this.level = level;
}
public int getLevel() {
return level;
}
public M getMember() {
return member;
}
@Override
public String toString() {
return "Entry [member=" + member + ", level=" + level + "]";
}
}
/**
* Returns a sorted copy of the given {@link List} of {@link Member}s. The members are sorted by the hierarchical
* level of their declaring {@link Class} or by the value of the optional defined {@link SortOrder} annotation, if the
* compared members are declared in the same class.
*
* @param members the members to sort
* @return the sorted list
*/
public static <M extends Member> List<M> sortMembers(List<M> members) {
List<Entry<M>> entries = toEntries(members);
Comparator<Entry<M>> comparator = new Comparator<Entry<M>>() {
public int compare(Entry<M> o1, Entry<M> o2) {
int levelComparison = o1.getLevel() - o2.getLevel();
if (levelComparison != 0) {
return levelComparison;
}
int classnameComparison =
o1.getMember().getDeclaringClass().getName().compareTo(o2.getMember().getDeclaringClass().getName());
if (classnameComparison != 0) {
return classnameComparison;
}
int sortOrderComparison = getSortOrderComparison(o1.getMember(), o2.getMember());
if (sortOrderComparison != 0) {
return sortOrderComparison;
}
int memberNameComparison = o1.getMember().getName().compareTo(o2.getMember().getName());
return memberNameComparison;
}
private int getSortOrderComparison(Member m1, Member m2) {
SortOrder a1 = getAnnotation(m1, SortOrder.class);
SortOrder a2 = getAnnotation(m2, SortOrder.class);
int i1 = a1 == null ? 0 : a1.value();
int i2 = a2 == null ? 0 : a2.value();
int sortOrderComparison = i1 - i2;
return sortOrderComparison;
}
private <T extends Annotation> T getAnnotation(Member member, Class<T> cls) {
if (member instanceof Field) {
return ((Field) member).getAnnotation(cls);
} else if (member instanceof Method) {
return ((Method) member).getAnnotation(cls);
} else {
throw new Error("Unexpected member type: " + member.getClass().getName());
}
}
};
try {
Collections.sort(entries, comparator);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
throw ex;
}
return toMembers(entries);
}
private static <M extends Member> List<M> toMembers(List<Entry<M>> entries) {
List<M> result = new ArrayList<M>();
for (Entry<M> e : entries) {
result.add(e.getMember());
}
return result;
}
private static <M extends Member> List<Entry<M>> toEntries(List<M> members) {
List<Entry<M>> result = new ArrayList<Entry<M>>();
Map<Class<?>, Integer> classLevelCache = new HashMap<Class<?>, Integer>();
for (M member : members) {
Class<?> cls = member.getDeclaringClass();
int level = calculateHierarchyLevel(cls, classLevelCache);
result.add(new Entry<M>(member, level));
}
return result;
}
private static int calculateHierarchyLevel(Class<?> cls, Map<Class<?>, Integer> classLevelCache) {
if (cls == null) {
return 0;
}
Integer cachedValue = classLevelCache.get(cls);
if (cachedValue != null) {
return cachedValue;
}
Class<?> superclass = cls.getSuperclass();
int result = 1 + calculateHierarchyLevel(superclass, classLevelCache);
Class<?>[] interfaces = cls.getInterfaces();
for (Class<?> interf : interfaces) {
result = Math.max(result, 1 + calculateHierarchyLevel(interf, classLevelCache));
}
classLevelCache.put(cls, result);
return result;
}
public static String format(Method method) {
StringBuffer buf = new StringBuffer();
buf.append(getBasename(method.getDeclaringClass()));
buf.append(".").append(method.getName());
buf.append("(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; ++i) {
if (i > 0) {
buf.append(", ");
}
buf.append(getBasename(params[i]));
}
buf.append(")");
return buf.toString();
}
public static String format(Field field) {
StringBuffer buf = new StringBuffer();
buf.append(getBasename(field.getDeclaringClass()));
buf.append(".").append(field.getName());
return buf.toString();
}
private static String getBasename(Class<?> cls) {
String name = cls.getName();
int idx = name.lastIndexOf('.');
if (idx == -1) {
return name;
} else {
return name.substring(idx + 1);
}
}
}