-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🐛 fix #1030 The Spring Boot jar fails to run when using @AiServic… #20
base: main
Are you sure you want to change the base?
Conversation
…e to Reflections[0.10.2]
Hi @clear2x almost all tests in |
Sorry, I have already fixed it. |
I found that the |
return reflections.getTypesAnnotatedWith(AiService.class); | ||
Reflections reflections = new Reflections((new ConfigurationBuilder()).forPackage(basePackage)); | ||
Set<Class<?>> classes = reflections.getTypesAnnotatedWith(AiService.class); | ||
classes.removeIf(clazz -> !clazz.getName().startsWith(basePackage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something fishy is going on... Why is filtering required? Why does getTypesAnnotatedWith
return all classes, even if we specify basePackage
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forPackage(basePackage));
This code calls the following piece of code :
public static Collection<URL> forResource(String resourceName, ClassLoader... classLoaders) {
final List<URL> result = new ArrayList<>();
final ClassLoader[] loaders = classLoaders(classLoaders);
for (ClassLoader classLoader : loaders) {
try {
final Enumeration<URL> urls = classLoader.getResources(resourceName);
while (urls.hasMoreElements()) {
final URL url = urls.nextElement();
int index = url.toExternalForm().lastIndexOf(resourceName);
if (index != -1) {
// Add old url as contextUrl to support exotic url handlers
result.add(new URL(url, url.toExternalForm().substring(0, index)));
} else {
result.add(url);
}
}
} catch (IOException e) {
if (Reflections.log != null) {
Reflections.log.error("error getting resources for " + resourceName, e);
}
}
}
return distinctUrls(result);
}
where the key part is:
int index = url.toExternalForm().lastIndexOf(resourceName);
if (index != -1) {
// Add old url as contextUrl to support exotic url handlers
result.add(new URL(url, url.toExternalForm().substring(0, index)));
} else {
result.add(url);
}
This segment extracts a part of the URL, and after extraction, it becomes test-classes.
Our goal is to find all AI Services under the base package and its sub-packages, so we perform filtering here .
A few other thoughts...... "In jar files, Reflections cannot scan classes." This issue has been discussed extensively in the link above. We might also consider not relying on Reflections and directly using Spring's related methods to achieve our goal. |
@clear2x instead of Reflections, which spring methods can be used? I tried to use some, but they ignore interfaces |
ResourcePatternResolver, PathMatchingResourcePatternResolver, StandardEnvironment, and SimpleMetadataReaderFactory can work together to achieve our goal. public class AnnotationUtils extends org.springframework.core.annotation.AnnotationUtils {
private static final PathMatchingResourcePatternResolver RESOLVER = new PathMatchingResourcePatternResolver();
private static final SimpleMetadataReaderFactory REGISTER = new SimpleMetadataReaderFactory();
private static final StandardEnvironment ENVIRONMENT = new StandardEnvironment();
public static String getResourcePath(String packagePath) {
if (StringUtils.isEmpty(packagePath)) {
return "";
}
return ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(ENVIRONMENT.resolveRequiredPlaceholders(packagePath))
+ '/' + "**/*.class";
}
public static Set<Class<?>> getClazzFromAnnotation(String pkgPath, Class<? extends Annotation> annoClazz) {
String pathPackage = getResourcePath(pkgPath);
log.info("pathPackage: {}", pathPackage);
Set<Class<?>> paths = new HashSet<>();
Resource[] resources;
try {
resources = RESOLVER.getResources(pathPackage);
} catch (IOException e) {
return new HashSet<>();
}
for (Resource resource : resources) {
MetadataReader metadataReader = null;
try {
metadataReader = REGISTER.getMetadataReader(resource);
} catch (IOException e) {
continue;
}
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
if (!annotationMetadata.hasAnnotation(annoClazz.getName())) {
continue;
}
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = classLoader.loadClass(className);
paths.add(clazz);
} catch (ClassNotFoundException e) {
log.warn(e.getMessage());
}
}
return paths;
}
}
|
The Spring Boot jar fails to run when using @aiservice due to Reflections[0.10.2]
Relevant Links: