View Javadoc
1   package top.infra.test.classloader.exclude;
2   
3   import com.google.common.collect.ImmutableList;
4   
5   import lombok.extern.slf4j.Slf4j;
6   
7   import java.net.URL;
8   import java.net.URLClassLoader;
9   import java.util.Collection;
10  
11  /**
12   * see: https://medium.com/@davehagler/junit-testrunner-with-a-custom-classloader-337d447dba4f
13   */
14  @Slf4j
15  public class ExcludeClassesClassLoader extends URLClassLoader {
16  
17      private final ClassLoader parentClassLoader;
18      private Collection<String> excludes;
19  
20      public ExcludeClassesClassLoader(
21          final ClassLoader parentClassLoader, final URL[] urls, final Collection<String> excludes) {
22  
23          super(urls, null);
24  
25          log.info("ExcludeClassesClassLoader parentClassLoader " + parentClassLoader);
26  
27          this.setExcludes(excludes);
28          this.parentClassLoader = parentClassLoader;
29      }
30  
31      @Override
32      public synchronized Class<?> loadClass(final String name) throws ClassNotFoundException {
33          //log.info("loadClass " + name);
34  
35          if (!this.excludes.contains(name)) {
36              // User's test class is already loaded by parentClassLoader
37              // Must use parentClassLoader to load top.infra.test.classloader.exclude.ExcludeClasses.
38              if (!name.startsWith("java.")
39                  && !name.startsWith("javax.")
40                  && !name.startsWith("org.junit.")
41                  && !name.startsWith("org.xml.")
42                  && !name.startsWith("org.w3c.")
43                  && !name.startsWith("sun.")
44                  && !"top.infra.test.classloader.exclude.ExcludeClasses".equals(name)
45              ) {
46                  final Class<?> result;
47                  final Class<?> loadedClass = this.findLoadedClass(name);
48                  if (loadedClass == null) {
49                      result = this.findClass(name);
50                  } else {
51                      result = loadedClass;
52                  }
53                  return result;
54              }
55  
56              return this.parentClassLoader.loadClass(name);
57          } else {
58              throw new ClassNotFoundException("class " + name + " is excluded from classpath");
59          }
60      }
61  
62      public void setExcludes(final Collection<String> excludes) {
63          this.excludes = excludes != null ? excludes : ImmutableList.of();
64      }
65  }