Spring Class.getAnnotationsByType does not work correctly when I introduce AOP - spring

I have a Bean in Spring with a custom Annotation.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface CliCommand {
Slice slice();
}
During runtime (startup) I want to load all classes that have this annotation.
During this process I call.
CliCommand[] cliAnnotations = myclass.getAnnotationsByType(CliCommand.class);
Before I introduced AOP it worked fine.
However now this returns NULL.
My AOP looks like this.
#Pointcut("within(com.companyx.cli..*)")
public void cliLayer() {
}
#Before("cliLayer()")
public void injectCLI(JoinPoint jp){
MDC.put(ConnectApplicationContext.LOG_LAYER_NAME, Layer.CLI);
}
I am not sure why this is happening. Has anyone seen this before. Is it something to do with the cgLib?

Cglib generates child of your class when creating proxy. So if 'myclass' in your example was obtained via someCglibObject.getClass() you will get cglib subclass, not yours.
In this case to make annotations declared on parent class to be available via childClass.getAnnotationsByType you should annotate your custom annotation with #Inherited

Related

Is it possible to cut into protected method inside abstract class using Spring AOP?

I am trying to execute some code after one protected method inside abstract class gets called. It looks something like this.
abstract class SomeAbstractClass : ServiceOne, ServiceTwo {
protected fun doSomething(p1: String, p2: Int): SomeEntity {
// some business logic
return SomeEntity()
}
}
I want to create annotation class like the one below and annotate method (above) with it and I want it to execute after class method returns value. I tried this and many other variations but nothing worked for me.
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.RUNTIME)
annotation class EntityCreated {
#Aspect
#Component
class EntityAspect {
#AfterReturning("#annotation(EntityCreated)")
fun afterSuccessfulCreate(jp: JoinPoint) {
// Created, execute something here
}
}
}
While protected methods are off limits for JDK proxies when proxying interfaces, the CGLIB proxies used by Spring to extend classes can intercept protected methods. But in order to proxy a Kotlin class, you have to open it, so it is not final and can be proxied.
Please note, however, that if you override a protected method in Java, that overridden method will not "inherit" the super method's annotations. This is a Java limitation and unrelated to AOP. Annotation inheritance only works from parent to sub classes, if the annotation bears the #Inherited meta annotation. There is a way to emulate annotation inheritance using an advanced form of a technique called ITD (inter-type definition) in native AspectJ, but not in simple Spring AOP.
The exact answer to your question depends on your exact use case, your sample code is too fragmentary to answer in more detail.

How can I reference annotation arguments in a custom Spring annotation?

I have an abstract class with methods requiring certain permissions. I would like the implementing classes to be able to require additional permissions, while still requiring those from the abstract class. Simply adding another #PreAuthorize annotation seems to override whatever was required in the abstract class, so my idea was to implement an annotation of my own.
My question is: how do I reference arguments in the #PreAuthorize annotation?
This code:
// Custom annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('BASE_PERMISSION') and hasRole('#role')")
public #interface MyCustomPreAuthorize {
String role() default "";
}
// Implementing class
#MyCustomPreAuthorize(role = "ANOTHER_ROLE")
does not seem to work.

What is the difference between #Configuration and #Component in Spring?

#ComponentScan creates beans using both #Configuration and #Component. Both these annotations work fine when swapped. What is the difference then?
#Configuration Indicates that a class declares one or more #Bean
methods and may be processed by the Spring container to generate bean
definitions and service requests for those beans at runtime
#Component Indicates that an annotated class is a "component". Such
classes are considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
#Configuration is meta-annotated with #Component, therefore
#Configuration classes are candidates for component scanning
You can see more here:
http://docs.spring.io/spring-framework/docs/4.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html
A #Configuration is also a #Component, but a #Component cannot act like a #Configuration.
Actually answer is not complete, is it true that:
#Component Indicates that an annotated class is a "component". Such
classes are considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.
But you do can create i.e MyConfiguration.java class then stereotype with #Component and add #Beans declaration to it. In this way it will looks as a configuration, main difference is that when annotated class with #Configuration #Bean annotated methods are proxy using CGLIB which made in code calls after the first one to return bean from context instead of execute method again and create another instance as happens when using #Component with #Bean
There is a very subtle difference between them. Let me provide a very quick outlook to this.
Consider the below scenario:
#Configuration
public class MyConfig {
#Bean
public ServiceA aService(){
return new ServiceA();
}
#Bean
public ServiceB bService(){
return new ServiceB(aService());
}
}
Note that ServiceB bean has a dependecy on ServiceA and this is not autowired. Instead, the way it's written implies that a new instance is created, which is not actually created by Spring. You, the programmer, did it with the new keyword instead.
So, if we do use #Configuration, then it uses CGLIB proxying, and in this situation it creates a singleton bean managed by the Spring context. If you invoke it multiple times, it returns the same bean that was created by Spring - sort of autowiring effect.
Whereas if you use #Component, it won't do this proxying and will simply return a new instance every time the method is invoked, instead of providing the Spring managed instance. (Remember that a Spring bean is something that is managed by the Spring container, and, as a developer, it's your job is to pull them in, e.g. with #Autowired.
The same #Component effect can be achieved with #Configuration(proxyEnabled= false) (This is also referred to as bean light mode processing). So, in light mode, you would end up doing something like this:
#Configuration(proxyEnabled = false) // Lite mode, same effect as #Component
public class MyConfig {
#Bean
public ServiceA aService() {
return new ServiceA();
}
#Autowired
#Bean
public ServiceB bService(ServiceA aServiceBean){
return new ServiceB(aServiceBean);
}
}
Refer here for a more elaborate explanation
Hope that helps! Happy Coding!
#Configuration - It is like beans.xml but Java-based bean configuration. It means class annotated with this annotation is the place where beans are configured and will be a candidate for auto-detection. In this class, methods are annotated with #Bean which return an object of the class.
Example:
#Configuration
public class ConfigClass {
#Bean
public UserClass getObject() {
return new UserClass();
}
}
#Component - You cannot autowire (#Autowired) any class if it is not marked with #Component. It means when you want to autowire any class using annotation that class should be annotated with #Component.
Example:
#Component
public class A { .... }
public class B {
#Autowired
A a;
.....
.....
}
Spring Document for reference:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
#Component is imported by default with #Configuration. controllers, service, and repostory are children components (along with Configuration). They are also candidate for auto-detection.
I am extending on #reus's answer.
#Configuration Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
If you look at the #Configuration class, you will see that it is meta-annotated with #Component.
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Configuration
#Bean is enables us to define the dependency in any way we like, this is why the #Bean annotation goes above a methods and we manually create a bean object and return it from that method. #Component enables us to define a dependency quickly, that is why #Component goes above classes. We only inject it wherever we need.
Collectively these 3 points says that- to quickly define a bean, we can annotate the class with #Component. To define a bean as we like (support custom requirements), we can write the bean definition using #Bean inside a #Configuration annotated class.
Apart from the differences highlighted by reos.
The reason why #Configuration cannot be replaced by #Component is as below:
The difference is in how the inter bean dependency is handled.
Refer the link for a detailed explanation with example:
Difference between Configuration and Component

Can #ContextConfiguration in a custom annotation be merged?

I am working on custom Spring Boot starters. In a test starter what I wanted do to is to implement a composed annotation, which would add additional #Configuration classes to the ApplicationContext (and possibly use this annotation in a TestExecutionListener). ex:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#ContextConfiguration(classes = AdditionalTestConfiguration.class)
public #interface ComposedAnnotation {
}
And use that in my Spring Boot integration test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebIntegrationTest
#SpringApplicationConfiguration(Application.class)
#ComposedAnnotation
public class SomeTest {
}
No inheritance is involved. Unfortunately, it does not seem to work. I doubt it's a Spring Boot thing, rather Spring testing framework itself.
Is there any way I can achieve expected result?
You're right: this is not an issue with Spring Boot. But it's also not an issue with spring-test.
Rather, it's the intended behavior of Spring in general. For details, check out my answer to this question: #ActiveProfiles in meta annotation and on test class not working
In summary, you cannot achieve this with two #ContextConfiguration annotations declared on an individual test class (either directly or as meta-annotations).
However, I just came up with a trick that will allow you to achieve this. Specifically, you can create an ApplicationContextInitializer (ACI) that registers one or more #Configuration classes. In your composed annotation, you can then register this ACI to register the always present #Configuration classes. And when the composed annotation is actually used, it can declare additional #Configuration classes like normal.
I just submitted a working example in this commit.
Basically, the code would look something like this:
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, initializers = FooConfigInitializer.class)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface ComposedContextConfiguration {
#AliasFor(annotation = ContextConfiguration.class, attribute = "classes")
Class<?>[] value() default {};
}
public class FooConfigInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
#Override
public void initialize(GenericApplicationContext applicationContext) {
new AnnotatedBeanDefinitionReader(applicationContext).register(FooConfig.class);
}
}
And you can use it like this:
#RunWith(SpringRunner.class)
#ComposedContextConfiguration(BarConfig.class)
public class InitializerConfiguredViaMetaAnnotationTests { /* ... */ }
Your ApplicationContext will then be loaded from FooConfig and BarConfig.
The above examples obviously do not use Spring Boot, but the same principles should also be applicable to #SpringApplicationConfiguration.
Regards,
Sam (author of the Spring TestContext Framework)

How to set up init-method for a bean when spring is configured by annotation driven?

I use spring roo to build project and it's annotation driven, and there is no bean definition in XML file. All the configuration info is in *.aj file.
And now I want to set up an init method for a bean which don't have a default constructor (that bean is from the third party and it has a constructor with arguments, and I cannot remove them or give a default constructor to it.)
Is there anyone who can tell me how to do this, please?
The reason I want to do this is because I want to use applicationContext.getBean("thatBeanName") to dynamically get the bean and use it. Because the bean don't have a default constructor, I always get the error: java.lang.NoSuchMethodException: com.to.that.bean.<init>() and this is why I want to add the init-method to the bean.
Use #PostConstruct as shown in below example. It is equivalent to init-method="initialize()"
#PostConstruct
public void initialize() {
messages.put("English", "Welcome");
messages.put("Deutsch", "Willkommen");
}
#Bean(initMethod="init")
public MyBean getMyBean() {
...
}
In spring container it is "init" method that being called the last,
#postconstruct called before afterPropertiesSet. so it is safer if someone miss use.
"Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
1.Methods annotated with #PostConstruct
2.afterPropertiesSet() as defined by the InitializingBean callback interface
A custom configured init() method
[https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-java-lifecycle-callbacks][1]
Although, today I would prefer to be more Spring independent and use either #Postconstract, or even configure default init method recognition. to have only meaningful method name indicate that it should be used for initialization - clear from frameworks, clear from annotations.
As #Pangea has put in , #PostConstruct is the best choice. You could also implement initializingBean and do the initialization in afterPropertiesSet method .Check here for this approach.
I realized that there have been multiple answers trying to solve the problem. But with the newly introduced #Configuration which is popularly used within Spring Boot. Things are changed a little bit.
If you are using #Bean annotation in #Configuration annotated class like:
#Configuration
class FooClass {
#Bean
public Bar bar() {
return new Bar();
}
}
If you want to use an automatically called method on the bean instance during initialization, you have two options below:
Option1:
#Configuration
class FooClass {
#Bean(initMethod="init")
public Bar bar() {
return new Bar();
}
}
Option2:
#Configuration
class FooClass {
#Bean
public Bar bar() {
Bar bar = new Bar();
bar.init();
return bar;
}
}
BUT, as is explain in #Bean Java Doc here:
/**
* The optional name of a method to call on the bean instance during initialization.
* Not commonly used, given that the method may be called programmatically directly
* within the body of a Bean-annotated method.
* The default value is {#code ""}, indicating no init method to be called.
*/
The second is regarded as a better answer. See link here

Resources