Can't find java class using reflection
Today I'd like to share an interesting case that took me some time before I came to a solution.
The case was about using reflection in unit tests to check if the established naming conventions are followed.
Problem - reflection does not find all classes
Let's assume a project that has 4 classes named:
UsecaseA
UsecaseB
UsecaseC
UsecaseD
All of these classes extend the AbstractUsecase
class.
The code can be previewed here:
github.com/speedlog/reflection-cant-find-class/tree/main/src/main/java/pl/speedlog/example
I wrote atest, which should check existence of classes that extend AbstractUsecase.
1@Test
2void searchUsecaseClasses() {
3 Reflections reflections = new Reflections("pl.speedlog.example.reflection");
4 Set < Class << ? extends AbstractUsecase >> classes = reflections.getSubTypesOf(AbstractUsecase.class);
5 Set < Class << ? extends AbstractUsecase >> expectedList = new HashSet < > ();
6 expectedList.add(UsecaseA.class);
7 expectedList.add(UsecaseB.class);
8 expectedList.add(UsecaseC.class);
9 expectedList.add(UsecaseD.class);
10 Assertions.assertEquals(expectedList, classes);
11}
It turns out that this simple test that was supposed to check if the 4 UsecaseA-D
classes extend AbstractUsecase
unfortunately ended in an error:
1Expected :[class pl.speedlog.example.reflection.domain2.UsecaseC, class pl.speedlog.example.reflection.domain1.UsecaseB, class pl.speedlog.example.reflection.domain2.UsecaseD, class pl.speedlog.example.reflection.domain1.UsecaseA]
2Actual :[class pl.speedlog.example.reflection.domain2.UsecaseC, class pl.speedlog.example.reflection.domain1.UsecaseA]
It only found 2 classes instead of 4.
Solution
It turned out that the project inherited a transitive dependency to the reflection library (via another library). In addition, it was an old version 0.9.9-RC1.
Classes that were not detected used functionality introduced in java 8 (lambda). The reflection library was able to read data only from classes containing java 7 bytecode.
I came to this solution when I changed the logging level to DEBUG
. The message clearly indicated that it could not read the aforementioned classes:
123:18:48.305 [main] DEBUG org.reflections.Reflections - could not scan file pl/speedlog/example/reflection/domain1/UsecaseB.class in url file:/home/speedlog/repos/blog/reflection-cant-find-class/target/classes/ with scanner TypeAnnotationsScanner
223:18:48.306 [main] DEBUG org.reflections.Reflections - could not scan file pl/speedlog/example/reflection/domain1/UsecaseB.class in url file:/home/speedlog/repos/blog/reflection-cant-find-class/target/classes/ with scanner SubTypesScanner
323:18:48.307 [main] DEBUG org.reflections.Reflections - could not scan file pl/speedlog/example/reflection/domain2/UsecaseD.class in url file:/home/speedlog/repos/blog/reflection-cant-find-class/target/classes/ with scanner TypeAnnotationsScanner
423:18:48.308 [main] DEBUG org.reflections.Reflections - could not scan file pl/speedlog/example/reflection/domain2/UsecaseD.class in url file:/home/speedlog/repos/blog/reflection-cant-find-class/target/classes/ with scanner SubTypesScanner
Summary
Whenever you have a problem that you can't see the solution to, immediately change the logging level to DEBUG
or TRACE
.
2. check the versions of the libraries and try to use the current versions.