人们经常会问AspectJ这样的问题,所以我想在以后可以轻松链接到的地方回答。
我有这个标记注释:
package de.scrum_master.app;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Marker {}
现在我像这样注释接口和/或方法:
package de.scrum_master.app;
@Marker
public interface MyInterface {
void one();
@Marker void two();
}
这是一个小驱动程序应用程序,它也实现了接口:
package de.scrum_master.app;
public class Application implements MyInterface {
@Override
public void one() {}
@Override
public void two() {}
public static void main(String[] args) {
Application application = new Application();
application.one();
application.two();
}
}
现在当我定义这个方面时,我希望它被触发
package de.scrum_master.aspect;
import de.scrum_master.app.Marker;
public aspect MarkerAnnotationInterceptor {
after() : execution((@Marker *).new(..)) && !within(MarkerAnnotationInterceptor) {
System.out.println(thisJoinPoint);
}
after() : execution(@Marker * *(..)) && !within(MarkerAnnotationInterceptor) {
System.out.println(thisJoinPoint);
}
}
不幸的是,方面没有打印任何内容,就像类应用程序和方法
two()
没有任何标记一样。为什么AspectJ不拦截它们?
这里的问题不是AspectJ,而是JVM。在Java中,注释位于
永远不会被继承
注释继承仅适用于从类到子类,但仅当超类中使用的注释类型具有继承的元注释时,请参阅JDK JavaDoc。
AspectJ是一种JVM语言,因此在JVM的限制范围内工作。这个问题没有通用的解决方案,但对于您希望模拟注释继承的特定接口或方法,可以使用以下解决方法:
package de.scrum_master.aspect;
import de.scrum_master.app.Marker;
import de.scrum_master.app.MyInterface;
/**
* It is a known JVM limitation that annotations are never inherited from interface
* to implementing class or from method to overriding method, see explanation in
* <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html">JDK API</a>.
* <p>
* Here is a little AspectJ trick which does it manually.
*
*/
public aspect MarkerAnnotationInheritor {
// Implementing classes should inherit marker annotation
declare @type: MyInterface+ : @Marker;
// Overriding methods 'two' should inherit marker annotation
declare @method : void MyInterface+.two() : @Marker;
}
请注意:有了这个方面,您可以从接口和带注释的方法中删除(文字)注释,因为AspectJ的ITD(类型间定义)机制将它们添加回接口以及所有实现/重写类/方法。
现在,当运行应用程序时,控制台日志显示:
execution(de.scrum_master.app.Application())
execution(void de.scrum_master.app.Application.two())
顺便说一句,您还可以将方面嵌入到界面中,以便将所有内容都放在一个地方。只需小心重命名MyInterface。java到MyInterface。aj是为了帮助AspectJ编译器认识到它必须在这里做一些工作。
package de.scrum_master.app;
public interface MyInterface {
void one();
void two();
// Cannot omit 'static' here due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=571104
public static aspect MarkerAnnotationInheritor {
// Implementing classes should inherit marker annotation
declare @type: MyInterface+ : @Marker;
// Overriding methods 'two' should inherit marker annotation
declare @method : void MyInterface+.two() : @Marker;
}
}
更新2021-02-11:有人建议对后一种解决方案进行编辑,说嵌套在接口MyInterface
中的方面MarkerAnNotationInheritor
是隐式公共静态
,因此可以省略方面声明中的修饰符。原则上这是真的,因为接口的成员(方法、嵌套类)默认情况下总是公共的,非静态内部类定义在接口内部也没有意义(没有实例可以绑定它)。不过,我喜欢在我的示例代码中明确,因为并非所有Java开发人员都知道这些细节。
此外,当前版本1.9.6中的AspectJ编译器在忽略静态时会抛出一个错误。我刚刚为这个问题创建了AspectJ问题#571104。
问题内容: 人们经常会问诸如此类的AspectJ问题,因此我想在一个我以后可以轻松链接的地方回答它。 我有这个标记注释: 现在,我注释这样的接口和/或方法: 这是一个小的驱动程序应用程序,它也实现了该接口: 现在,当我定义此方面时,我希望它会被触发 为每个构造函数执行带注释的类,并 每次执行带注释的方法。 不幸的是,方面没有打印任何内容,就像类Application和方法two()没有任何@Mar
我有一个带有注释方法的接口。注释用标记,所以我希望实现者继承它。然而事实并非如此: 所以问题是,为什么没有,尽管它实现了一个标记为的方法,即?
我对EasyMock(3.1)类的模拟有些困难。这应该适用于模拟部分类实现,我认为,这对于单元测试抽象基类,同时模拟缺少的方法是非常理想的。这是一个模式-一个立即识别的经典... 现在的测试是: EasyMock似乎不喜欢这样。它抛出: 有什么想法吗?我发现了一个相关的问题,但它并不是真正公正的标题。
问题内容: 由于外部库不公开接口(因此不是可模拟的),而仅公开纯函数,因此我很难在Go中编写单元测试。即使像Google这样的大公司也没有,所以我想知道我的方法是否足够好。库不是提供s而不是仅提供函数的包以便用户模拟它们的好习惯吗? 到目前为止,我想到的解决方案是将这些程序包与接口的实现包装在一起,但这似乎工作量太大。 我举一个例子。我的功能可能看起来像这样 其中session是一个导入的包,返回
我这里有我的问题的简化版本。A类有一个受保护的方法。类B继承了这个方法。 我现在用Mockito编写一个单元测试,它在另一个包测试中,我想测试方法。为此,我需要模拟getString()调用。由于该方法受到保护,并且我的测试类位于不同的包中,所以我不能使用。问题是,我监视类B。所以我不能使用。 我尝试通过反射获得受保护的方法: 但是我不知道如何在中使用这个。
我有一个方法,我需要写单元测试用例。该方法返回类型。