You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查找Java中指定类所使用的全部类?(xStream白名单场景)

解决XStream白名单依赖类扫描不全的问题

替代Reflections的可行方案

1. 基于ASM字节码解析精准扫描

直接解析目标类的字节码,递归遍历字段、方法参数/返回值、泛型类型,能完整获取所有关联类:

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Type;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class ClassDependencyScanner {
    private final Set<String> dependencies = new HashSet<>();

    public Set<String> scan(String className) throws IOException {
        ClassReader cr = new ClassReader(className);
        cr.accept(new ClassVisitor(org.objectweb.asm.Opcodes.ASM9) {
            @Override
            public void visitField(int access, String name, String desc, String signature, Object value) {
                String type = Type.getType(desc).getClassName();
                addAndScan(type);
                super.visitField(access, name, desc, signature, value);
            }

            @Override
            public void visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
                // 处理方法参数和返回值
                Type[] argTypes = Type.getArgumentTypes(desc);
                for (Type t : argTypes) {
                    addAndScan(t.getClassName());
                }
                Type returnType = Type.getReturnType(desc);
                addAndScan(returnType.getClassName());
                // 解析泛型签名
                if (signature != null) {
                    parseGenericSignature(signature);
                }
                super.visitMethod(access, name, desc, signature, exceptions);
            }
        }, ClassReader.SKIP_DEBUG);
        return dependencies;
    }

    private void addAndScan(String className) throws IOException {
        if (className.startsWith("java.") || dependencies.contains(className)) {
            return;
        }
        dependencies.add(className);
        scan(className);
    }

    private void parseGenericSignature(String signature) {
        int start = signature.indexOf('L');
        while (start != -1) {
            int end = signature.indexOf(';', start);
            if (end != -1) {
                String type = signature.substring(start + 1, end).replace('/', '.');
                try {
                    addAndScan(type);
                } catch (IOException e) {
                    // 忽略无法加载的类
                }
            }
            start = signature.indexOf('L', end);
        }
    }
}

该方案直接读取类结构信息,不会遗漏字段、方法关联类及泛型参数中的类型。

2. 借助XStream运行时跟踪捕获类

利用XStream自身的反序列化逻辑,通过扩展转换器捕获实际用到的类:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import java.util.HashSet;
import java.util.Set;

public class TypeTrackingConverter implements Converter {
    private final Set<Class<?>> trackedTypes = new HashSet<>();
    private final Converter delegate;

    public TypeTrackingConverter(Converter delegate) {
        this.delegate = delegate;
    }

    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        trackedTypes.add(source.getClass());
        delegate.marshal(source, writer, context);
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        Class<?> type = context.getRequiredType();
        trackedTypes.add(type);
        Object result = delegate.unmarshal(reader, context);
        return result;
    }

    @Override
    public boolean canConvert(Class<?> type) {
        return delegate.canConvert(type);
    }

    public Set<Class<?>> getTrackedTypes() {
        return trackedTypes;
    }
}

使用方式:

XStream xStream = new XStream();
TypeTrackingConverter trackingConverter = new TypeTrackingConverter(xStream.getConverterLookup().lookupConverterForType(YourTargetClass.class));
xStream.registerConverter(trackingConverter);
// 用测试XML执行反序列化
xStream.fromXML(yourTestXml);
// 获取所有实际用到的类
Set<Class<?>> requiredTypes = trackingConverter.getTrackedTypes();

这种方法完全贴合XStream的反序列化流程,能精准捕获真正需要的类,避免扫描未被使用的依赖。

Reflections失效的常见排查点

如果坚持使用Reflections,检查以下内容:

  • 确认扫描路径覆盖所有相关模块的classpath,大型项目多模块容易遗漏
  • 开启泛型、内部类的扫描支持,调整配置:
    new Reflections(new ConfigurationBuilder()
        .setScanners(new SubTypesScanner(false), new TypeAnnotationsScanner(), new FieldAnnotationsScanner())
        .setUrls(ClasspathHelper.forPackage("your.target.package")))
    
  • 动态生成类(如CGLIB代理类)编译期不存在,Reflections无法扫描,只能通过运行时跟踪获取

内容的提问来源于stack exchange,提问作者nikowla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 16:01:01