org.nutz.aop.AbstractClassAgent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nutz Show documentation
Show all versions of nutz Show documentation
Nutz, which is a collections of lightweight frameworks, each of them can be used independently
package org.nutz.aop;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
/**
* 提供ClassAgent的基础实现,拦截不可能插入Aop代码的Class
*
* 传入的Class对象需要满足的条件
* 不能是final或者abstract的
* 必须有非private的构造函数
*
* 被拦截的方法需要满足的条件 不能是final或者abstract的 不是private的
*
* @author wendal([email protected])
*
*/
public abstract class AbstractClassAgent implements ClassAgent {
private ArrayList pairs = new ArrayList();
public String id;
public ClassAgent addInterceptor(MethodMatcher matcher, MethodInterceptor listener) {
if (null != listener)
pairs.add(new Pair(matcher, listener));
return this;
}
public Class define(ClassDefiner cd, Class klass) {
if (klass.getName().endsWith(CLASSNAME_SUFFIX))
return klass;
String newName = klass.getName() + (id == null ? "" : "$" + id) + CLASSNAME_SUFFIX;
return define(cd, klass, newName);
}
public Class define(ClassDefiner cd, Class klass, String newName) {
Class newClass = try2Load(newName, klass.getClassLoader());
if (newClass != null)
return newClass;
if (!checkClass(klass))
return klass;
Pair2[] pair2s = findMatchedMethod(klass);
if (pair2s.length == 0)
return klass;
Constructor[] constructors = getEffectiveConstructors(klass);
newClass = generate(cd, pair2s, newName, klass, constructors);
return newClass;
}
protected abstract Class generate( ClassDefiner cd,
Pair2[] pair2s,
String newName,
Class klass,
Constructor[] constructors);
@SuppressWarnings("unchecked")
protected Constructor[] getEffectiveConstructors(Class klass) {
Constructor[] constructors = (Constructor[]) klass.getDeclaredConstructors();
List> cList = new ArrayList>();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
if (Modifier.isPrivate(constructor.getModifiers()))
continue;
cList.add(constructor);
}
if (cList.isEmpty())
throw Lang.makeThrow("No non-private constructor founded,unable to create sub-class!");
return cList.toArray(new Constructor[cList.size()]);
}
protected boolean checkClass(Class klass) {
if (klass == null)
return false;
String klassName = klass.getName();
if (klassName.endsWith(CLASSNAME_SUFFIX))
return false;
if (klass.isInterface()
|| klass.isArray()
|| klass.isEnum()
|| klass.isPrimitive()
|| klass.isMemberClass()
|| klass.isAnnotation()
|| klass.isAnonymousClass())
throw Lang.makeThrow("%s is NOT a Top-Class!Creation FAIL!", klassName);
if (Modifier.isFinal(klass.getModifiers()) || Modifier.isAbstract(klass.getModifiers()))
throw Lang.makeThrow("%s is final or abstract!Creation FAIL!", klassName);
return true;
}
@SuppressWarnings("unchecked")
protected Class try2Load(String newName, ClassLoader loader) {
try {
if (loader == null)
return (Class) getClass().getClassLoader().loadClass(newName);
return (Class) loader.loadClass(newName);
}
catch (ClassNotFoundException e) {
}
return null;
}
private Pair2[] findMatchedMethod(Class klass) {
Method[] all = Mirror.me(klass).getAllDeclaredMethodsWithoutTop();
List p2 = new ArrayList();
for (Method m : all) {
int mod = m.getModifiers();
if (mod == 0 || Modifier.isStatic(mod) || Modifier.isPrivate(mod)
|| Modifier.isFinal(mod)
|| Modifier.isAbstract(mod))
continue;
ArrayList mls = new ArrayList();
for (Pair p : pairs)
if (p.matcher.match(m))
mls.add(p.listener);
if (!mls.isEmpty())
p2.add(new Pair2(m, mls));
}
return p2.toArray(new Pair2[p2.size()]);
}
protected static class Pair {
MethodMatcher matcher;
MethodInterceptor listener;
Pair(MethodMatcher matcher, MethodInterceptor listener) {
this.matcher = matcher;
this.listener = listener;
}
}
protected static class Pair2 {
private Method method;
private List listeners;
Pair2(Method method, List listeners) {
this.method = method;
this.listeners = listeners;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public List getListeners() {
return listeners;
}
public void setListeners(List listeners) {
this.listeners = listeners;
}
}
}