Java 如何动态创建两个不相关类的公共代理类?
我有两个不相关的java类(只有Java 如何动态创建两个不相关类的公共代理类?,java,code-generation,cglib,dynamic-class-loaders,Java,Code Generation,Cglib,Dynamic Class Loaders,我有两个不相关的java类(只有*.class,没有*.java),如下所示: public class Trick { public String getName() { return "Jack"; } public String trick() { ... } } 及 我想在运行时生成一种代理类,它表示两个类的并集,并将它们转发到各自的实例,如果不可能,可能会抛出。我假设这可以通过cglib完成,但我不知道从哪里开始 这就是我想做的(伪代码): 或者类似的东西。我想完全动
*.class
,没有*.java
),如下所示:
public class Trick {
public String getName() { return "Jack"; }
public String trick() { ... }
}
及
我想在运行时生成一种代理类,它表示两个类的并集,并将它们转发到各自的实例,如果不可能,可能会抛出。我假设这可以通过cglib
完成,但我不知道从哪里开始
这就是我想做的(伪代码):
或者类似的东西。我想完全动态地完成它,可能是基于cglib
?如果这是不可能的,我会在两者之间添加一个代码生成步骤?- 如果您需要两个类/接口的功能,可以使用
- 用类的接口扩展它,比如TreatInterface和TrickInterface
- 创建实现java.lang.reflect.InvocationHandler的类ProxyManager
如果您愿意使用cglib进行交易,您可以使用。我通常拒绝称之为魔术,但你看:
class Magic {
Class<?> createUnionInterface(Class<?> a, Class<?> b) {
DynamicType.Builder<?> builder = new ByteBuddy().makeInterface();
Set<MethodDescription.SignatureToken> tokens = new HashSet<>();
for (MethodDescription m : new TypeDescription.ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
tokens.add(m.asSignatureToken());
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
for (MethodDescription m : new TypeDescription.ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
if (!tokens.contains(m.asSignatureToken())) {
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
}
return builder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
Object createProxy(Class<?> m, final Object delegate) throws Exception {
return new ByteBuddy()
.subclass(m)
.method(new ElementMatcher<MethodDescription>() {
@Override
public boolean matches(MethodDescription target) {
for (Method method : delegate.getClass()
.getDeclaredMethods()) {
if (new MethodDescription.ForLoadedMethod(method)
.asSignatureToken()
.equals(target.asSignatureToken())) {
return true;
}
}
return false;
}
}).intercept(MethodDelegation.to(delegate))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
类魔法{
类接口(a类、b类){
DynamicType.Builder=newbyteBuddy().makeInterface();
Set tokens=new HashSet();
for(MethodDescription m:新类型说明。ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual()){
添加(m.asSignatureToken());
builder=builder.defineMethod(m.getName(),
m、 getReturnType(),
m、 getModifiers())。不带代码();
}
for(MethodDescription m:新类型描述。ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual()){
如果(!tokens.contains(m.asSignatureToken())){
builder=builder.defineMethod(m.getName(),
m、 getReturnType(),
m、 getModifiers())。不带代码();
}
}
returnbuilder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
对象createProxy(类m,最终对象委托)引发异常{
返回新的ByteBuddy()
.第(m)款
.method(新的ElementMatcher(){
@凌驾
公共布尔匹配(MethodDescription目标){
对于(方法:delegate.getClass()
.getDeclaredMethods()){
if(新方法说明.ForLoadedMethod(方法)
.asSignatureToken()
.equals(target.asSignatureToken()){
返回true;
}
}
返回false;
}
}).intercept(方法委派给(委派))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
请注意,您不能在编译时引用运行时生成的类型。但是,这是运行时代码生成的给定约束
Magic magic = new Magic();
Class<?> trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
Trick trick = new Trick();
Object proxyA = magic.createProxy(trickOrTreat, trick);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyA));
Treat treat = new Treat();
Object proxyB = magic.createProxy(trickOrTreat, treat);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyB));
Magic Magic=new Magic();
类trickOrTreat=magic.createUnionInterface(Trick.Class,Treat.Class);
技巧=新技巧();
objectproxya=magic.createProxy(trickOrTreat,trick);
System.out.println(“技巧名称:”+trickOrTreat.getDeclaredMethod(“getName”).invoke(proxyA));
治疗=新治疗();
objectproxyb=magic.createProxy(trickOrTreat,treat);
System.out.println(“技巧名称:”+trickOrTreat.getDeclaredMethod(“getName”).invoke(proxyB));
您可以通过在运行之前生成TrickOrTreat
类来克服这一问题,这样您就可以在运行时引用该类型
至于建议的联合类型方法,这将要求您至少有一个类作为接口类型,因为Java不支持多重继承。我不明白,为什么要动态地这样做?由于您必须静态地编写TrickOrTreat接口。。。作为指导原则,cglib只能在无法知道运行时将拥有的对象类型时使用,即仅用于库代码。@DLevant Hrm,是的。因为我想在我的客户机源代码中编写
TrickOrTreat
,所以我必须事先将它作为一个类。你是对的,否则就没有意义了。所以我必须先通过一个代码生成器。好的,那么cglib
不是正确的工具,但是什么是正确的工具呢javaparser
有*.java
作为输入,我没有。所以怎么走?我还是不明白你为什么不直接手写你需要的东西…这真是太神奇了。我不知道。我会读的。我可以这样做,是的,但你的建议远不能解决问题。它只适用于接口(或一个接口和一个类)。尽管使用了&
-符号,“计算”接口的并集(而不是交集)——因为它只希望两个接口都由TT
提供。这不完全是我需要的,但是非常接近而且绝对有用。我没有时间完全调查你的问题。在我的回答中有一个编辑-这是一个方向,我会去获取您所寻求的功能。在这个示例中,我在createProxy
中的.load(…)
行上得到一个NoClassDefFoundError。有什么建议吗?
public <TT extends Trick & Treat> void process(TT thing){
//...
}
public interface MyProxyHandler {}
public abstract class ProxyManager<T extends MyProxyHandler> implements InvocationHandler {
protected static String LOCK_OBJECT = new String("LOCK");
protected T proxyHandler;
protected List<T> handlers = new ArrayList<>();
@SuppressWarnings("unchecked")
public ProxyManager(Class<T> _clazz) {
proxyHandler = (T) Proxy.newProxyInstance(_clazz.getClassLoader(), new Class[]{_clazz}, this);
}
public T getProxy() {
return proxyHandler;
}
public List<T> getHandlers() {
return handlers;
}
public void setHandlers(List<T> handlers) {
this.handlers = handlers;
}
public boolean registerHandler(T handler) {
synchronized (LOCK_OBJECT) {
boolean add = true;
for (T item : this.handlers) {
if (item.getClass().equals(handler.getClass())) {
add = false;
}
}
if (add)
this.handlers.add(handler);
return add;
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String result = "";
for (MyProxyHandler handler : getHandlers()) {
try {
//I recommend that methods returns some enum like HANDLED/NOTHANDLED
result = (String) method.invoke(handler, args);
if (result.equals("Some flag"))
break;
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
return result;
}
}
public class TreatTrickProxyManager<T extends TreatInterface & TreatInterface> extends ProxyManager<T> {
public TreatTrickProxyManager(Class<T> _clazz) {
super(_clazz);
}
}
public void retrieveSomeData(){
((TreatTrickProxyManager)getTreatTrickProxyManager().getProxy()).someMethodInvocation()
}
class Magic {
Class<?> createUnionInterface(Class<?> a, Class<?> b) {
DynamicType.Builder<?> builder = new ByteBuddy().makeInterface();
Set<MethodDescription.SignatureToken> tokens = new HashSet<>();
for (MethodDescription m : new TypeDescription.ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
tokens.add(m.asSignatureToken());
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
for (MethodDescription m : new TypeDescription.ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
if (!tokens.contains(m.asSignatureToken())) {
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
}
return builder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
Object createProxy(Class<?> m, final Object delegate) throws Exception {
return new ByteBuddy()
.subclass(m)
.method(new ElementMatcher<MethodDescription>() {
@Override
public boolean matches(MethodDescription target) {
for (Method method : delegate.getClass()
.getDeclaredMethods()) {
if (new MethodDescription.ForLoadedMethod(method)
.asSignatureToken()
.equals(target.asSignatureToken())) {
return true;
}
}
return false;
}
}).intercept(MethodDelegation.to(delegate))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
Magic magic = new Magic();
Class<?> trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
Trick trick = new Trick();
Object proxyA = magic.createProxy(trickOrTreat, trick);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyA));
Treat treat = new Treat();
Object proxyB = magic.createProxy(trickOrTreat, treat);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyB));