Advice.withCustomMapping().bind(...) 的目的
Purpose of Advice.withCustomMapping().bind(...)
我正在尝试了解 Advice.withCustomMapping().bind(...)
的目的和用途,看看它是否可以帮助我的用例。
正在阅读 Advice.withCustomMapping()
的 javadoc:
Allows for the configuration of custom annotations that are then bound to a dynamically computed, constant value.
这是我尝试应用此模式的用例:
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
的 实例上下文 中继到 静态上下文 JettyAdvice
和 ServletContextAdvice
。由于建议方法应该是静态的,我无法找到一种方法将实例状态获取到这些方法中(没有有效地构建某种涉及 class<-> 实例映射的外部中继机制,导致复制+粘贴代码在 AgentRule
的所有子 class 中)。此用例正在应用于涉及 a lot of rules 的项目,这就是为什么我试图找出执行此操作的最高效和最简洁的方法。
当我用 Advice.withCustomMapping().bind(...)
尝试这种方法时,我从 ByteBuddy 得到一个异常说:
java.lang.IllegalStateException: org.eclipse.jetty.servlet.ServletContextHandler() does not define an index 0
Advice.withCustomMapping().bind(...)
的目的只是为了覆盖方法签名中存在的特定参数吗?我在 javadocs 中找不到对此的提及,并且在网上查看其他示例,我似乎认为我的用例应该有效。
你需要
@Retention(RUNTIME)
public @interface Name { }
否则 Byte Buddy 无法看到您的注释并回退到默认值,即具有相同索引的参数。
我正在尝试了解 Advice.withCustomMapping().bind(...)
的目的和用途,看看它是否可以帮助我的用例。
正在阅读 Advice.withCustomMapping()
的 javadoc:
Allows for the configuration of custom annotations that are then bound to a dynamically computed, constant value.
这是我尝试应用此模式的用例:
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
的 实例上下文 中继到 静态上下文 JettyAdvice
和 ServletContextAdvice
。由于建议方法应该是静态的,我无法找到一种方法将实例状态获取到这些方法中(没有有效地构建某种涉及 class<-> 实例映射的外部中继机制,导致复制+粘贴代码在 AgentRule
的所有子 class 中)。此用例正在应用于涉及 a lot of rules 的项目,这就是为什么我试图找出执行此操作的最高效和最简洁的方法。
当我用 Advice.withCustomMapping().bind(...)
尝试这种方法时,我从 ByteBuddy 得到一个异常说:
java.lang.IllegalStateException: org.eclipse.jetty.servlet.ServletContextHandler() does not define an index 0
Advice.withCustomMapping().bind(...)
的目的只是为了覆盖方法签名中存在的特定参数吗?我在 javadocs 中找不到对此的提及,并且在网上查看其他示例,我似乎认为我的用例应该有效。
你需要
@Retention(RUNTIME)
public @interface Name { }
否则 Byte Buddy 无法看到您的注释并回退到默认值,即具有相同索引的参数。