繁体   English   中英

如何使用ByteBuddy创建没有公共构造函数的类的动态代理

How to create dynamic proxy of class with no public constructor using ByteBuddy

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我想创建一个类Sample的动态代理,该类具有两个没有公共构造函数的类,它不起作用并给出错误。 但是,如果我将构造函数设置为Public,则可以正常工作。 字节伙伴中是否有可能实现这一目标?

还有可能使addToList(..)方法成为非公共方法吗?

样例代码:

public class Sample {
    private String name;
    private String college;
    private String id;
    private List<String> fieldList = new LinkedList<>();

     Sample() {
        //some code
        System.out.println("No arg constructor invoked");
    }

     Sample(String id) {
        this();
        this.id = id;
    }

    public String getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        System.out.println("Setting name: "+ name);
        this.name = name;
    }


    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        System.out.println("Setting college: "+college);
        this.college = college;
    }

    public void addToList(String fieldName){
        fieldList.add(fieldName);
    }

    public List<String> getFieldList() {
        return Collections.unmodifiableList(fieldList);
    }

    public static Sample getProxyObject(String id) {
        Sample proxyObj = null;
        try {
            Class<? extends Sample> dynamicType = new ByteBuddy()
                    .subclass(Sample.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS )
                    .method(ElementMatchers.nameStartsWith("set"))
                    .intercept(MethodDelegation.to(new GreetingInterceptor()))
                    .make()
                    .load(Sample.class.getClassLoader())
                    .getLoaded();
            proxyObj = dynamicType.getConstructor(String.class).newInstance(id);
        } catch (Exception ex){
            ex.printStackTrace();
        }
        return proxyObj;
    }

    public static Sample getProxyObject() {
        Sample proxyObj = null;
        try {
             proxyObj = new ByteBuddy()
                    .subclass(Sample.class)
                    .method(ElementMatchers.nameStartsWith("setName"))
                    .intercept(MethodDelegation.to(new GreetingInterceptor()))
                    .make()
                    .load(Sample.class.getClassLoader())
                    .getLoaded().newInstance();
        } catch (Exception ex){
            ex.printStackTrace();
        }
        return proxyObj;
    }

    public static class GreetingInterceptor {
        public void abc(@SuperCall Callable<Void> zuper, @Origin Method method, @Super Sample parentObj, @This Object myself, @AllArguments Object[] args) {
            try {

                parentObj.addToList(method.getName());
                zuper.call();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }
}

要测试的主要课程:

public class SampleMain {
public static void main(String[] args) {
    System.out.println("===Scenario 1=====");
    Sample proxyObject = Sample.getProxyObject();
    proxyObject.setName("John Doe");

    System.out.println("===Scenario 2=====");
    proxyObject.getFieldList().stream().forEach(System.out::println);
    Sample proxyObject1 = Sample.getProxyObject("id123");
    proxyObject1.setName("John Doe");
    proxyObject1.setCollege("MIT");

    System.out.println("Id is: "+proxyObject1.getId());

    proxyObject1.getFieldList().stream().forEach(System.out::println);
} 
}

错误跟踪:

===方案1 =====

Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.algorithm.Sample.<init>()V from class com.algorithm.Sample$ByteBuddy$J74XiIU8
    at com.algorithm.Sample$ByteBuddy$J74XiIU8.<init>(Unknown Source)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at com.algorithm.Sample.getProxyObject(Sample.java:88)
    at com.algorithm.SampleMain.main(SampleMain.java:6)
2 个回复

如果protected构造函数没问题,则:

  1. Sample()更改为protected Sample()以使方案1起作用:这使ByteBuddy产生的子类可以访问no-args构造函数。
  2. Sample(String id)更改为protected Sample(String id) ,然后在getProxyObject(String id)更改

     proxyObj = dynamicType.getConstructor(String.class).newInstance(id); 

     Constructor<? extends Sample> ctor = dynamicType.getDeclaredConstructor(String.class); ctor.setAccessible(true); proxyObj = ctor.newInstance(id); 

    这使方案2起作用。 ConstructorStrategy.Default.IMITATE_SUPER_CLASS在子类中生成相同的受保护构造函数,因此您需要使用getDeclaredConstructor()来获取它,然后使其可访问。

您还可以将addToList(..)受保护的,因为GreetingInterceptor可以访问它,因此可以正常工作。

请注意,只有在同一运行时包中定义了程序包私有构造函数,该类才对类可见。 默认情况下,Byte Buddy在加载类而不指定ClassLoadingStrategy时会创建一个新的类加载ClassLoadingStrategy 如果一个软件包的名称相同,但未由同一类加载器加载,则运行时软件包将有所不​​同。

我假设通过指定:

.load(Sample.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)

尽管其他答案中提到的反射性访问已损坏,但您的代理仍可以按预期工作。 但是请注意,此策略使用了不安全的API,该API在以后的JVM版本中可能不再起作用。

1 使用ByteBuddy的没有空构造函数的类的代理

有没有一种方法可以使用ByteBuddy为没有空构造函数的类创建代理? 这个想法是为给定的具体类型创建代理,然后将所有方法重定向到处理程序。 此测试展示了为没有空构造函数的类创建代理的场景,并且抛出java.lang.NoSuchMethodException 实体: ...

3 如何使用Byte Buddy创建默认构造函数

我想拦截我的一个类上的一些方法调用,但这些类没有默认的构造函数。 鉴于以下类,我如何设置Byte Buddy也创建一个公共无参数构造函数来创建生成的类? 编辑:具体的用例是简化单元测试设置。 目前我们总是要写这样的东西: 我认为在@Before方法中创建代理会自动为您设 ...

4 ByteBuddy使用构造函数创建枚举

使用ByteBuddy,我如何用这样的构造函数创建枚举: 我尝试了这段代码,它给了我错误。 这是错误,它发生在enumClass.getDeclaredConstructors()中 ...

5 如何使用 ByteBuddy 代理处理构造函数抛出的异常?

我正在尝试使用ByteBuddy (v1.7.9) java 代理记录在方法和构造函数中抛出的每个调用、返回的对象和异常,而不干扰检测代码的正常功能。 我当前的代理实例是 我从最简单的“顾问”开始, 但是,当我运行该程序时,我从 bytebuddy 收到一个异常: 那么,我应该怎么做才 ...

8 ByteBuddy 调用生成类的构造函数

我正在尝试在生成的类中生成这样的方法 我正在为 API 苦苦挣扎,我目前所在的位置 我相信我需要FieldAccessor.ofField和MethodCall.construct但是我正在努力为要生成的类的构造函数提供MethodDescription 。 ...

暂无
暂无

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

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