简体   繁体   中英

How to load same class by custom classloader twice in Maven project with JUnit

I did stackoverflowing like a mad two hours but nothing helped so far.

I have very very basic Maven project where I have some Singleton class. There is said that it is possible to load singleton twice with different classloaders so I wrote my own but the issue is that I am not able to load that class because I am getting ClassNotFoundException but I do not have a clue why.

@RunWith(JUnit4.class)
public class SingletonClassLoadedDifferentClassLoadersTestCase {

    static class SingletonClassLoader extends ClassLoader {

        @Override
        public Class<?> loadClass(String className)
          throws ClassNotFoundException {
            try {
                InputStream is =
                    // seems to be the central problem 
                    ClassLoader.getSystemResourceAsStream(className);
                if (is == null) {
                    throw new ClassNotFoundException();
                }

                ByteArrayOutputStream buffer = new ByteArrayOutputStream();

                int nRead;
                byte[] data = new byte[1024];

                while ((nRead = is.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }

                byte[] classBytes = buffer.toByteArray();

                return defineClass(className, classBytes, 0, classBytes.length);
            } catch (IOException ex) {
                throw new ClassNotFoundException();
            }
        }
    }

    @Test
    public void singletonTest() throws Exception {
        Class<?> singleton1 = new SingletonClassLoader()
            .loadClass("SingletonLazy");
        Class<?> singleton2 = new SingletonClassLoader()
            .loadClass("SingletonLazy");
    }
}

SingletonLazy is just a class in src/main/java (burried in some package directory). It seems that ClassLoader is unable to find that class but why? I see that it is not in target/test-classes . How do I tell Maven to somehow put that class in src/main/java/some/package/SingletonLazy.java on classpath while I do tests? I am executing it from the command line like mvn clean test

Thank you for any hint!

Don't use SystemClassLoader. Use the immediate classloader instead. Change your code to,

InputStream is = SingletonClassLoadedDifferentClassLoadersTestCase.class
      .getClassLoader()
      .getResourceAsStream(className);

I believe JUnit creates a separate classloader for each test. I was under impression that JUnit is doing that to avoid the issues created by static state. I tried a few tests and I can see that it is not the case! Even if you have a class defined in src/test/java its static state is not erased, that is class is not reloaded per test.

Second thing I tried was to fork tests, but <forkMode>always</forkMode> which i believe highest level of forking works for only tests defined in two different test classes. If you have tests methods defined in the same class, all the test method runs will use the same JVM instance.

Statics are inherently bad so I would recommend using an Inversion of Control (IOC) framework. I have used Guice in past and its very lightweight and efficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM