mardi 4 janvier 2022

Class?> .isAnnotationPresent returns false for annotated class

I have my own annotation:

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

And class:

package com.ltp.analog.test;

import com.ltp.analog.core.annotation.Component;

@Component
public class TestOne {

    public void test(){
        System.out.println("TEST ONE");
    }

}

Also implemented custom ClassLoader:


package com.ltp.analog.reflection;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class AnalogClassLoader extends ClassLoader{

    @Override
    public Class findClass(String name) {
        Class cl = findLoadedClass(name);

        if(cl != null){
            return cl;
        }

        byte[] b = loadClassFromFile(name);
        return defineClass(name, b, 0, b.length);
    }

    private byte[] loadClassFromFile(String fileName)  {
        InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(
                fileName.replaceAll("[.]", "/") + ".class");
        byte[] buffer;
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        int nextValue = 0;
        try {
            while ( (nextValue = inputStream.read()) != -1 ) {
                byteStream.write(nextValue);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        buffer = byteStream.toByteArray();
        return buffer;
    }

}

And ReflectionUtils class which have to load all the classes in package recursively:

package com.ltp.analog.reflection;

import com.ltp.analog.Testing;
import com.ltp.analog.reflection.qualifier.ClassQualifier;

import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

public class ReflectionUtils {

    private static final AnalogClassLoader cl = new AnalogClassLoader();

    public static List<Class> getClassesInPackageRecursively(String packName){
        List<String> packs = getSubpackagesRecursively(packName);

        List<Class> result = new LinkedList<>();

        packs.forEach(pack -> result.addAll(getClassesInPackage(pack)));

        return result.stream().distinct().collect(Collectors.toList());
    }

    public static List<Class> getClassesInPackage(String packName){
        if(packName == null || packName.isEmpty()){
            return List.of();
        }

        URL url = ClassLoader.getSystemClassLoader().getResource(packName.replaceAll("[.]", "/"));

        if(url == null){
            return List.of();
        }

        File pack = new File(url.getPath());

        if(!pack.isDirectory() || pack.listFiles() == null){
            return List.of();
        }

        return Arrays.stream(pack.listFiles())
                .filter(File::isFile)
                .filter(f -> f.getName().endsWith(".class"))
                .map(f -> cl.findClass(packName + "." + f.getName().substring(0, f.getName().indexOf('.'))))
                .collect(Collectors.toList());
    }

    public static List<String> getSubpackagesRecursively(String packName){
        List<String> result = new LinkedList<>();

        for(String pack : getSubpackages(packName)){
            List<String> subPacks = getSubpackagesRecursively(pack);
            result.addAll(subPacks);
        }

        result.add(packName);

        return result.stream().distinct().collect(Collectors.toList());
    }

    public static List<String> getSubpackages(String packName){
        if(packName == null || packName.isEmpty()){
            return List.of();
        }

        URL url = ClassLoader.getSystemClassLoader().getResource(packName.replaceAll("[.]", "/"));

        if(url == null){
            return List.of();
        }

        File pack = new File(url.getPath());

        if(!pack.isDirectory() || pack.listFiles() == null){
            return List.of();
        }

        return Arrays.stream(pack.listFiles())
                .filter(File::isDirectory)
                .map(f -> packName + "." + f.getName())
                .collect(Collectors.toList());
    }

    private ReflectionUtils(){}

}

The problem is that after loading all the classes in the passed package I'm trying to filter them and get only annotated by @Component, but the result is weird:

someClass.isAnnotationPresent(Component.class) returns false, even when there is a @Component annotation in someClass.getDeclaredAnnotations()

Sample:

List<Class> componentClasses = new LinkedList<>();
        scans.forEach(s -> componentClasses.addAll(ReflectionUtils.getClassesInPackageRecursively(s)));
        System.out.printf("Classes: %d", componentClasses.size());
        componentClasses.forEach(c -> {
            System.out.println("-".repeat(50));
            System.out.println(Arrays.stream(c.getAnnotations()).map(Annotation::toString).collect(Collectors.joining(", ")));
            System.out.printf("%s -> %s\n", c.getName(), c.isAnnotationPresent(Component.class));
        });

The output:

...
@com.ltp.analog.core.annotation.Component()
com.ltp.analog.test.TestOne -> false
...




Aucun commentaire:

Enregistrer un commentaire