Не удается получить пользовательские аннотации из класса Java - PullRequest
1 голос
/ 29 апреля 2020

Я хочу получить аннотацию уровня класса от Java class:

    class FixAnnotation {

        public String[] author;

    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface Fix {

        public String[] author() default "";

    }

Я попробовал этот пример скомпилированного java class:

@Component("test")
@Fix(
    author = {"Example author 1", "Example author 2"}
)
public class Order implements Action {
..
}

Но когда я пытаюсь:

publi c Список listLocalFilesAndDirsAllLevels (File baseDir) {

        List<File>  collectedFilesAndDirs = new ArrayList<>();
        Deque<File> remainingDirs = new ArrayDeque<>();

        if(baseDir.exists()) {
            remainingDirs.add(baseDir);

            while(!remainingDirs.isEmpty()) {
                File dir = remainingDirs.removeLast();
                List<File> filesInDir = Arrays.asList(dir.listFiles());
                for(File fileOrDir : filesInDir)  {
                    // We need to process only .class files
                    if(fileOrDir.getName().endsWith(".class")){
                        collectedFilesAndDirs.add(fileOrDir);
                        if(fileOrDir.isDirectory()) {
                            remainingDirs.add(fileOrDir);
                        }
                    }
                }
            }
        }

        return collectedFilesAndDirs;
    }

      List<File> list;

      for(int i=0; i<list.size(); i++) {
            File item = list.get(i);
            System.out.println(item.getName());

            Fix name = item.getClass().getAnnotation(Fix.class);

            out.println("author: " + name.author());
       }

Я получаю NPE. Знаете ли вы, как я могу получить содержание аннотации?

РЕДАКТИРОВАТЬ: Я пытался это:

public static void main() throws Exception
        {    
            final File folder = new File("/opt/test");
            processAnnotatedFiles(listLocalFilesAndDirsAllLevels(folder));

        }

    public void processAnnotatedFiles(List<File> list) throws IOException, ClassNotFoundException {
        out.println("Directory files size " + list.size());

        for(int i=0; i<list.size(); i++) {
            out.println("File " + list.get(i).getName());

            File file = list.get(i);

            String path = file.getPath();

            String[] authors = getFixFromClassFile(Paths.get(path));
            System.out.println(Arrays.toString(authors));
        }

    }

    public List<File> listLocalFilesAndDirsAllLevels(File baseDir) {

        List<File>  collectedFilesAndDirs = new ArrayList<>();
        Deque<File> remainingDirs = new ArrayDeque<>();

        if(baseDir.exists()) {
            remainingDirs.add(baseDir);

            while(!remainingDirs.isEmpty()) {
                File dir = remainingDirs.removeLast();
                List<File> filesInDir = Arrays.asList(dir.listFiles());
                for(File fileOrDir : filesInDir)  {
                    // We need to process only .class files
                    if(fileOrDir.getName().endsWith(".class")){
                        collectedFilesAndDirs.add(fileOrDir);
                        if(fileOrDir.isDirectory()) {
                            remainingDirs.add(fileOrDir);
                        }
                    }
                }
            }
        }

        return collectedFilesAndDirs;
    }

    private String[] getFixFromClassFile(Path pathToClass) throws MalformedURLException, ClassNotFoundException {
        // Create class loader based on path
        URLClassLoader loader = new URLClassLoader(new URL[]{pathToClass.toUri().toURL()});

        // convert path to class with package
        String classWithPackage = getClassWithPackageFromPath(pathToClass);

        // Load class dynamically
        Class<?> clazz = loader.loadClass(classWithPackage);
        Fix fix = clazz.getAnnotation(Fix.class);
        if (fix == null) {
            return new String[0];
        }

        return fix.author();
    }

    private String getClassWithPackageFromPath(Path pathToClass) {
        final String packageStartsFrom = "com.";
        final String classFileExtension = ".class";
        final String pathWithDots = pathToClass.toString().replace(File.separator, ".");
        return pathWithDots.substring(pathWithDots.indexOf(packageStartsFrom)).replace(classFileExtension, "");
    }

Я получаю java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(String.java:1927)

1 Ответ

1 голос
/ 29 апреля 2020

Когда вы вызываете метод getClass для объекта File, он возвращает экземпляр java.io.File Class. Этот метод не загружает класс из заданного файла.

Если вы хотите загрузить класс из заданного *.class файла, вам нужно использовать реализацию java.lang.ClassLoader. Например, java.net.URLClassLoader. Ниже вы можете найти пример того, как загрузить класс и проверить аннотацию:

import java.io.File;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

@Fix(author = "Test author")
public class ReflectionApp {

    public static void main(String[] args) throws Exception {
        String path = "path/to/com/so/ReflectionApp.class";
        String[] authors = getFixFromClassFile(Paths.get(path));
        System.out.println(Arrays.toString(authors));
    }

    private static String[] getFixFromClassFile(Path pathToClass) throws MalformedURLException, ClassNotFoundException {
        // Create class loader based on path
        URLClassLoader loader = new URLClassLoader(new URL[]{pathToClass.toUri().toURL()});

        // convert path to class with package
        String classWithPackage = getClassWithPackageFromPath(pathToClass);

        // Load class dynamically
        Class<?> clazz = loader.loadClass(classWithPackage);
        Fix fix = clazz.getAnnotation(Fix.class);
        if (fix == null) {
            return new String[0];
        }

        return fix.author();
    }

    private static String getClassWithPackageFromPath(Path pathToClass) {
        final String packageStartsFrom = "com.";
        final String classFileExtension = ".class";
        final String pathWithDots = pathToClass.toString().replace(File.separator, ".");
        return pathWithDots.substring(pathWithDots.indexOf(packageStartsFrom)).replace(classFileExtension, "");
    }
}

Над отпечатками кода:

[Test author]

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...