Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何动态创建两个不相关类的公共代理类?_Java_Code Generation_Cglib_Dynamic Class Loaders - Fatal编程技术网

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完成,但我不知道从哪里开始 这就是我想做的(伪代码): 或者类似的东西。我想完全动

我有两个不相关的java类(只有
*.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));