package org.zstack.utils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.zstack.utils.function.Function;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.Arrays.asList;
/**
*/
public class BeanUtils {
private enum FilterType {
CLASS,
ANNOTATION,
}
private interface TypeWrapper {
FilterType filterType();
Class clazz();
}
public static List<Class> scanClass(List<String> pkgNames, List<TypeWrapper> includes, List<TypeWrapper> excludes) {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
if (includes != null) {
for (TypeWrapper wrapper : includes) {
if (wrapper.filterType() == FilterType.ANNOTATION) {
scanner.addIncludeFilter(new AnnotationTypeFilter(wrapper.clazz()));
} else if (wrapper.filterType() == FilterType.CLASS) {
scanner.addIncludeFilter(new AssignableTypeFilter(wrapper.clazz()));
} else {
DebugUtils.Assert(false, String.format("unknown type: %s", wrapper.filterType()));
}
}
}
if (excludes != null) {
for (TypeWrapper wrapper : excludes) {
if (wrapper.filterType() == FilterType.ANNOTATION) {
scanner.addExcludeFilter(new AnnotationTypeFilter(wrapper.clazz()));
} else if (wrapper.filterType() == FilterType.CLASS) {
scanner.addExcludeFilter(new AssignableTypeFilter(wrapper.clazz()));
} else {
DebugUtils.Assert(false, String.format("unknown type: %s", wrapper.filterType()));
}
}
}
List<Class> ret = new ArrayList<Class>();
for (String pkg : pkgNames) {
for (BeanDefinition bd : scanner.findCandidateComponents(pkg)) {
try {
Class clz = Class.forName(bd.getBeanClassName());
ret.add(clz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
return ret;
}
public static List<Class> scanClassByType(List<String> pkgNames, List<Class> includeTypes, List<Class> excludeTypes) {
List<TypeWrapper> includes = CollectionUtils.transformToList(includeTypes, new Function<TypeWrapper, Class>() {
@Override
public TypeWrapper call(final Class arg) {
return new TypeWrapper() {
@Override
public FilterType filterType() {
return FilterType.CLASS;
}
@Override
public Class clazz() {
return arg;
}
};
}
});
List<TypeWrapper> excludes = CollectionUtils.transformToList(excludeTypes, new Function<TypeWrapper, Class>() {
@Override
public TypeWrapper call(final Class arg) {
return new TypeWrapper() {
@Override
public FilterType filterType() {
return FilterType.CLASS;
}
@Override
public Class clazz() {
return arg;
}
};
}
});
return scanClass(pkgNames, includes, excludes);
}
public static List<Class> scanClassByType(List<String> pkgNames, List<Class> includeTypes) {
List<TypeWrapper> includes = CollectionUtils.transformToList(includeTypes, new Function<TypeWrapper, Class>() {
@Override
public TypeWrapper call(final Class arg) {
return new TypeWrapper() {
@Override
public FilterType filterType() {
return FilterType.CLASS;
}
@Override
public Class clazz() {
return arg;
}
};
}
});
return scanClass(pkgNames, includes, null);
}
public static List<Class> scanClassByType(String pkgName, Class includeType) {
return scanClassByType(asList(pkgName), asList(includeType));
}
public static List<Class> scanClass(List<String> pkgNames, List<Class> includeAnnotations) {
List<TypeWrapper> includes = CollectionUtils.transformToList(includeAnnotations, new Function<TypeWrapper, Class>() {
@Override
public TypeWrapper call(final Class arg) {
return new TypeWrapper() {
@Override
public FilterType filterType() {
return FilterType.ANNOTATION;
}
@Override
public Class clazz() {
return arg;
}
};
}
});
return scanClass(pkgNames, includes, null);
}
public static List<Class> scanClass(String pkgName, List<Class> includeAnnotations) {
return scanClass(asList(pkgName), includeAnnotations);
}
public static List<Class> scanClass(String pkgName, Class includeAnnotation) {
return scanClass(asList(pkgName), asList(includeAnnotation));
}
public static List<Class> scanClass(List<String> pkgNames, Class includeAnnotation) {
return scanClass(pkgNames, asList(includeAnnotation));
}
private static Object getProperty(Object bean, Iterator<String> it) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String path = it.next();
if (bean instanceof Map) {
Pattern re = Pattern.compile("(.*)\\[(\\d+)]");
Matcher m = re.matcher(path);
if (m.find()) {
path = String.format("(%s)[%s]", m.group(1), m.group(2));
}
}
Object val = PropertyUtils.getProperty(bean, path);
if (it.hasNext()) {
return getProperty(val, it);
} else {
return val;
}
}
public static Object getProperty(Object bean, String path) {
List<String> paths = asList(path.split("\\."));
try {
return getProperty(bean, paths.iterator());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void setProperty(Object bean, Iterator<String> it, String fieldName, Object val) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
if (it.hasNext()) {
bean = getProperty(bean, it);
}
if (bean instanceof Map) {
Pattern re = Pattern.compile("(.*)\\[(\\d+)]");
Matcher m = re.matcher(fieldName);
if (m.find()) {
fieldName = String.format("(%s)[%s]", m.group(1), m.group(2));
}
}
PropertyUtils.setProperty(bean, fieldName, val);
}
public static void setProperty(Object bean, String path, Object val) {
List<String> paths = asList(path.split("\\."));
String fieldName = paths.get(paths.size()-1);
paths = paths.subList(0, paths.size()-1);
try {
setProperty(bean, paths.iterator(), fieldName, val);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}