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

io.github.sinri.keel.helper.KeelReflectionHelper Maven / Gradle / Ivy

Go to download

A website framework with VERT.X for ex-PHP-ers, exactly Ark Framework Users.

The newest version!
package io.github.sinri.keel.helper;


import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static io.github.sinri.keel.facade.KeelInstance.Keel;

/**
 * @since 2.6
 */
public class KeelReflectionHelper {
    private static final KeelReflectionHelper instance = new KeelReflectionHelper();

    private KeelReflectionHelper() {

    }

    static KeelReflectionHelper getInstance() {
        return instance;
    }

    /**
     * @param  class of target annotation
     * @return target annotation
     * @since 1.13
     */
    @Nullable
    public  T getAnnotationOfMethod(@Nonnull Method method, @Nonnull Class classOfAnnotation, @Nullable T defaultAnnotation) {
        T annotation = method.getAnnotation(classOfAnnotation);
        if (annotation == null) {
            return defaultAnnotation;
        }
        return annotation;
    }

    /**
     * @since 2.6
     */
    @Nullable
    public  T getAnnotationOfMethod(@Nonnull Method method, @Nonnull Class classOfAnnotation) {
        return getAnnotationOfMethod(method, classOfAnnotation, null);
    }

    /**
     * @return Returns this element's annotation for the specified type if such an annotation is present, else null.
     * @throws NullPointerException – if the given annotation class is null
     *                              Note that any annotation returned by this method is a declaration annotation.
     * @since 2.8
     */
    @Nullable
    public  T getAnnotationOfClass(@Nonnull Class anyClass, @Nonnull Class classOfAnnotation) {
        return anyClass.getAnnotation(classOfAnnotation);
    }

    /**
     * @since 3.1.8
     * For the repeatable annotations.
     */
    @Nonnull
    public  T[] getAnnotationsOfClass(@Nonnull Class anyClass, @Nonnull Class classOfAnnotation) {
        return anyClass.getAnnotationsByType(classOfAnnotation);
    }

    /**
     * @param packageName In this package
     * @param baseClass   seek any class implementations of this class
     * @param          the target base class to seek its implementations
     * @return the sought classes in a set
     * @since 3.0.6
     * @since 3.2.12.1 rewrite
     */
    public  Set> seekClassDescendantsInPackage(@Nonnull String packageName, @Nonnull Class baseClass) {
//        Reflections reflections = new Reflections(packageName);
//        return reflections.getSubTypesOf(baseClass);

        Set> set = new HashSet<>();

        List classPathList = Keel.fileHelper().getClassPathList();
        for (String classPath : classPathList) {
            if (classPath.endsWith(".jar")) {
                Set> classes = seekClassDescendantsInPackageForProvidedJar(classPath, packageName, baseClass);
                set.addAll(classes);
            } else {
                Set> classes = seekClassDescendantsInPackageForFileSystem(packageName, baseClass);
                set.addAll(classes);
            }
        }

        return set;
    }

    /**
     * @since 3.2.11
     */
    protected  Set> seekClassDescendantsInPackageForFileSystem(@Nonnull String packageName, @Nonnull Class baseClass) {
        Set> descendantClasses = new HashSet<>();
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // in file system
        String packagePath = packageName.replace('.', '/');
        try {
            // Assuming classes are in a directory on the file system (e.g., not in a JAR)
            URL resource = classLoader.getResource(packagePath);
            if (resource != null) {
                URI uri = resource.toURI();
                Path startPath = Paths.get(uri);
                Files.walkFileTree(startPath, new SimpleFileVisitor() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                        if (file.toString().endsWith(".class")) {
                            String className = file.toString().replace(".class", "").replace("/", ".");
                            className = className.substring(className.indexOf(packageName));

                            try {
                                Class clazz = (Class) classLoader.loadClass(className);
                                if (baseClass.isAssignableFrom(clazz)) {
                                    descendantClasses.add(clazz);
                                }
                            } catch (Throwable e) {
                                Keel.getLogger().debug(getClass() + " seekClassDescendantsInPackageForFileSystem for " + className + " error: " + e.getMessage());
                            }
                        }
                        return FileVisitResult.CONTINUE;
                    }
                });
            }
        } catch (Exception e) {
            Keel.getLogger().exception(e);
        }
        return descendantClasses;
    }

    /**
     * @since 3.2.11
     */
    protected  Set> seekClassDescendantsInPackageForRunningJar(@Nonnull String packageName, @Nonnull Class baseClass) {
        Set> descendantClasses = new HashSet<>();
        Set strings = Keel.fileHelper().seekPackageClassFilesInRunningJar(packageName);
        for (String s : strings) {
            try {
                Class aClass = Class.forName(s);
                if (baseClass.isAssignableFrom(aClass)) {
                    descendantClasses.add((Class) aClass);
                }
            } catch (Throwable e) {
                Keel.getLogger().debug(getClass() + " seekClassDescendantsInPackageForRunningJar for " + s + " error: " + e.getMessage());
            }
        }
        return descendantClasses;
    }

    /**
     * @since 3.2.11
     */
    protected  Set> seekClassDescendantsInPackageForProvidedJar(@Nonnull String jarInClassPath, @Nonnull String packageName, @Nonnull Class baseClass) {
        Set> descendantClasses = new HashSet<>();
        List classNames = Keel.fileHelper().traversalInJarFile(new File(jarInClassPath));
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        classNames.forEach(className -> {
            if (className.startsWith(packageName + ".")) {
                try {
                    Class clazz = (Class) classLoader.loadClass(className);
                    if (baseClass.isAssignableFrom(clazz)) {
                        descendantClasses.add(clazz);
                    }
                } catch (Throwable e) {
                    Keel.getLogger().debug(getClass() + " seekClassDescendantsInPackageForProvidedJar for " + className + " error: " + e.getMessage());
                }
            }
        });
        return descendantClasses;
    }

    /**
     * @return Whether the given `baseClass` is the base of the given `implementClass`.
     * @since 3.0.10
     */
    public boolean isClassAssignable(@Nonnull Class baseClass, @Nonnull Class implementClass) {
        return baseClass.isAssignableFrom(implementClass);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy