reflections icon indicating copy to clipboard operation
reflections copied to clipboard

[0.10.2] Reflections does not detect any classes, if base class (or package prefix) is passed as argument, and application is running as a jar

Open Bairei opened this issue 4 years ago • 16 comments

Given the application built using Java 11 and Spring Boot framework, interface DeviceCode, residing inside the some.package package, and enum classes some.package.a.A, some.package.b.B, some.package.c.C, each implementing the DeviceCode: and code:

public interface DeviceCode {

  static List<DeviceCode> getDeviceCodes() {
    Reflections reflections = new Reflections(DeviceCode.class);
    Set<Class<? extends DeviceCode>> classes = reflections.getSubTypesOf(DeviceCode.class);
    // ...
  }
}

// SomeService.java that runs the code above on start
@Service
class SomeService {

  private final List<DeviceCode> devices = DeviceCode.getDeviceCodes();
  // ...
} 

Expected behaviour:

After migrating from 0.9.12, reflections should detect all the classes implementing DeviceCode interface, in this case A, B, C, as usual, no matter the environment that the application runs on.

Actual behaviour:

Although the code runs as expected, when ran using the IDE (e.g. IntelliJ IDEA), or build tools (during tests) like Maven, no class is detected when the application is launched using java -jar command. Same issue appears, if we initiate reflections using interface's package as an argument:

    Reflections reflections = new Reflections("some.package"); // or new Reflections (DeviceCode.class.getPackageName());

Current workaround:

Reflections object must be initiated using ConfigurationBuilder instance, in order to restore the previous functionality, when application is running as a jar.

    Reflections reflections =
        new Reflections(new ConfigurationBuilder().forPackages(DeviceCode.class.getPackageName()));
    Set<Class<? extends DeviceCode>> classes = reflections.getSubTypesOf(DeviceCode.class);

Bairei avatar Dec 15 '21 06:12 Bairei

Can confirm, had the exact same issue. Worked when started "outside" of a JAR, failed when inside when using new Reflections("my.pkg.name.here").

The provided workaround worked like a charm, thanks a lot!

olewehrmeyer avatar Dec 19 '21 18:12 olewehrmeyer

same issue too

wuqifeng avatar Dec 24 '21 07:12 wuqifeng

Same problem here.

tkn777 avatar Jan 16 '22 00:01 tkn777

same problem, and we use java -jar command online....

JiaYingLii avatar Jan 18 '22 05:01 JiaYingLii

Same problem here as well, only the provided workaround does not fix it for us image

GriffinCodes avatar Jan 18 '22 22:01 GriffinCodes

Yep same problem. @Bairei thank you for the workaround - it works flawlessly.

BeshEater avatar Apr 12 '22 12:04 BeshEater

Same here, using maven process plugin to start services during integration test phase.
Pay attention that you better filter out the exact package you initially set as String in the Reflections constructor other wise you will scan much more than you intended:


FilterBuilder inputsFilter = new FilterBuilder();
inputsFilter.includePackage("com.your.package");

reflections = new Reflections(new ConfigurationBuilder()
                .forPackage("com.your.package")
                .addScanners(Scanners.TypesAnnotated)
                .filterInputsBy(inputsFilter));

mistriel avatar Apr 28 '22 17:04 mistriel

same problem, and we use java -jar command online....

i found another workaround:

var reflections = new Reflections(new ConfigurationBuilder()
                .setUrls(ClasspathHelper.forPackage(DeviceCode.class.getPackageName())));
var classes = reflections.getTypesAnnotatedWith(DeviceCode.class);

vlborkunov avatar May 16 '22 19:05 vlborkunov

In our case the workaround "fixes" running from commandline but breaks running from IDE (tried with both Intellij and Eclipse) - I get error:

...

java.lang.SecurityException: sealing violation: can't seal package oracle.jdbc.driver: already defined [ Stack Trace: at java.base/jdk.internal.loader.BuiltinClassLoader.getAndVerifyPackage(BuiltinClassLoader.java:850) 

Therefore had to specify classloader as well for it to work for both:

static Reflections reflections = new Reflections(
            new ConfigurationBuilder()
                    .setClassLoaders(new ClassLoader[]{
                            ClassLoader.getPlatformClassLoader()
                    })
                    .setUrls(ClasspathHelper.forPackage("com.package"))
    );

asgarov1 avatar Jul 01 '22 07:07 asgarov1

Same problem 😅

heowc avatar Dec 06 '22 11:12 heowc

The workaround mentioned above does not work for JAR files created with Spring Boot. JAR URL is then

jar:file:/home/me/myproject/target/myproject.jar!/BOOT-INF/classes!/

and it internally throws an exception that /BOOT-INF/classes!/ cannot be opened.

martin-kuba avatar Jan 09 '23 16:01 martin-kuba

Current workaround:

Reflections object must be initiated using ConfigurationBuilder instance, in order to restore the previous functionality, when application is running as a jar.

    Reflections reflections =
        new Reflections(new ConfigurationBuilder().forPackages(DeviceCode.class.getPackageName()));
    Set<Class<? extends DeviceCode>> classes = reflections.getSubTypesOf(DeviceCode.class);

it was working; thank you

BellerSun avatar Jan 16 '23 09:01 BellerSun

I tried below approach and it works like magic. reflections = new Reflections(new ConfigurationBuilder() .setUrls(ClasspathHelper.forPackage(package.name.here)) .setScanners(Scanners.values()));

ankitgarg379 avatar Jul 08 '23 12:07 ankitgarg379

Reflection does not work with spring boot that is run as a boot-jar (java 17)

We tried several ways - nothing worked. Classes in dependencies are scanned correctly, but in boot module (with main method) classes are not found.

The only way that worked:

  • we had to downgrade reflections from version 0.10.2 to 0.9.11
  • Use ConfigurationBuilder, e.g.
var config = new ConfigurationBuilder()
.forPackages(yourPackages)
.setScanners(new SubTypesScanner())
.filterInputsBy(new FilterBuilder().includePackage(packages));

var reflections = new Reflections(config);

reflections.getSubTypesOf(YourType.class)
...

Note: you need to define the same packages forPackages and for filterInputsBy, otherwise it works incorrecly (perhaps, there was a bug in library)

P.S. What is funny: you will get aware of it only in production, since this bug occurs only when app is run as a boot-jar. You won't face it in your functional tests

andriewski avatar Nov 27 '23 16:11 andriewski

I've had same problem with Spring boot 3 and Java 21. This is problem came after update to version 0.10.x.

Solve is simple. You need change your configuration. That worked for me:

Reflections reflections = new Reflections(
              new ConfigurationBuilder()
                      .forPackage("com.example.base.package"));
final Set<Class<? extends SomeInterface>> classSet = reflections.getSubTypesOf(SomeInterface.class);

temanskyM avatar Dec 13 '23 19:12 temanskyM

这是来自QQ邮箱的自动回复邮件。   您好,我已经收到您的邮件

Terraqo avatar Dec 13 '23 19:12 Terraqo