I have created a custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ValidateBeforeBuild {
}
And an aspect as:
#Aspect
#Component
public class AspectForBuildInBuilders {
private static final Logger LOGGER = LoggerFactory.getLogger(AspectForBuildInBuilders.class);
#Before("#annotation(validateBeforeBuild )")
public void validateBusinessModelAdvice(JoinPoint jp, ValidateBeforeBuild validateBeforeBuild ) throws Throwable {
LOGGER.info("Executing class: {}", jp);
}
}
I have a build() that is marked with above annotation. When I am trying to call the build(), I am not getting the log message from the validateBusinessModelAdvice(). I also have #EnableAspectJAutoProxy in one of the configuration classes. Am I missing something? Is there any more information required?
You defined your annotation as ValidateBeforeBuild and in your aspect you specified validateBeforeBuild (notice the upper V in your annotation)
Try changing
#Before("#annotation(validateBeforeBuild)")
for
#Before("#annotation(ValidateBeforeBuild)")
Related
I've been desperately trying to build an extension that requires information from both the JUnit5 extension model and the Spring-Boot Test framework. Specifically, I'd like to hook into the ApplicationContext creation process using a ApplicationContextInitializer and a custom annotation:
#Retention(RUNTIME)
#Target(TYPE)
#ContextConfiguration(initializers = CustomContextInitializer.class)
public #interface CustomAnnotation {
String someOption();
}
The test then looks like this:
#SpringBootTest
#CustomAnnotation(someOption = "Hello There")
public class SomeTest {
...
}
Now, how do I access the CustomAnnotation instance of the test class from within my CustomContextInitializer?
class CustomContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// How to access the Test Class here?
CustomAnnotation annotation = <Test Class>.getAnnotation(CustomAnnotation.class);
System.out.println(annotation.someOption());
}
}
Is it possible to somehow access the JUnit5 ExtensionContext during the creation of the ApplicationContext? It doesn't have to be from within a ApplicationContextInitializer. I just need a hook that is executed early enough so that I can inject some dynamically generated properties before the whole bean instantiation process actually starts.
Take a look at #DynamicPropertySource for injecting properties before the bean initialization. You can then use #RegisterExtension to register a custom extension that reads the annotation properties and makes them available through some method:
#CustomAnnotation(someOption = "Hello There")
public class SomeTest {
#RegisterExtension
static CustomExtension extension = new CustomExtension();
#DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("property.you.need",
() -> customExtension.getProperty());
}
}
public class CustomExtension implements BeforeAllCallback {
private String property;
public String getProperty() {
return property;
}
#Override
public void beforeAll(ExtensionContext context) throws Exception {
CustomAnnotation annotation = context.getRequiredTestClass()
.getAnnotation(CustomAnnotation.class);
property = annotation.someOption();
}
}
I know it doesn’t answer the question about hooking JUnit 5 with Spring initialization mechanism, but if dynamic properties is all you need, this solves exactly that.
You can implement your own TestExecutionListener and use it to access annotation you mentioned
#Retention(RUNTIME)
#Target(ElementType.TYPE)
#TestExecutionListeners(listeners = CustomTestExecutionListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
#interface CustomAnnotation {
String someOption();
}
static class CustomTestExecutionListener implements TestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
final CustomAnnotation annotation = testContext.getTestClass().getAnnotation(CustomAnnotation.class);
System.out.println(annotation.someOption());
}
}
I have a problem with using Aspect with annotation. The aspect method is triggered in some methods, but not in some other methods.
What I have checked is the methods are public, and the class it doesn't work is #Component.
#Aspect
#Component
public class PrometheusCounterMetricAspect {
private static final Map<String, Counter> counters = new HashMap<>();
#Before(
"execution(* *(..)) && #annotation(package.aspects.PrometheusCounterMetric)")
void beforeInsert(JoinPoint joinPoint) {
.....}
This is annotation interface
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface PrometheusCounterMetric {
String metricName();
}
And in the project the flow is controller -> service -> storage. It works in service, but not in storage, despite the fact that It is component.
I have an annotation.
#Target(value = {ElementType.METHOD, ElementType.TYPE})
#Retention(value = RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface MyCustomAnnotation{
}
My Aspect class is like that
#Component
#Aspect
public class MyCustomAsspect{
#AfterReturning(
pointcut="#annotation(MyCustomAnnotation)",
returning="retVal")
public void publishMessage(JoinPoint jp, Object retVal) throws Throwable {
}
}
My Service class is
#Service
public class ServiceClass{
#MyCustomAnnotation
public Object someMethod(){
return new Object();
}
}
Above are mentioned classes i am not sure why my aspect not working. I am new to Spring AOP . Please help me it shall be very thankful.
Issue is due to pointcut declaration. As spring documentation says
#annotation - limits matching to join points where the subject of the
join point (method being executed in Spring AOP) has the given
annotation
So I order to make this work
#Aspect
public class MyCustomAsspect{
#AfterReturning(
pointcut="execution(public * *(..)) and #annotation(MyCustomAnnotation)",
returning="retVal")
public void publishMessage(JoinPoint jp, Object retVal) throws Throwable {
}
}
I'd like to weave an advice on a method that is NOT part of a Spring bean (Spring Boot 1.4.4.RELEASE) :
#Component
#Aspect
...
#Around("execution(public * com.netflix.appinfo.InstanceInfo.getId())")
I added aspectjrt and spring-instrument (??) dependencies
I added #EnableAspectJAutoProxy and #EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED) annotations
I added VM arguments:
-javaagent:d:\.m2\repository\org\springframework\spring-instrument\4.3.6.RELEASE\spring-instrument-4.3.6.RELEASE.jar
-javaagent:d:\.m2\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar
The bean is handled (postconstruct log) but the execution isn't intercepted.
Does anyone has a clue on something I could miss ? Thx in advance
Ok, here is the trick for those interested, a singleton pattern is handling access to a singleton for both LTW and Spring, so it can be injected with Spring dependencies after being weaved by LTW:
#Configuration
#Aspect
public class MyAspect {
#Value("${mycompany.property}")
private String myKey;
#Around("execution(public * com.mycompany.NotASpringean.getProperty())")
public String weave(ProceedingJoinPoint jp) throws Throwable {
String value = (String) jp.proceed();
// transform the value thx to injected myKey value
return value;
}
#Bean("post-construct-aspect")
public MyAspect init() {
return MyAspect.aspectOf(); // get existing instance via factory method
}
private static MyAspect instance = new MyAspect();
/** Singleton pattern used by LTW then Spring */
public static MyAspect aspectOf() {
return instance;
}
}
Try using the #Pointcut annotation too like this:
#Pointcut("execution(public * com.netflix.appinfo.InstanceInfo.getId())")
public void pointcut() {}
#Around("pointcut()")
public Object whatever(ProceedingJoinPoint joinPoint) throws {...}
I'm using Java EE 6 & Jboss AS7.1 and try to use interceptor binding (Example from jboss site).
I have an InterceptorBinding annotation:
#InterceptorBinding
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface GeoRestrictedEquipment {
}
The interceptor:
#GeoRestrictedEquipment
#Interceptor
public class GeoRestrictedEquipmentInterceptor {
#EJB EquipmentDao equipmenttDao;
#EJB SecurityService securityService;
#AroundInvoke
public Object checker(InvocationContext ctx) throws Exception {
Integer id = (Integer) ctx.getParameters()[0];
Equipment equipment = equipmenttDao.findById(id);
GeoChecker.check(equipment.getSite(), securityService.getUser());
return ctx.proceed();
}
}
And a bean:
#Stateless
#LocalBean
#SecurityDomain(Realm.NAME)
#RolesAllowed({ Roles.REGISTERED })
public class PumpService implements PumpServiceLocal {
#Override
#GeoRestrictedEquipment
public PumpInfos getPumpInfos(Integer pumpId) {
/* ... */
}
}
But the interceptor is not called... What do I miss from the example ?
The interceptor is called when I write this:
#Override
#Interceptors({GeoRestrictedEquipmentInterceptor.class})
public PumpInfos getPumpInfos(Integer pumpId) {
/* ... */
}
Thanks for your help.
According to the documentation there is another way rather than using beans.xml:
You do not need to specify the interceptor in the beans.xml file when
you use the #Priority annotation.
#Logged
#Interceptor
#Priority(Interceptor.Priority.APPLICATION)
public class LoggedInterceptor implements Serializable { ... }
And it works.
Did you enable your interceptor as described in the referenced example?
By default, a bean archive has no enabled interceptors bound via
interceptor bindings. An interceptor must be explicitly enabled by
listing its class under the element of the beans.xml
file of the bean archive.
You can use any priority value = Priority.Application is 2000 by default.
For example =
#Interceptor
#Loggable
#Priority(100)
public class FileLogger {}
Priority type:
PLATFORM_BEFORE [0-999] - interceptors start at the first. They are started by the platform.
LIBRARY_BEFORE [1000-1999] - by the libraries.
APPLICATION [2000-2999]- by the application
LIBRARY_AFTER,PLATFORM_AFTER [3000-4000]
You manage primary loading for interceptors.