6

Problem

Simple process request: find all extensions of List.class in the java.util package.

Here is the source I am using:

Reflections reflections = new Reflections("java.util");
Set<Class<?>> subtypes = reflections.getSubTypesOf(List.class);

Pretty simple, right?

It works in both IntelliJ IDEA and in Eclipse, but is not working when I run my tests via Maven. I tried adding things using the org.reflections.util.ConfigurationBuilder's provided methods for adding URLs and filtering on package names with no luck.

Any suggestions?

I looked through this post but was not able to get things working: "Unit test using the Reflections google library fails only when executed by Maven"

Code

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>ohno</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>org.reflections</groupId>
      <artifactId>reflections</artifactId>
      <version>0.9.10</version>
    </dependency>

    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.9.10</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Sample.java

package com.example.uhoh;

import org.reflections.Reflections;
import java.util.Set;

public class Sample {

  @SuppressWarnings ("unchecked")
  public static Set<Class<?>> lookup(Class<?> type) {
    Reflections reflections = new Reflections("java.util");
    return (Set<Class<?>>) reflections.getSubTypesOf(type);
  }
}

SampleTest.java

package com.example.uhoh;

import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.List;
import java.util.Set;

@Test
public class SampleTest {

  public void testSample() {
    Set<Class<?>> result = Sample.lookup(List.class);
    Assert.assertNotNull(result, "NULL returned.");
    Assert.assertFalse(result.isEmpty(), "Unable to find any extensions of java.util.List");
  }
}

Output

Working in IDE Sample Working in IDE

Maven Output

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.example.uhoh.SampleTest
Configuring TestNG with: org.apache.maven.surefire.testng.conf.TestNG652Configurator@4e515669
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.261 sec <<< FAILURE!
(com.example.uhoh.SampleTest)  Time elapsed: 0.071 sec  <<< FAILURE!
java.lang.AssertionError: Unable to find any extensions of java.util.List expected [false] but found [true]
    at org.testng.Assert.fail(Assert.java:94)
    at org.testng.Assert.failNotEquals(Assert.java:513)
    at org.testng.Assert.assertFalse(Assert.java:63)
    at com.example.uhoh.SampleTest.testSample(SampleTest.java:15)


Results :

Failed tests:   (com.example.uhoh.SampleTest): Unable to find any extensions of java.util.List expected [false] but found [true]

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

Parallel Error

Code public void testSample() { Class[] dataTypes = { ArrayList.class, LinkedList.class, List.class, AbstractList.class, Collection.class, Map.class, Properties.class };

  Arrays.stream(dataTypes).parallel().forEach(next -> {
    Set<Class<?>> result = Sample.lookup(next);
    Assert.assertNotNull(result, "NULL returned.");
    Assert.assertFalse(result.isEmpty(), "Unable to find any extensions of java.util.List");
  });
}

Maven Output

java.lang.IllegalStateException: java.lang.IllegalStateException: zip file closed

Community
  • 1
  • 1
el n00b
  • 1,957
  • 7
  • 37
  • 64

2 Answers2

7

I just encountered the same problem with Reflections library (version 0.9.11), only when executing unit tests from Maven builds. A simple POM file change to my Surefire plugin fixed this for me.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.21.0</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.21.0</version>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

The <useSystemClassLoader> config parameter defaults to 'true'. Forcing it to 'false' seems to resolve the classloader problem in my unit tests.

Jim Tough
  • 14,843
  • 23
  • 75
  • 96
2

To fix your issue, use Reflections' ConfigurationBuilder to manually set the URL for the jar that contains the class. This works in IntelliJ, and when invoking the Surefire plugin using command line Maven, mvn test.

Sample.java

public static Set<Class<?>> lookup(Class<?> type) {
    ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();

    // For List.class, this will be a path to rt.jar.
    configurationBuilder.addUrls(ClasspathHelper.forClass(type));

    Reflections reflections = new Reflections(configurationBuilder);
    return (Set<Class<?>>) reflections.getSubTypesOf(type);
}
ck1
  • 5,243
  • 1
  • 21
  • 25
  • Using a parallel stream to test this, I get “_java.lang.IllegalStateException: zip file closed_”. The code I used is added above - removing `parallel()` works. What you provided is most certainly the answer to the root problem. – el n00b Jul 10 '16 at 12:39