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.

Translations: