1

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.

Community
  • 1
  • 1
Sled
  • 18,541
  • 27
  • 119
  • 168
  • A wild guess: maybe this is related to the groovy compiler which triggers the need for some libraries, even though they are not used in Groovy code. – Will Jan 11 '14 at 12:28

2 Answers2

1

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).

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
  • That would be strange since the package I'm scanning is only simple POJOs that are used to represent our domain. – Sled Jan 13 '14 at 18:15
  • Looking at this again, since you aren't getting this exception at compile time, you aren't running into the issue I mentioned. However, since it happens when Groovy reflectively inspects a class, it might be a similar problem. What's at line 27 of `DeltaCodeGen.groovy`? Does this line reference a class that declares just a single method? Does any of your runtime dependencies have an optional dependency on the servlet API? – Peter Niederwieser Jan 13 '14 at 22:05
  • `ClasspathHelper.forClassLoader(...)` The only classloader in that list is the base class for all of our domain models. The Maven project that I am scanning doesn't even have `ServletContext` in it's dependencies AFAICT. – Sled Jan 14 '14 at 20:44
  • It has to come from somewhere. Could also be an optional dependency of the reflections library. – Peter Niederwieser Jan 15 '14 at 00:26
0

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).

Sled
  • 18,541
  • 27
  • 119
  • 168
zapp
  • 1,533
  • 1
  • 14
  • 18
  • Well my intent was to use the code from the answer from that other question as closely as possible. And I also wanted classes in `net.initech.foo` and `net.initech.bar` etc, just not `net.initech.util`. – Sled Jan 20 '14 at 13:51