繁体   English   中英

在运行时在java类中添加默认构造函数

[英]Add default constructor in a java class in runtime

我正在编写一个库,我需要为某些对象创建代理。 由于有些类没有实现任何接口,所以我决定使用 CGLIB 来创建代理而不是 JDK 代理。 但是我遇到了一些类没有默认构造函数并且 CGLIB 无法为这些类型创建代理的情况,即 CGLIB 抛出异常并带有消息:超类没有空构造函数但没有给出任何参数。 我如何解决这个问题,有没有办法使用 cglib/asm 或其他工具在运行时添加默认构造函数? 谢谢。

使用http://objenesis.org/ 它的典型用例之一正好解决了您的问题:

代理、AOP 库和模拟对象 - 可以对类进行子类化,而无需担心 super() 构造函数。

我只是将评论中提供的博客文章中的解决方案复制并粘贴到另一个答案中以保留它。 它结合了 Objenesis 和 CGLIB,它确实有效。

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.objenesis.ObjenesisHelper;

public class ProxyPlayground {

    public static void main(final String[] args) {

        final MethodInterceptor hashCodeAlwaysNull = new MethodInterceptor() {

            @Override
            public Object intercept(final Object object, final Method method,
                    final Object[] args, final MethodProxy methodProxy)
                    throws Throwable {
                if ("hashCode".equals(method.getName())) {
                    return 0;
                }
                return methodProxy.invokeSuper(object, args);
            }
        };
        final Foo proxy = createProxy(Foo.class, hashCodeAlwaysNull);
        System.out.println(proxy.hashCode()); // prints 0

    }

    @SuppressWarnings("unchecked")
    private static <T> T createProxy(final Class<Foo> classToMock,
            final MethodInterceptor interceptor) {
        final Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(classToMock);
        enhancer.setCallbackType(interceptor.getClass());

        final Class<?> proxyClass = enhancer.createClass();
        Enhancer.registerCallbacks(proxyClass, new Callback[] { interceptor });
        return (T) ObjenesisHelper.newInstance(proxyClass);
    }
}

这是可能的,下面是来自 objenesis 的代码参考。

ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Constructor<?> constructor = reflectionFactory.newConstructorForSerialization(YourObject.class, Object.class.getConstructor((Class[]) null));
Object instance = constructor.newInstance();

您假设表示为字节码的内容无法完成,因为它会被 JVM 的验证程序拒绝。 正如另一个答案所指出的,您应该考虑使用诸如 Objenesis 之类的库。 但是,请注意,在引入 Jigsaw 项目后,Objenesis 使用了 JVM 内部 API,而 Java 9 将不再可能使用这些 API。

出于这个原因,您可能更愿意以不同的方式处理这个问题。 Cglib 只是复制超类的所有构造函数。 您想调用任何您知道它没有副作用的构造函数。 只需为基元传递null值或0值。 只要您拦截所有方法,对象状态无论如何都无关紧要,因为从来没有调用过任何真正的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM