当前位置: 首页 > 知识库问答 >
问题:

使用字节伙伴拦截器初始化构造函数中的字段

姜煌
2023-03-14

如何在构造函数拦截器中启动对象字段?

我在Buddy代码中创建了一个字节构造函数。

Class<?> klass = new ByteBuddy()
            .subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)

            .defineProperty("origin", CoreObject.class, true)
            .defineProperty("variableNamedField", Map.class, true)

            .defineConstructor(Visibility.PUBLIC)
            .withParameters(CoreObject.class)
            .intercept(
                    // Invoke Objects default constructor explicitly
                    MethodCall.invoke(Object.class.getConstructor())
                            .andThen(FieldAccessor.ofField("origin").setsArgumentAt(0))
                            .andThen(FieldAccessor.ofField("variableNamedField").setsValue(new HashMap<>()))
                            .andThen(MethodDelegation.to(new FillMapInterceptor("variableNamedField")))

                    //
                    // I have to fill the map.
                    // Something like this:
                    //
                    // variableNamedField.put("first", new FirstHandler(origin));
                    // variableNamedField.put("second", new SecondHandler(origin));
                    //

            )
            .make()
            .load(CoreObject.class.getClassLoader())
            .getLoaded();

构造函数首先将参数保存到私有字段。然后它创建集合。然后它调用以下拦截器来填充该集合。

class FillMapInterceptor {

    private final String mapField;

    public FillMapInterceptor(String mapField) {
        this.mapField = mapField;
    }

    public void construct(@FieldValue("variableNamedField") Map<String, Handler> map, @FieldValue("origin") CoreObject coreObject){
        map.put("first", new FirstHandler(coreObject));
        map.put("second", new SecondHandler(coreObject));
    }
}

最好在拦截器中实例化variableNamedField字段,因为事实证明,每次创建新的类实例时,variableNamedField字段都是用相同的HashMap对象实例化的。但是,我只能通过@FieldValue注释将现有字段传递给拦截器。但我似乎无法在拦截器中为字段分配新变量

  1. 如何在构造函数拦截器中启动类字段?我只能在拦截器中使用@FieldValue pess现有字段值。
  2. 如何使字段名任意?像@FieldValue这样的注释需要常量参数(例如字段名)。也许,我可以以某种方式将该字段从定义属性方法结果中获取并将其传递给拦截器或用作拦截器的字段?
  3. 如何将构造函数参数直接传递给拦截器?我不喜欢先启动字段,然后通过@FieldValue注释将字段传递给拦截器的方式。

共有1个答案

东郭宏深
2023-03-14

最简单的方法是使用Advice类定义构造函数。advice类允许您使用稍后内联的模板定义代码。你可以使用@Advice。OnMethodExit在本例中,在上述实现之后添加代码,然后环绕上面已经创建的代码:

Advice.to(YourAdvice.class).wrap(...)

您可以在javadoc中找到有关定义建议的所有信息,基本上,您可以将上面的代码复制粘贴到一个静态方法中以内联它:

class YourAdvice {
  @Advice.OnMethodExit
  static void exit(@Advice.FieldValue("variableNamedField") 
        Map<Object, Object> variableNamedField) {
    variableNamedField.put("first", new FirstHandler(origin));
    variableNamedField.put("second", new SecondHandler(origin));
  }
}

 类似资料:
  • 我正在尝试用Byte Buddy拦截构造函数调用,这是我的示例代码: 我看到了这个相关的问题,但是,我得到了一个冲突异常(就好像构造函数被定义了两次)。

  • 我必须将注释XmlElementWrapper和XmlElement添加到列表类型的字段,但是这些注释需要名称。我想把属性名设置为字段名。我愿意: 这是我的拦截器: 这是目标类的一部分: 但我有一个例外: [public static void factory.framework.SetterListInterceptor.getter(java.lang.reflect.Method)、publ

  • 我试图通过java应用程序中的所有外部调用传递监视/跟踪信息。为了使其透明,我尝试使用byte-buddy,但在使其工作时遇到了一些困难。 为了跟踪每个传入的(http)请求,我截获了HttpServlet。service(),从HttpServletRequest中提取令牌头,并将其放在名为TokenHolder的类中的静态ThreadLocal中。 为了跟踪每个传出(超文本传输协议)请求,我拦

  • 问题内容: 如果未将ArrayList初始化为字段,则将项目添加到ArrayList时出现NullPointerException。谁能解释为什么? 当我将ArrayList初始化为字段时起作用: 当我将ArrayList声明为字段然后在Class构造函数中对其进行初始化时,它不起作用: 问题答案: 因为构造函数中的版本正在创建一个新变量,而该变量恰好与您的成员字段名称相同,而成员字段仍未设置。这

  • 我在使用Byte Buddy时遇到了一个简单的问题,下面是我的代码: 我希望工作并将调用转发到受人尊敬的拦截器实例,但是我得到这个异常: 最奇怪的部分在异常消息的最后: 我做错了什么?

  • 这是一个关于java中子类的非常基本的问题,我还是不明白…… 假设我有一个超类,它有三个字段,并且只有默认的构造函数: 我想添加一个字段x。我无法更改,所以我创建了一个子类: 我现在想从现有的对象生成object: 这样我仍然可以访问,等。 如果不在子类的构造函数中“手动”分配所有这些字段,我如何才能最好地做到这一点?