Issue
Having recently been bit by Spring CGLib vs JDK Dynamic proxying issues in a Spring Boot application (that when run on a Mac seems to use CGLib where as the same app when run on Linux is using JDK dynamic proxying).
I'm looking for a linter tool config / plugin (PMD, Checkstyle, Spotbugs etc) that can identify where an @Autowired annotated field / parameter is being used and the Class being autowired is defined with a class instance rather than an interface.
For example:
public interface MyService {
}
public class MyServiceImpl implements MyService {
}
@RestController
public class MyController {
@Autowired
private MyServiceImpl serviceImpl; // this should raise a warning in a linter as
// class is being used for injection type
@Autowired
private MyService service; // this should not raise a warning, as interface
// is used for type
}
Solution
I don't think this will be possible to check with PMD, Checkstyle, Spotbugs, etc. But there is a solution to check this.
ArchUnit offers writing custom rules, a custom rule can be written for this. Assuming you are using JUnit5 or JUnit4 for testing, you could do something like-
@ArchTest
public static final ArchRule archRule = noFields()
.that()
.areAnnotatedWith(Autowired.class)
.should()
.haveNameEndingWith("Impl");
This can be incorporated within your tests, you would have to read the documentation of arch unit and set up in your work environment, it super easy to integrate. You can create similar rules for setters or methods-
@ArchTest
public static final ArchRule archRule1 = noMethods()
.that()
.areAnnotatedWith(Autowired.class)
.should()
.haveRawParameterTypes(MyServiceImpl.class, MyDaoImpl.class);
As you integrate this into your code base, you can create custom rules for yourself. Using ArchUnit for spring projects is generally a great idea, they also have pre configured templates that you can use in your project. Hope this helps.
Answered By - VyomYdv
Answer Checked By - David Goodson (JavaFixing Volunteer)