我用AspectJ编写了一个方法,并对其应用了一个建议。在advice逻辑中,我希望访问该方法的所有注释参数。我这样做是为了过滤我正在寻找的特定注释。
问题是,在我调用的
后,我收到了一个getAnNotatedParameterTypes()
java.lang.reflectAnNotatedType
数组。我可以在那里找到我正在寻找的预期参数。但是,当我想访问该参数的注释类型时——因为我想按其类型过滤——没有注释存在。
我希望它会出现-因为它说它是一个带注释的类型-那么注释在哪里:D
这是要查看的代码
@Around("@annotation(com.mystuff.client.annotation.Query)")
public void doStuff(ProceedingJoinPoint joinPoint) {
Method[] methods = joinPoint.getSignature().getDeclaringType().getMethods();
Optional<Method> first = Arrays.stream(methods).findFirst();
if (first.isPresent()) {
Method method = first.get();
AnnotatedType[] annotatedParameterTypes = method.getAnnotatedParameterTypes();
AnnotatedType annotatedParameterType = annotatedParameterTypes[0];
LOG.info(Arrays.toString(annotatedParameterType.getAnnotations()));
}
}
日志输出
2020-10-10 22:17:11.821信息215068---[测试工作者]com。迈斯塔夫。方面:[]
我的批注
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query{
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Response {
}
整个魔法测试的班级
@Component
class TestCandidate {
@Query
public TestResponseModel useData(@Response TestResponseModel model){
return model;
}
}
您的方面代码有几个问题:
>
您的目标方法返回一些东西,但通知方法的返回类型是val
,即它永远不会隐式匹配除val
方法之外的任何东西。但是,它肯定不会匹配您的示例useData(...)
方法。因此,如果您想限制返回类型,您需要创建返回类型Object
或TestResseModel
。
周围的通知从不调用连接点。继续(),即不会执行目标方法,而是跳过该方法。
如果您只想记录响应参数,而不想在继续之前/之后修改任何参数或结果,实际上一个简单的建议就足够了。不过,我将在我的示例代码中保留您的建议,以防您想对这些参数做一些特殊的处理。
建议方法中的前两行执行以下操作:
这没有多大意义。为什么你总是用第一种方法而不管它是什么方法?您想识别被通知截获的目标方法上的参数注释,不是吗?可能第一个方法的第一个参数没有任何注释,这就是为什么没有记录任何注释。实际上,幸运的是,第一个方法有一个参数,否则,annotatedParameterTypes[0]将产生“数组索引越界”异常。
这是你想要做的。顺便说一句,我在这里介绍一个完整的MCVE,因为你应该在第一个地方做。我使用的是纯AspectJ,而不是Spring AOP,因此我不使用任何组件注释。但是,如果您是Spring用户,您可以只制作方面和目标类Spring组件/bean,以使其工作。
注释虚拟助手类:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Query {}
package de.scrum_master.app;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(PARAMETER)
public @interface Response {}
package de.scrum_master.app;
public class TestResponseModel {}
具有正/负测试用例的目标类驱动程序应用程序
package de.scrum_master.app;
class TestCandidate {
@Query
public TestResponseModel useData(@Response TestResponseModel model) {
return model;
}
@Query
public TestResponseModel dummyOne(TestResponseModel model) {
return model;
}
public TestResponseModel dummyTwo(@Response TestResponseModel model) {
return model;
}
@Query
public TestResponseModel multipleResponses(@Response TestResponseModel model, @Response String anotherResponse, int i) {
return model;
}
public static void main(String[] args) {
TestCandidate candidate = new TestCandidate();
TestResponseModel model = new TestResponseModel();
candidate.dummyOne(model);
candidate.dummyTwo(model);
candidate.useData(model);
candidate.multipleResponses(model, "foo", 11);
}
}
期望为方法useData
和multiple响应
触发建议,并且后一种方法中的多个@响应
参数的特殊情况也由方面正确处理。
@周围
方面变体:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import de.scrum_master.app.Response;
@Aspect
public class QueryResponseInterceptor {
@Around(
"@annotation(de.scrum_master.app.Query) && " +
"execution(* *(.., @de.scrum_master.app.Response (*), ..))"
)
public Object doStuff(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
for (int i = 0; i < args.length; i++) {
for (Annotation annotation : annotationMatrix[i]) {
if (annotation.annotationType().equals(Response.class)) {
System.out.println(" " + args[i]);
break;
}
}
}
return joinPoint.proceed();
}
}
请注意执行()
切入点如何限制带有@响应
注释的参数的方法,无论它们可能出现在参数列表中的任何位置。
方面变量之前:
如果您只想记录带注释的参数,一个更简单的变体是在这方面,在建议之前加上一个@和更少的样板文件:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import de.scrum_master.app.Response;
@Aspect
public class QueryResponseInterceptor {
@Before(
"@annotation(de.scrum_master.app.Query) && " +
"execution(* *(.., @de.scrum_master.app.Response (*), ..))"
)
public void doStuff(JoinPoint joinPoint) {
System.out.println(joinPoint);
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
for (int i = 0; i < args.length; i++) {
for (Annotation annotation : annotationMatrix[i]) {
if (annotation.annotationType().equals(Response.class)) {
System.out.println(" " + args[i]);
break;
}
}
}
}
}
看见现在,您真的可以使用void返回类型,不需要调用procedue()
,因此也不需要抛出抛出。
控制台日志:
对于这两个方面变体,控制台日志是相同的。
execution(TestResponseModel de.scrum_master.app.TestCandidate.useData(TestResponseModel))
de.scrum_master.app.TestResponseModel@71318ec4
execution(TestResponseModel de.scrum_master.app.TestCandidate.multipleResponses(TestResponseModel, String, int))
de.scrum_master.app.TestResponseModel@71318ec4
foo
问题内容: 这是一个测试类: 这是我的输出: 我缺少通过反射使注释可见的什么? 我是否仅需要检查它们的存在就需要注释处理器? 问题答案: 为了在运行时访问注释,它需要具有运行时的保留策略。 否则,注释将被丢弃,并且JVM无法识别它们。 有关更多信息,请参见此处。
我正在尝试使用简单的自定义@NotNull注释对我的方法执行空检查,即我将方法声明为,当有人调用此方法并将空值作为'name'参数传递时,会引发异常。 我已经使用aspectj实现了一个简单方面。这个解决方案对我来说很有效。一个例外是内部类的构造函数。在这种情况下,由于java内部的异常,方面崩溃。郎。反思。参数: 简化的实施: 方面: 注释: 测试等级: 据我所知,这是由java将封闭的类对象作
我在MyController类下有一个函数: 我在我的项目中设置了AspectJ,以便在这两个addPerson(…)时运行AOP逻辑上述方法称为: 我的问题在上述代码注释中提到。我想知道如何访问AOP函数中用RequestBody注释的参数?我不想检查参数类型或名称,但想知道如何通过检查注释来访问参数。有可能吗?
问题内容: 我需要知道如何在运行时阅读Javadoc注释(可能是通过反射吗?) 说我有以下功能: 在运行时,我可以通过反射获得有关此函数的更多信息。但是无法阅读注释。所以问题是,如何在运行时阅读此 javadoc 注释。 问题答案: 考虑使用注释而不是Javadoc并编写注释处理器。
问题内容: 是否可以通过注释处理器访问带有注释的元素? 是否可以通过注释处理器访问带注释的类型边界? 高度赞赏我错过的相关文档的链接。 内容: 注释: 一个示例类: 处理器: 在classpath 上使用编译以上内容将显示消息,但永远不会调用该方法。当方法参数中存在注释时,使用注释向处理器添加另一个注释可以正常工作。如果方法参数带有注释,则过程将再次忽略该元素。 问题答案: 该注释是有点棘手,因为
我是Spring Security的新手。我看过很多关于如何通过外部属性文件的注释注入值的文章。我尝试了很多方法,但最终都是用java。lang.IllegalArgumentException:无法解析占位符“val.id”异常。 你能给我一些提示如何处理这个例外吗? 我的java类如下所示: 我的属性文件名为val.properties,位于WEB-INF下,其内容为val.id=xyz 我将