0

I want to read the annotations from .class file placed into random folder. I tried this:

            public static void main(String[] args) 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, "");
        }

I get java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(String.java:1927)

In this part I want to create a package into random dir. It is really hard to create a valid package from path because there is no any rule package names should follow.

Can you give me some advice how this can be fixed?

Peter Penzov
  • 1,126
  • 134
  • 430
  • 808
  • 2
    There is no guaranty that the qualified name contains a `com.`. Besides that, there is already a problem earlier, as the `URLClassLoader` expects the URL representing the class path entry, i.e. the root of the package structure. So you nee to identify the correct starting point even before that. – Holger Apr 29 '20 at 14:57
  • 1
    A simple solution with some limitations has been posted in [this answer](https://stackoverflow.com/a/47292026/2711488). – Holger Apr 29 '20 at 15:09
  • 1
    A full solution, extracting the qualified name from the class file itself with the minimal operations possible, working with all scenarios, is in [this answer](https://stackoverflow.com/a/52332101/2711488). – Holger Apr 29 '20 at 15:25
  • I have one idea: The project that I'm working on uses Spring. Can you show me a solution with classes in classpath by getting ApplicationContext.getResources("classpath*:/**/*.class")? Is this possible? – Peter Penzov Apr 29 '20 at 15:31
  • 1
    You want to scan the existing classes, e.g. something like [this](https://stackoverflow.com/a/36021165/2711488)? Or `getResources("/")` to get the roots, then traverse… – Holger Apr 29 '20 at 15:36
  • Is there any other solution to load a class? I can't make it work. – Peter Penzov Apr 30 '20 at 06:37
  • 1
    You should spent some time for explaining what you are actually trying to do. So the classes *are* on the class path (or in general loadable in the current environment) and you just want to discover them? Or do you want to scan a directory outside any class path? Further, it would be helpful to know which approach you tried and what problem you encountered. – Holger Apr 30 '20 at 07:05
  • Here is the complete code: https://pastebin.com/KbBAZVfB I get java.lang.ClassNotFoundException: Order.class – Peter Penzov Apr 30 '20 at 07:09
  • 1
    Don’t pass `file.getName()` as `predictedName` argument. They key point is to pass a `predictedName` when you know the base directory. Otherwise pass `null`. The expression `file.getName()` will evaluate to `"Order.class"` which obviously is not the name of the class, hence you get `ClassNotFoundException: Order.class`. – Holger Apr 30 '20 at 07:18
  • 1
    But, as said, you really should explain your actual goal rather than your solution attempts. See also [What is the XY problem?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem/66378#66378) – Holger Apr 30 '20 at 07:20
  • The goal is to load any .class file and read the class annotations. Can you show me please fixed version of the code? – Peter Penzov Apr 30 '20 at 07:26

0 Answers0