All Downloads are FREE. Search and download functionalities are using the official Maven repository.

name.remal.reflection.ExtendedURLClassLoader Maven / Gradle / Ivy

The newest version!
package name.remal.reflection;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import static name.remal.reflection.ExtendedURLClassLoader.LoadingOrder.*;

public class ExtendedURLClassLoader extends URLClassLoader {

    static {
        ClassLoader.registerAsParallelCapable();
    }

    public enum LoadingOrder {
        PARENT_FIRST, THIS_FIRST, PARENT_ONLY, THIS_ONLY;
    }

    @FunctionalInterface
    public interface LoadingOrderFactory {
        @Nonnull
        LoadingOrder getLoadingOrder(@Nonnull String className);
    }

    @Nonnull
    private final LoadingOrderFactory loadingOrderFactory;

    public ExtendedURLClassLoader(@Nonnull LoadingOrderFactory loadingOrderFactory, @Nonnull URL[] urls, @Nullable ClassLoader parent) {
        super(urls, null != parent ? parent : getSystemClassLoader());
        this.loadingOrderFactory = loadingOrderFactory;
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrder loadingOrder, @Nonnull URL[] urls, @Nullable ClassLoader parent) {
        this(__ -> loadingOrder, urls, parent);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrderFactory loadingOrderFactory, @Nonnull Iterable urls, @Nullable ClassLoader parent) {
        this(loadingOrderFactory, iterableUrlsToArray(urls), parent);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrder loadingOrder, @Nonnull Iterable urls, @Nullable ClassLoader parent) {
        this(__ -> loadingOrder, urls, parent);
    }

    public ExtendedURLClassLoader(@Nonnull URL[] urls, @Nullable ClassLoader parent) {
        this(PARENT_FIRST, urls, parent);
    }

    public ExtendedURLClassLoader(@Nonnull Iterable urls, @Nullable ClassLoader parent) {
        this(PARENT_FIRST, urls, parent);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrderFactory loadingOrderFactory, @Nonnull URL[] urls) {
        this(loadingOrderFactory, urls, null);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrder loadingOrder, @Nonnull URL[] urls) {
        this(loadingOrder, urls, null);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrderFactory loadingOrderFactory, @Nonnull Iterable urls) {
        this(loadingOrderFactory, urls, null);
    }

    public ExtendedURLClassLoader(@Nonnull LoadingOrder loadingOrder, @Nonnull Iterable urls) {
        this(loadingOrder, urls, null);
    }

    public ExtendedURLClassLoader(@Nonnull URL[] urls) {
        this(urls, null);
    }

    public ExtendedURLClassLoader(@Nonnull Iterable urls) {
        this(urls, null);
    }

    @Nonnull
    @Override
    public Class loadClass(@Nonnull String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    @Nonnull
    @Override
    protected Class loadClass(@Nonnull String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class loadedClass = findLoadedClass(name);

            if (null == loadedClass) loadedClass = findSystemClassOrNull(name);

            if (null == loadedClass) {
                LoadingOrder loadingOrder = loadingOrderFactory.getLoadingOrder(name);
                if (PARENT_FIRST == loadingOrder) {
                    loadedClass = findParentClassOrNull(name);
                    if (null == loadedClass) loadedClass = findClassOrNull(name);
                } else if (THIS_FIRST == loadingOrder) {
                    loadedClass = findClassOrNull(name);
                    if (null == loadedClass) loadedClass = findParentClassOrNull(name);
                } else if (PARENT_ONLY == loadingOrder) {
                    loadedClass = findParentClassOrNull(name);
                } else if (THIS_ONLY == loadingOrder) {
                    loadedClass = findClassOrNull(name);
                } else {
                    throw new IllegalStateException("Unsupported " + LoadingOrder.class.getSimpleName() + ": " + loadingOrder);
                }
            }

            if (null == loadedClass) throw new ClassNotFoundException(name);

            if (resolve) resolveClass(loadedClass);

            return loadedClass;
        }
    }

    @Nullable
    protected Class findSystemClassOrNull(@Nonnull String className) {
        try {
            return findSystemClass(className);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    @Nullable
    protected Class findClassOrNull(@Nonnull String className) {
        try {
            Class loadedClass = findClass(className);
            return loadedClass;
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    @Nullable
    protected Class findParentClassOrNull(@Nonnull String className) {
        ClassLoader parent = getParent();
        if (null == parent) return null;
        try {
            Class loadedClass = parent.loadClass(className);
            return loadedClass;
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    @Nonnull
    private static URL[] iterableUrlsToArray(@Nonnull Iterable urls) {
        if (urls instanceof List) return ((List) urls).toArray(new URL[0]);
        List list = new ArrayList<>();
        for (URL url : urls) list.add(url);
        return list.toArray(new URL[0]);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy