首页 > 解决方案 > Advice.withCustomMapping().bind(...) 的目的

问题描述

我正在尝试了解 的目的和用途Advice.withCustomMapping().bind(...),看看它是否可以帮助我的用例。

阅读javadoc Advice.withCustomMapping()

允许配置自定义注释,然后将其绑定到动态计算的常量值。

这是我尝试应用此模式的用例:

public @interface Name {
}
public abstract class AgentRule {
  private final String className = getClass().getName();

  public final Advice.WithCustomMapping advice() {
    return Advice.withCustomMapping().bind(Name.class, className);
  }

  public static boolean isEnabled(final String className, final String origin) {
    ...
  }

  public abstract Iterable<? extends AgentBuilder> buildAgent(AgentBuilder builder) throws Exception;
}
public class ServletContextAgentRule extends AgentRule {
  public static boolean filterAdded = false;

  @Override
  public Iterable<? extends AgentBuilder> buildAgent(final AgentBuilder builder) throws Exception {
    return Arrays.asList(builder
      .type(named("org.eclipse.jetty.servlet.ServletContextHandler"))
      .transform(new Transformer() {
        @Override
        public Builder<?> transform(final Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
          return builder.visit(advice().to(JettyAdvice.class).on(isConstructor()));
        }})
.type(not(isInterface()).and(hasSuperType(named("javax.servlet.ServletContext"))
        // Jetty is handled separately due to the (otherwise) need for tracking state of the ServletContext
      .transform(new Transformer() {
        @Override
        public Builder<?> transform(final Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
          return builder.visit(advice().to(ServletContextAdvice.class).on(isConstructor()));
        }}));
  }

  public static class JettyAdvice {
    @Advice.OnMethodExit
    public static void exit(final @Name String className, final @Advice.Origin String origin, final @Advice.This Object thiz) {
      if (isEnabled(className, origin))
        filterAdded = JettyAgentIntercept.addFilter(thiz);
    }
  }

  public static class ServletContextAdvice {
    @Advice.OnMethodExit
    public static void exit(final @Name String className, final @Advice.Origin String origin, final @Advice.This Object thiz) {
      if (isEnabled(className, origin))
        filterAdded = ServletContextAgentIntercept.addFilter(thiz);
    }
  }
}

实际上,我要做的是将信息从实例上下文传递ServletContextAgentRule到and的静态上下文。由于建议方法应该是静态的,因此我无法找到将实例状态放入这些方法的方法(没有有效地构建某种涉及类<->实例映射的外部中继机制,从而导致在所有子类中复制+粘贴代码)。这个用例被应用于一个涉及很多规则的项目,这就是为什么我试图找出最高效和最简洁的方法来做到这一点。JettyAdviceServletContextAdviceAgentRule

当我尝试使用这种方法时Advice.withCustomMapping().bind(...),我从 ByteBuddy 那里得到一个例外,说:

java.lang.IllegalStateException: org.eclipse.jetty.servlet.ServletContextHandler() does not define an index 0

目的Advice.withCustomMapping().bind(...)仅仅是覆盖方法签名中存在的特定参数吗?我在 javadocs 中找不到提到这一点,并且在网上查看其他示例,我似乎认为我的用例应该可以工作。

标签: javabyte-buddy

解决方案


你需要

@Retention(RUNTIME)
public @interface Name { }

否则 Byte Buddy 看不到您的注释并回退到默认值,即具有相同索引的参数。


推荐阅读