Reputation: 4216
Spring supports the creation of Beans using methods. E.g. a definition like so:
@Bean
public DataSource springBatchDataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
... rest of init code omitted for brevity ...
return dataSource;
}
defines a Bean "SpringBatchDataSource". That Bean can then be used for Autowiring etc.
However, we had a couple of cases where junior colleagues hadn't understood that concept and had instead called the method to create an object of that type, i.e. instead of
...
@Autowire
DataSource ds;
...
they had written something like:
...
DataSource ds = springBatchDataSource();
...
If you do that at several places you end up having multiple objects instead of all talking to the same, single Bean (as was intended - that Bean should be (considered) a singleton in your application). The multiple objects then caused major issues in our application.
I thus now want to add an ArchUnit-check to prevent the access to methods that are actually Bean creators. How do I do that?
I found a callMethodWhere(...)
-method that takes a predicate on methods and I found a predicate areAnnotatedWith(<class>.class)
, so that would become: areAnnotatedWith(Bean.class)
. But I am lost in how to combine and apply these, i.e. what would need to replace the ???
in my below snippet?
@ArchTest
void checkNoCallToBeanCreators(JavaClasses classes) {
ArchRule rule = noClasses()
.should().callMethodWhere(???.areAnnotatedWith(Bean.class));
rule.check(classes);
}
Or is there some better, more elegant or even straight forward way of checking this?
Upvotes: 0
Views: 158
Reputation: 3142
I found a
callMethodWhere(...)
-method that takes a predicate on methods
You're wrong in a relevant detail: callMethodWhere(...)
takes a predicate for JavaMethodCall
s, not for JavaMethod
s.
The actually called method is the target
of a method call.
With JavaAccess.Functions.Get.target
, you can conveniently transform a predicate for JavaMethod
s to a predicate for JavaMethodCall
s. With
import static com.tngtech.archunit.core.domain.JavaAccess.Functions.Get.target;
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Predicates.annotatedWith;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
you can write your rule as
noClasses().should().callMethodWhere(target().is(annotatedWith(Bean.class)))
Upvotes: 0