Using Google-Reflection within Groovy causes exception whereas equivalent Java code works

1k views Asked by At

I'm trying to use some code from another answer on SO, and while the code run in Java, from Groovy it causes an exception.

The code in question is:

Reflections reflections = new Reflections(new ConfigurationBuilder()
        .setScanners( new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner() )
        .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
        .filterInputsBy(
        new FilterBuilder()
                .include( prefix( "net.initech" ) )
                .exclude( prefix( "net.initech.util" )
        )));

The exception is getting throwline in question seems to be: ClasspathHelper.forClassLoader(...)

The happens regardless of whether I'm using @CompileStatic or not. Also, tried just using this.getClassLoader() and the same issue occurs.

The exception is:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/ServletContext at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2688) at java.lang.Class.getDeclaredMethods(Class.java:1962) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.getAbstractMethods(CachedSAMClass.java:91) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.getSAMMethod(CachedSAMClass.java:155) at org.codehaus.groovy.reflection.ClassInfo.isSAM(ClassInfo.java:280) at org.codehaus.groovy.reflection.ClassInfo.createCachedClass(ClassInfo.java:270) at org.codehaus.groovy.reflection.ClassInfo.access$400(ClassInfo.java:36) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:441) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:432) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.ClassInfo.getCachedClass(ClassInfo.java:89) at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:107) at groovy.lang.MetaClassImpl.(MetaClassImpl.java:163) at groovy.lang.MetaClassImpl.(MetaClassImpl.java:187) at groovy.lang.MetaClassImpl.(MetaClassImpl.java:193) at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createNormalMetaClass(MetaClassRegistry.java:158) at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.createWithCustomLookup(MetaClassRegistry.java:148) at groovy.lang.MetaClassRegistry$MetaClassCreationHandle.create(MetaClassRegistry.java:131) at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:175) at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:192) at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:255) at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:859) at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:72) at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:159) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116) at net.initech.DeltaCodeGen.main(DeltaCodeGen.groovy:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext at java.net.URLClassLoader$1.run(URLClassLoader.java:372) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:360) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 35 more

I can work around this by adding to my POM.xml

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>servlet-api</artifactId>
        <version>6.0.37</version>
    </dependency>

but I shouldn't have, and don't have it in the Java version.

2

There are 2 answers

4
Peter Niederwieser On

You might be running into the well-known problem that the Groovy compiler sometimes needs runtime dependencies to be put on its compile class path. This is because the compiler uses Java reflection to access its compile class path. There are concrete plans to fix this in an upcoming release (don't remember if it's 2.x or 3.0).

1
zapp On

Looks like the domain you wish to scan is "net.initech". In that case, why not using ClasspathHelper.forPackage("net.initech") (and leaving the exclude pattern)?

Second, what's the idea of using new ClassLoader[0]?

Also, note the using new SubTypesScanner(false) is not a best practice, as it might create a huge md store of all classes (well, all classes are derived from Object). Basically Reflections does not intend to list all classes (though it obviously can), but to aggregate types based on some criteria (annotation/supertype and so).