FsLoader.java

package space.sunqian.common;

import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.Nullable;
import space.sunqian.common.base.enums.EnumKit;
import space.sunqian.common.base.exception.UnknownTypeException;
import space.sunqian.common.base.system.JvmKit;
import space.sunqian.common.reflect.ClassKit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Loader for implementations of this lib.
 *
 * @author sunqian
 */
public class FsLoader {

    /**
     * This method is used to load the corresponding version of service implementation based on the currently running
     * JVM platform for this lib.
     * <p>
     * This is a lib-internal method.
     *
     * @param serviceClass the service class
     * @param highVersion  the high version
     * @param <T>          the service type
     * @return the corresponding version of service implementation
     */
    public static <T> @Nonnull T loadImplByJvm(
        @Nonnull Class<T> serviceClass, int highVersion
    ) throws UnknownTypeException {
        int majorVersion = JvmKit.javaMajorVersion();
        String className;
        if (majorVersion > 8) {
            className = serviceClass.getName() + "ImplByJ" + highVersion;
            T ret = loadImplByJvm(className);
            if (ret != null) {
                return ret;
            }
        }
        className = serviceClass.getName() + "Impl";
        T ret = loadImplByJvm(className);
        if (ret != null) {
            return ret;
        }
        throw new UnknownTypeException(className);
    }

    private static <T> @Nullable T loadImplByJvm(String classImplName) {
        Class<?> cls = ClassKit.classForName(classImplName);
        Enum<?> enumObj = EnumKit.findEnum(Fs.as(cls), "INST");
        return Fs.as(enumObj);
    }

    /**
     * This method is used to load a class that depends on another class.
     * <p>
     * This is a lib-internal method.
     *
     * @param className          the name of the class that needs to be loaded
     * @param dependentClassName the name of the dependent class
     * @return the loaded class
     */
    public static @Nullable Class<?> loadClassByDependent(
        @Nonnull String className, @Nonnull String dependentClassName
    ) {
        Class<?> dependentClass = ClassKit.classForName(dependentClassName);
        if (dependentClass == null) {
            return null;
        }
        return ClassKit.classForName(className);
    }

    /**
     * This method is used to load the given objects. If the object is {@link Class}, loads it to an instance, else
     * loads the object itself. The {@code null} elements and {@code null} instanced (if loading fails) will be
     * ignored.
     * <p>
     * This is a lib-internal method.
     *
     * @param classesOrInstances the objects array that need to be loaded
     * @param <T>                the type of the instances
     * @return the instances
     */
    public static <T> @Nonnull List<@Nonnull T> loadInstances(@Nullable Object @Nonnull ... classesOrInstances) {
        ArrayList<T> list = new ArrayList<>(classesOrInstances.length);
        for (Object obj : classesOrInstances) {
            if (obj == null) {
                continue;
            }
            if (obj instanceof Class<?>) {
                Class<?> cls = (Class<?>) obj;
                Object o = ClassKit.newInstance(cls);
                if (o != null) {
                    list.add(Fs.as(o));
                }
            } else {
                list.add(Fs.as(obj));
            }
        }
        list.trimToSize();
        return Collections.unmodifiableList(list);
    }

    private FsLoader() {
    }
}