[英]How to find interfaces with specified annotation using ClassPathScanningCandidateComponentProvider?
I try to replace org.reflections:reflections library by org.springframework:spring-context and ClassPathScanningCandidateComponentProvider
because reflections library has a bug that is critical for me.我尝试用 org.springframework:spring-context 和ClassPathScanningCandidateComponentProvider
替换 org.reflections:reflections 库,因为反射库有一个对我来说至关重要的错误。 I want to find all classes, interfaces and subclasses that contain specific annotation.我想找到所有包含特定注释的类、接口和子类。 It was easy in reflections:反思很容易:
var subTypeScanner = new SubTypesScanner( true );
var typeAnnotationScanner = new TypeAnnotationsScanner();
var configBuilder = new ConfigurationBuilder().setUrls( ClasspathHelper.forPackage( "com.example" ) )
.setScanners( subTypeScanner, typeAnnotationScanner );
Reflections reflections= new Reflections( configBuilder );
Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Path.class);
Unfortunately it is not easy for me using ClassPathScanningCandidateComponentProvider
.不幸的是,使用ClassPathScanningCandidateComponentProvider
对我来说并不容易。 I have made workaround to find subclasses.我已经解决了寻找子类的方法。 First I find set of classes and after that I search for subclasses separately for each class:首先,我找到一组类,然后分别为每个 class 搜索子类:
protected Set< Class< ? > > findClasses( ClassPathScanningCandidateComponentProvider aScanner )
{
return aScanner.findCandidateComponents( "com.example" )
.stream()
.map( BeanDefinition::getBeanClassName )
.map( e -> {
try
{
return Class.forName( e );
}
catch( ClassNotFoundException aE )
{
throw new RuntimeException( aE );
}
} )
.collect( Collectors.toUnmodifiableSet() );
}
protected Set< Class< ? > > findSubClasses( Set< Class< ? > > aClasses )
{
return aClasses.stream()
.map( aClass -> {
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider( false );
scanner.addIncludeFilter( new AssignableTypeFilter( aClass ) );
return scanner.findCandidateComponents( "com.example" );
} )
.flatMap(Collection::stream)
.map( BeanDefinition::getBeanClassName )
.map( e -> {
try
{
return Class.forName( e );
}
catch( ClassNotFoundException aE )
{
throw new RuntimeException( aE );
}
} )
.collect( Collectors.toUnmodifiableSet() );
}
Unfortunately I do not know how to find interfaces with annotation.不幸的是,我不知道如何找到带有注释的接口。 Following code does not finds interfaces.以下代码找不到接口。 It only finds classes that has Path
annotation or extends class or implements interface that has Path
annotation.它只查找具有Path
注释或扩展 class 或实现具有Path
注释的接口的类。
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider( false );
scanner.addIncludeFilter( new AnnotationTypeFilter( Path.class, true, true ) );
Set<Class<?>> classes = findClasses(scanner);
//findSubClasses(findClasses( scanner ))
How to find interfaces with Path
annotation?如何找到带有Path
注释的接口?
The current implementation is also clear as mentioned on method level docs当前的实现也很清楚,如方法级别文档中所述
The default implementation checks whether the class is not an interface and not dependent on an enclosing class.默认实现检查 class 是否不是接口并且不依赖于封闭的 class。
As per this github issue we can fix this by overridden behaviour of isCandidateComponent()
method根据这个 github 问题,我们可以通过覆盖isCandidateComponent()
方法的行为来解决这个问题
Here is the sample reference working code from the github issue这是来自 github 问题的示例参考工作代码
provider = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) || beanDefinition.getMetadata().isAbstract();
}
};
Annotation注解
package in.silentsudo.classpathannotationscanner.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyCustomAnnotation {
}
My Simple interface我的简单界面
package in.silentsudo.classpathannotationscanner;
import in.silentsudo.classpathannotationscanner.annotation.MyCustomAnnotation;
@MyCustomAnnotation
public interface SimpleInterface {
}
Sample test code示例测试代码
package in.silentsudo.classpathannotationscanner;
import in.silentsudo.classpathannotationscanner.annotation.MyCustomAnnotation;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RestController
@RequestMapping("/list")
public class SampleController {
private final ClassPathScanningCandidateComponentProvider provider;
SampleController() {
provider = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) || beanDefinition.getMetadata().isAbstract();
}
};
provider.addIncludeFilter(new AnnotationTypeFilter(MyCustomAnnotation.class, true, true));
}
@GetMapping
public Map<String, Object> list() throws Exception {
return Map.of("mycustomannotationsmarkedinterafce", getData());
}
public List<String> getData() throws Exception {
final Set<BeanDefinition> classes = provider.findCandidateComponents("in.silentsudo.classpathannotationscanner");
List<String> names = new ArrayList<>();
for (BeanDefinition bean : classes) {
Class<?> clazz = Class.forName(bean.getBeanClassName());
names.add(clazz.getName());
}
return names;
}
}
This should give following response:这应该给出以下响应:
{
"mycustomannotationsmarkedinterafce": [
"in.silentsudo.classpathannotationscanner.SimpleInterface"
]
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.