package com.github.ompc.greys.core.manager.impl;
import com.github.ompc.greys.core.ClassDataSource;
import com.github.ompc.greys.core.GlobalOptions;
import com.github.ompc.greys.core.manager.ReflectManager;
import com.github.ompc.greys.core.util.GaCheckUtils;
import com.github.ompc.greys.core.util.GaMethod;
import com.github.ompc.greys.core.util.matcher.Matcher;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import static com.github.ompc.greys.core.util.GaReflectUtils.recGetSuperClass;
/**
* 默认反射操作管理类实现
* Created by vlinux on 15/11/1.
*/
public class DefaultReflectManager implements ReflectManager {
private final ClassDataSource classDataSource;
public DefaultReflectManager(ClassDataSource classDataSource) {
this.classDataSource = classDataSource;
}
@Override
public Collection<Class<?>> searchClass(final Matcher<Class<?>> classMatcher) {
final Set<Class<?>> classSet = new LinkedHashSet<Class<?>>();
for (Class<?> clazz : classDataSource.allLoadedClasses()) {
if (classMatcher.matching(clazz)) {
classSet.add(clazz);
}
}
return classSet;
}
@Override
public Collection<Class<?>> searchSubClass(final Class<?> targetClass) {
final Set<Class<?>> classSet = new LinkedHashSet<Class<?>>();
for (Class<?> clazz : classDataSource.allLoadedClasses()) {
if (!clazz.equals(targetClass)
&& targetClass.isAssignableFrom(clazz)) {
classSet.add(clazz);
}
}
return classSet;
}
@Override
public Collection<Class<?>> searchClassWithSubClass(Matcher<Class<?>> classMatcher) {
final Set<Class<?>> matchedClassSet = new LinkedHashSet<Class<?>>();
// 搜索所有匹配器需求
// 搜索当前匹配器所匹配的类
for (Class<?> matchedClass : searchClass(classMatcher)) {
// 首先添加自己
matchedClassSet.add(matchedClass);
if (!GlobalOptions.isDisableSubClass) {
// 继续搜索子类
matchedClassSet.addAll(searchSubClass(matchedClass));
}
}
return matchedClassSet;
}
/**
* 返回类中的所有可见方法<br/>
* 所谓可见方法的定义是开发在类中可以直接通过Java语法继承关系感知到的方法
*
* @param clazz 目标类
* @return 类的所有可见方法
*/
private Set<Method> listVisualMethod(final Class<?> clazz) {
final Set<Method> methodSet = new LinkedHashSet<Method>();
// 首先查出当前类所声明的所有方法
final Method[] classDeclaredMethodArray = clazz.getDeclaredMethods();
if (null != classDeclaredMethodArray) {
for (Method declaredMethod : classDeclaredMethodArray) {
methodSet.add(declaredMethod);
}
}
// 查出当前类所有的父类
final Collection<Class<?>> superClassSet = recGetSuperClass(clazz);
// 查出所有父类的可见方法
for (Class<?> superClass : superClassSet) {
final Method[] superClassDeclaredMethodArray = superClass.getDeclaredMethods();
if (null != superClassDeclaredMethodArray) {
for (Method superClassDeclaredMethod : superClassDeclaredMethodArray) {
final int modifier = superClassDeclaredMethod.getModifiers();
// 私有方法可以过滤掉
if (Modifier.isPrivate(modifier)) {
continue;
}
// public & protected 这两种情况是可以通过继承可见
// 所以放行
else if (Modifier.isPublic(modifier)
|| Modifier.isProtected(modifier)) {
methodSet.add(superClassDeclaredMethod);
}
// 剩下的情况只剩下默认, 默认的范围需要同包才能生效
else if (null != clazz
&& null != superClassDeclaredMethod
&& null != superClassDeclaredMethod.getDeclaringClass()
&& GaCheckUtils.isEquals(clazz.getPackage(), superClassDeclaredMethod.getDeclaringClass().getPackage())) {
methodSet.add(superClassDeclaredMethod);
}
}
}
}
return methodSet;
}
/*
* 移除来自{@link java.lang.Object}的方法
*/
private Collection<GaMethod> removeObjectMethods(final Collection<GaMethod> gaMethods) {
final Iterator<GaMethod> gaMethodIt = gaMethods.iterator();
while (gaMethodIt.hasNext()) {
final GaMethod gaMethod = gaMethodIt.next();
if (GaCheckUtils.isEquals(gaMethod.getDeclaringClass(), Object.class)) {
gaMethodIt.remove();
}
}
return gaMethods;
}
@Override
public Collection<GaMethod> searchClassGaMethods(Class<?> targetClass, Matcher<GaMethod> gaMethodMatcher) {
final Set<GaMethod> gaMethodSet = new LinkedHashSet<GaMethod>();
for (final Method method : listVisualMethod(targetClass)) {
final GaMethod gaMethod = new GaMethod.MethodImpl(method);
if (gaMethodMatcher.matching(gaMethod)) {
gaMethodSet.add(gaMethod);
}
}
// 因为构造函数不能继承,所以这里就不用像方法这么复杂的做可视化处理了
for (final Constructor<?> constructor : targetClass.getDeclaredConstructors()) {
final GaMethod gaMethod = new GaMethod.ConstructorImpl(constructor);
if (gaMethodMatcher.matching(gaMethod)) {
gaMethodSet.add(gaMethod);
}
}
return removeObjectMethods(gaMethodSet);
}
}