Java:在运行时创建类型的新实现?

发布于 2024-08-08 20:15:39 字数 1056 浏览 4 评论 0原文

所以,我意识到这个问题的答案可能是“这很难”,但是:

我有一个奇怪的想法,并且想知道是否可以在 Java 中创建一个如下方法:

<T> T wrapInterface (Class<T> interfaceClass, T wrappedObject) {
  if (mClass.isInterface()) {
    //create a new implementation of interfaceClass that, in each method, 
    //does some action before delegating to wrappedObject
    return thatImplementation;
  }
}

所以基本上,如果我的接口 Foo 定义了一个方法 foo (),我希望这个方法创建一个看起来像这样的新类,使用wrappedObject作为构造函数参数创建该类的实例,然后返回它:

public class GeneratedClass implements Foo {
  private Foo wrapped;
  public GeneratedClass (Foo wrapped) {
    this.wrapped = wrapped;
  }
  @Override
  public void foo () {
    System.out.println("Calling Foo.foo() on wrapped object " + 
                        wrapped.toString());
    wrapped.foo();
  }
}

我正在考虑的应用程序比仅仅记录日志更复杂调用,但日志记录足以实现这个想法。我想用大量的接口类型来完成此操作,这就是为什么我不会只手动编写所有生成的类。

如果解决方案不需要额外的语言功能(引入 AspectJ 或类似的东西),则可以获得加分;如果仅使用标准 JDK 库就可以做到这一点,则可以获得双倍加分。

(我不需要一个精确的、可编译的答案;只需一个指向正确的工具/库/等集的指针,让我可以做到这一点。)

谢谢!

So, I realize the answer to this is probably "it's hard", but:

I've got a weird idea, and was wondering if it's possible in Java to create a method like:

<T> T wrapInterface (Class<T> interfaceClass, T wrappedObject) {
  if (mClass.isInterface()) {
    //create a new implementation of interfaceClass that, in each method, 
    //does some action before delegating to wrappedObject
    return thatImplementation;
  }
}

So basically, if my interface Foo defined a method foo(), I'd want this method to create a new class that looked about like this, created an instance of that class with wrappedObject as the constructor parameter, and then returned it:

public class GeneratedClass implements Foo {
  private Foo wrapped;
  public GeneratedClass (Foo wrapped) {
    this.wrapped = wrapped;
  }
  @Override
  public void foo () {
    System.out.println("Calling Foo.foo() on wrapped object " + 
                        wrapped.toString());
    wrapped.foo();
  }
}

The application I'm considering is more complicated than just logging the call, but logging is sufficient for the idea. I'd like to do this with a large number of interface types, which is why I wouldn't just write all the GeneratedClasses by hand.

Bonus points for a solution that doesn't require extra-linguistic features (bringing in AspectJ or something along those lines), and double-bonus-points if this is possible with just the standard JDK libraries.

(I don't need a precise, compilable answer; just a pointer to the right sets of tools/libraries/etc that would let me do this.)

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

寄与心 2024-08-15 20:15:39

这是一个非常简单的实现(对于您想要做的事情可能不够好,但需要进行一些调整...主要要注意的是类加载器问题,然后可能存在一些验证问题等)我使用该代码用于测试目的,因此它不完全是生产质量的东西。

    @SuppressWarnings("unchecked")
    public static <T> T generateProxy(Object realObject, Class<?>... interfaces) {
        return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
    }


    private static class SimpleInvocationHandler implements InvocationHandler {
        private Object invokee;

        public SimpleInvocationHandler(Object invokee) {
            this.invokee = invokee;
        }

        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            try {
                return method.invoke(invokee, args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
        }
    }

Here is a very simplistic implementation (not good enough likely for what you want to do, but with some tweaking ... The main thing to look at would be class loader issues, then there might be some validation issues, etc.) I use the code for testing purposes, so it isn't exactly production quality stuff.

    @SuppressWarnings("unchecked")
    public static <T> T generateProxy(Object realObject, Class<?>... interfaces) {
        return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
    }


    private static class SimpleInvocationHandler implements InvocationHandler {
        private Object invokee;

        public SimpleInvocationHandler(Object invokee) {
            this.invokee = invokee;
        }

        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            try {
                return method.invoke(invokee, args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
        }
    }
海风掠过北极光 2024-08-15 20:15:39

您需要的是 ASM

来自 asm-guide.pdf
2.2.3 生成类
生成类所需的唯一组件是 ClassWriter 组件。
让我们举个例子来说明这一点。考虑以下接口:

package pkg;
public interface Comparable extends Mesurable {
  int LESS = -1;
  int EQUAL = 0;
  int GREATER = 1;
  int compareTo(Object o);
}

它可以通过对 ClassVisitor 的六个方法调用来生成:

ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
    "pkg/Comparable", null, "java/lang/Object",
    new String[] { "pkg/Mesurable" });
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I",
    null, new Integer(-1)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I",
    null, new Integer(0)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I",
    null, new Integer(1)).visitEnd();
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo",
    "(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] b = cw.toByteArray();

What you need is ASM.

From asm-guide.pdf:
2.2.3 Generating classes
The only required component to generate a class is the ClassWriter component.
Let’s take an example to illustrate this. Consider the following interface:

package pkg;
public interface Comparable extends Mesurable {
  int LESS = -1;
  int EQUAL = 0;
  int GREATER = 1;
  int compareTo(Object o);
}

It can be generated with six method calls to a ClassVisitor:

ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
    "pkg/Comparable", null, "java/lang/Object",
    new String[] { "pkg/Mesurable" });
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I",
    null, new Integer(-1)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I",
    null, new Integer(0)).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I",
    null, new Integer(1)).visitEnd();
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo",
    "(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] b = cw.toByteArray();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文