This is an automated email from the ASF dual-hosted git repository.
nvazquez pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.22 by this push:
new d4f5dff7311 Fix overly broad classpath scanning in
ReflectUtil.getClassesWithAnnotation() (#13427)
d4f5dff7311 is described below
commit d4f5dff7311bdb6a7fb6174b8eddb705a8e0eac5
Author: Vishesh <[email protected]>
AuthorDate: Wed Oct 7 00:41:44 2026 +0530
Fix overly broad classpath scanning in
ReflectUtil.getClassesWithAnnotation() (#13427)
* Fix overly broad classpath scanning in
ReflectUtil.getClassesWithAnnotation()
Production logs show a recurring WARN at startup:
"could not get type for name org.conscrypt.AllocatedBuffer"
(org.reflections.ReflectionsException / ClassNotFoundException)
Root cause: ReflectUtil.getClassesWithAnnotation() uses
ClasspathHelper.forPackage() to collect URLs to scan, but this
returns all classpath entries (JARs/directories), not just those
containing the target package. The Reflections library then scans
every .class file in every JAR — including Netty's
ConscryptAlpnSslEngine$BufferAdapter which references the optional
org.conscrypt.AllocatedBuffer type. During expandSuperTypes(),
Reflections tries Class.forName() on that type and fails because
Conscrypt is not (and need not be) on the classpath.
The fix adds a FilterBuilder that restricts bytecode scanning to
only classes whose fully-qualified names match the requested
packages. This prevents Reflections from processing unrelated
classes (e.g., io.netty.handler.ssl.*), eliminating the warning
and reducing startup time by skipping thousands of irrelevant
class files.
Signed-off-by: Ganesh Maharaj Mahalingam <[email protected]>
* Add missing API command packages to ApiXmlDocWriter's classpath scan list
---------
Signed-off-by: Ganesh Maharaj Mahalingam <[email protected]>
Co-authored-by: Ganesh Maharaj Mahalingam <[email protected]>
---
server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java | 5 ++++-
utils/src/main/java/com/cloud/utils/ReflectUtil.java | 4 ++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
b/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
index b1bb316471b..0495a41e36a 100644
--- a/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
+++ b/server/src/main/java/com/cloud/api/doc/ApiXmlDocWriter.java
@@ -92,7 +92,10 @@ public class ApiXmlDocWriter {
public static void main(String[] args) {
Set<Class<?>> cmdClasses =
ReflectUtil.getClassesWithAnnotation(APICommand.class, new String[]
{"org.apache.cloudstack.api", "com.cloud.api",
"com.cloud.api.commands", "com.globo.globodns.cloudstack.api",
"org.apache.cloudstack.network.opendaylight.api",
- "org.apache.cloudstack.api.command.admin.zone",
"org.apache.cloudstack.network.contrail.api.command"});
+ "org.apache.cloudstack.api.command.admin.zone",
"org.apache.cloudstack.network.contrail.api.command",
+ "org.apache.cloudstack.cloudian.api",
"org.apache.cloudstack.framework.extensions.api",
+ "org.apache.cloudstack.mom.webhook.api.command.user",
"org.apache.cloudstack.network.tungsten.api.command",
+ "org.apache.cloudstack.oauth2.api.command",
"org.apache.cloudstack.storage.datastore.util"});
for (Class<?> cmdClass : cmdClasses) {
if(cmdClass.getAnnotation(APICommand.class)==null){
diff --git a/utils/src/main/java/com/cloud/utils/ReflectUtil.java
b/utils/src/main/java/com/cloud/utils/ReflectUtil.java
index 5b40d48c20e..bf11cea22cc 100644
--- a/utils/src/main/java/com/cloud/utils/ReflectUtil.java
+++ b/utils/src/main/java/com/cloud/utils/ReflectUtil.java
@@ -42,6 +42,7 @@ import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
+import org.reflections.util.FilterBuilder;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.collect.ImmutableSet;
@@ -70,9 +71,12 @@ public class ReflectUtil {
Reflections reflections;
Set<Class<?>> classes = new HashSet<Class<?>>();
ConfigurationBuilder builder=new ConfigurationBuilder();
+ FilterBuilder filterBuilder = new FilterBuilder();
for (String packageName : packageNames) {
builder.addUrls(ClasspathHelper.forPackage(packageName));
+ filterBuilder.includePackage(packageName);
}
+ builder.filterInputsBy(filterBuilder);
builder.setScanners(new SubTypesScanner(),new
TypeAnnotationsScanner());
reflections = new Reflections(builder);
classes.addAll(reflections.getTypesAnnotatedWith(annotation));