cailin186 / reflections

Automatically exported from code.google.com/p/reflections
Do What The F*ck You Want To Public License
0 stars 0 forks source link

Type scanning crashes with exception: java.lang.RuntimeException: could not create class file from class #78

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Add the attached jar file to the classpath
2. Create a Reflections object with following code
        Reflections r = new Reflections(new ConfigurationBuilder().setUrls(
            ClasspathHelper.getUrlsForCurrentClasspath()).setScanners(new TypesScanner(),
            new TypeAnnotationsScanner()));

-----------------------------
Ideally:
The parsing of the classpath should not throw any exception.

Instead:
The execution of the above code crashes with following exception:

Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: 
could not create class file from class
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
    at java.util.concurrent.FutureTask.get(FutureTask.java:83)
    at org.reflections.Reflections.scan(Reflections.java:162)
    ... 14 more
Caused by: java.lang.RuntimeException: could not create class file from class
    at org.reflections.scanners.TypesScanner.scan(TypesScanner.java:28)
    at org.reflections.Reflections$2.run(Reflections.java:149)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    ... 1 more
Caused by: java.io.IOException: bad magic number: 230a2320
    at javassist.bytecode.ClassFile.read(ClassFile.java:689)
    at javassist.bytecode.ClassFile.<init>(ClassFile.java:85)
    at org.reflections.adapters.JavassistAdapter.createClassObject(JavassistAdapter.java:86)
    at org.reflections.adapters.JavassistAdapter.createClassObject(JavassistAdapter.java:22)
    at org.reflections.scanners.TypesScanner.scan(TypesScanner.java:25)
    ... 7 more

-----------------------------
The used version is: 0.9.5-RC2 / on Win 7 Pro (reproducible on Win XP Pro)

-----------------------------
Most of the type related scanners have one default implementation of the 
acceptsInput() method, which looks like:

    public boolean acceptsInput(String file) {
        return file.endsWith(".class"); //classes only
    }

The problem comes when the class-path contains a file like (inside a jar):

camel-core-2.7.0.jar/META-INF/services/org/apache/camel/component/class

Normally this file should be avoided by the above filter code(does not end with 
.class) but unfortunately before calling the scanners the Reflection object 
transforms the above path into:

META-INF.services.org.apache.camel.component.class

and this gets passed to the scanners acceptsInput() method, which normally 
returns true.
Because of this the file gets passed to the scan() method of the scanner which 
fails.

The problem seems to be in the Reflections class scan() method, where the 
following code is found:

....

                for (final Vfs.File file : files) {
                    Future<?> future = executorService.submit(new Runnable() {
                        public void run() {
                            String input = file.getRelativePath().replace('/', '.');
                            if (configuration.acceptsInput(input)) {
                                for (Scanner scanner : configuration.getScanners()) {
                                    if (scanner.acceptsInput(input)) {
                                        scanner.scan(file);
                                    }
                                }
                            }
                        }
                    });
                    futures.add(future);
                }
....
(decompiled code)

Unfortunately I could not understand what purpose does it serve the following 
line of code?:

 String input = file.getRelativePath().replace('/', '.');

Because of this it is impossible to solve the mentioned bug in the Scanner 
acceptInput() method.

Shouldn't this be just? 

 String input = file.getRelativePath();

I think it should cover all situations for files inside jars. Or?

Original issue reported on code.google.com by norbert....@gmail.com on 30 Jun 2011 at 10:35

Attachments:

GoogleCodeExporter commented 9 years ago
already fixed on trunk, check out or wait for new version

Original comment by ronm...@gmail.com on 1 Jul 2011 at 5:05