I have a bunch of classes inside a Spring 4.2 project.
I'd like to have all of them annotated with #Xyz annotation. According to AspectJ documentation it could be done by
declare #type : x.y.z.* : #Xyz;
instruction.
But I have no clue where to place it.
I did some testing on my side and after some struggling, I looked for the concrete implementation. Sadly, #DeclareAnnotation exists but is not implemented.
We can see it here.
https://github.com/eclipse/org.aspectj/blob/V1_8_9/docs/adk15ProgGuideDB/ataspectj.xml#L1017
I thought it would be implemented sinced the annotation appeared in version 1.5.3. My bad.
Original answer (not working, AspectJ v1.8.9).
First you need to enable AspectJ in your configuration. For example, Java configuration :
#Configuration
#EnableAspectJAutoProxy
public class AopConfiguration {}
Then you create a new aspect with the #DeclareAnnotation annotation :
#Aspect
public class XyzAspect {
#DeclareAnnotation("x.y.z.*")
#Xyz class XyzClass {}
#DeclareAnnotation("x.y.z.MyClass.*(..)")
#Xyz void xyzMethod() {}
}
Related
I need to add an annotation to a class which is in a sperate dependency (in a separate jar) of the project that I am working on. I am wondering that can I do this in Java?
As an example, I need to add an annotation HisClass without touching the source code of HisClass.
public class HisClass{
// ...
}
So, that the above class should be look like below at the build time,
#MyAnnot ( me = MyClass.class )
public class HisClass{
// ...
}
There are many ways:
Write a compiler plugin for javac, and make it add the annotations. This will be quite difficult, as the plugin API has nearly no documentation.
2.(Maybe not possible) Inject the annotation after compiling. Add an extra buildstep after compiling and use a library like ASM to add this annotation to the classfile.
I've got a fairly standard spring boot app which is built with gradle from several gradle modules. Here's the directory layout:
- root
- serviceA
- src/main/java
- org.example.serviceA
- ServiceAApplication.java
- serviceB
- serviceC
- common
- src/main/java
- org.example.common
- CommonSecurityConfiguration.java
What I would like to do is to include the CommonSecurityConfiguration class from the shared common module in serviceA. Note that ServiceAApplication and CommonSecurityConfiguration reside in different base packages.
I tried to use #Import(CommonSecurityConfiguration.class) on my ServiceAApplication, but that had no observable effect at all.
The only thing which worked was to annotate ServiceAApplication like so:
#SpringBootApplication(basePackages = { "org.example.serviceA", "org.example.common"})
public class ServiceAApplication { ... }
This approach works, but seems very coarse grained to me - it will import each and every component and configuration it finds in org.example.common.
Is there a better way to do this? Can I include individual classes into the component scan by listing them one by one?
Try to use
#Import(CommonSecurityConfiguration.class) above configuration class. So it would look like this:
#Configuration
#Import(CommonSecurityConfiguration.class)
public class ServiceAConfiguration { ... }
I believe what you are looking for is #CompnentScan("com.example"), this will tell Spring to look at all the files under the specified path recursively. (In this case it would be #ComponentScan("root"))
You find more info here: baeldun.com/spring-component-scanning
Hope this helps.
Since you want to control which components are brought in , we can make an annotation , let's call that annotation PickyComponentImport
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface PickyComponentImport{
}
Then on our SpringBootApplication annotation we can add a new filter which looks for this annotation.
#ComponentScan(basePackages = { "org.example.serviceA",
"org.example.common" }, includeFilters = #Filter(PickyComponentImport.class))
public class ServiceAApplication { ... }
Then we can just add that annotation on any class we want included
#Configuration
#PickyComponentImport
public class CommonSecurityConfiguration {
}
EDIT: I think if you go with this approach you can just componentScan basepackage as root.
In spring boot we may exclude specific auto-configuration classes such that they will never be applied. Example with annotation based configuration:
#SpringBootApplication(exclude = OneConfiguration.class)
What I want is to provide an environment variable with a value that will determine some auto configurations that will be excluded. Any ideas how to achieve that?
You can exclude this configuration class by default:
#SpringBootApplication(exclude = OneConfiguration.class)
then extend it and make it conditonal:
#Configuration
#ConditionalOnProperty(name = "one.configuration.condtion", havingValue = "some-value")
public class OneConfigurationConditional extends OneConfiguration { }
Create class extending Condition checking value of enviroment variable:
public class AutoConfigurationCondition extends Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return System.getenv("EXCLUDE").equals("yes");
}
}
Then you can use it in Configuration class:
#Configuration
#Conditional(AutoConfigurationCondition.class)
#EnableAutoConfiguration(exclude = {OneConfiguration.class})
class AutoConfigurationExcludingConf {}
I managed to do what I wanted with profiles :-( So I have few files now - e.g. application-artemis.yaml and application-activemq.yaml. In each I've defined corresponding spring.autoconfigure.exclude property. I'm not proud with this solution though it works fine so far and looks more or less neat compared to other things that I did :-) .
What I've tried besides that:
Managing the value with an environment variable, e.g.:
spring:
autoconfigure:
exclude: ${ABC:com.example.Myautoconfiguration}
This does not work and I've even reported it as an issue. But it seems that I can't rely on expression for this property. Strange enough it works for other properties...
I've played around with the suggestion of #Randal Flagg but somehow I couldn't get it up and running - I'm using #SpringBootApplication, the documentation says that I can use EnableAutoConfiguration only once, etc.
I've tried with my own TypeFilter but this is also not an option - autoconfigurations have special treatment during component scan and the design does not seem very extensible there. At least I could not find a nice way to plug in.
I'm using Spring 3.1 and bootstrapping an application using the #Configuration and #ComponentScan attributes.
The actual start is done with
new AnnotationConfigApplicationContext(MyRootConfigurationClass.class);
This Configuration class is annotated with
#Configuration
#ComponentScan("com.my.package")
public class MyRootConfigurationClass
and this works fine. However I'd like to be more specific about the packages I scan so I tried.
#Configuration
#ComponentScan("com.my.package.first,com.my.package.second")
public class MyRootConfigurationClass
However this fails with errors telling me it can't find components specified using the #Component annotation.
What is the correct way to do what I'm after?
Thanks
#ComponentScan uses string array, like this:
#ComponentScan({"com.my.package.first","com.my.package.second"})
When you provide multiple package names in only one string, Spring interprets this as one package name, and thus can't find it.
There is another type-safe alternative to specifying a base-package location as a String. See the API here, but I've also illustrated below:
#ComponentScan(basePackageClasses = {ExampleController.class, ExampleModel.class, ExmapleView.class})
Using the basePackageClasses specifier with your class references will tell Spring to scan those packages (just like the mentioned alternatives), but this method is both type-safe and adds IDE support for future refactoring -- a huge plus in my book.
Reading from the API, Spring suggests creating a no-op marker class or interface in each package you wish to scan that serves no other purpose than to be used as a reference for/by this attribute.
IMO, I don't like the marker-classes (but then again, they are pretty much just like the package-info classes) but the type safety, IDE support, and drastically reducing the number of base packages needed to include for this scan is, with out a doubt, a far better option.
Provide your package name separately, it requires a String[] for package names.
Instead of this:
#ComponentScan("com.my.package.first,com.my.package.second")
Use this:
#ComponentScan({"com.my.package.first","com.my.package.second"})
Another way of doing this is using the basePackages field; which is a field inside ComponentScan annotation.
#ComponentScan(basePackages={"com.firstpackage","com.secondpackage"})
If you look into the ComponentScan annotation .class from the jar file you will see a basePackages field that takes in an array of Strings
public #interface ComponentScan {
String[] basePackages() default {};
}
Or you can mention the classes explicitly. Which takes in array of classes
Class<?>[] basePackageClasses
You use ComponentScan to scan multiple packages using
#ComponentScan({"com.my.package.first","com.my.package.second"})
You can also use #ComponentScans annotation:
#ComponentScans(value = { #ComponentScan("com.my.package.first"),
#ComponentScan("com.my.package.second") })
I use:
#ComponentScan(basePackages = {"com.package1","com.package2","com.package3", "com.packagen"})
make sure you have added this dependency in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Use
#ComponentScan(basePackages = {"package1", "package2"})
define it at top before class.
Edit: the brackets must be around all the base packages, not a pair of brackets per package
In my grails application I have Java classes (src/java). And I want to have access to my domain classes and use GORM features(like get(), findBy..., save(), delete() and etc.) directly from my Java classes. I know, I can do this by Spring IoC: for example, I can add grails service to my Java class:
public class SimpleJavaClass{
//...
#Autowired
private ExampleService exampleService;
//...
}
And wireup each instance of this class by Spring:
//...
GrailsApplication grailsApplication
//...
def simpleAction(){
def instance = new SimpleJavaClass()
grailsApplication.mainContext.autowireCapableBeanFactory.autowireBean(instance)
}
But may be there is more appropriate way to do same?
Using Grails 2.0, the only current way is to package your domain classes into a binary plugin (see http://grails.org/doc/2.0.x/guide/single.html#binaryPlugins)
You then can depend on this binary plugin and because it is precompiled the Java code will see many of the GORM methods which are wired into the byte code