java – 找出使用给定API的哪些类

前端之家收集整理的这篇文章主要介绍了java – 找出使用给定API的哪些类前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在我的 Java项目中,我想从程序中找出使用给定API的哪些类.有没有办法做到这一点?可以通过源代码解析或字节码解析?因为反思不会有任何用处,恐怕.

为了使事情更简单:我的项目中的任何地方都没有通配符导入(import com.mycompany.api.*;),没有完全限定字段或变量定义(private com.mycompany.api.MyThingy thingy;)也没有任何Class.forName(...)结构.鉴于这些限制,它归结为解析导入语句,我猜.是否有首选方法

解决方法

您可以使用 ASMRemapper课程(相信或不相信)发现课程.这个类实际上是为了替换字节码中所有出现的类名.但是,为了您的目的,它不需要更换任何东西.

这可能不是很有意义的,所以这里是一个例子…

首先,您创建一个Remapper子类,其唯一目的在于拦截所有调用mapType(String)方法,记录其参数供以后使用.

public class ClassNameRecordingRemapper extends Remapper {

    private final Set<? super String> classNames;

    public ClassNameRecordingRemapper(Set<? super String> classNames) {
        this.classNames = classNames;
    }

    @Override
    public String mapType(String type) {
        classNames.add(type);
        return type;
    }

}

现在你可以编写一个这样的方法

public Set<String> findClassNames(byte[] bytecode) {
    Set<String> classNames = new HashSet<String>();

    ClassReader classReader = new ClassReader(bytecode);
    ClassWriter classWriter = new ClassWriter(classReader,0);

    ClassNameRecordingRemapper remapper = new ClassNameRecordingRemapper(classNames);
    classReader.accept(remapper,0);

    return classNames;
}

实际获取所有类的字节码是您的责任.

seanizer编辑(OP)

我接受这个答案,但由于上面的代码不太正确,我将插入我使用的方式:

public static class Collector extends Remapper{

    private final Set<Class<?>> classNames;
    private final String prefix;

    public Collector(final Set<Class<?>> classNames,final String prefix){
        this.classNames = classNames;
        this.prefix = prefix;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String mapDesc(final String desc){
        if(desc.startsWith("L")){
            this.addType(desc.substring(1,desc.length() - 1));
        }
        return super.mapDesc(desc);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String[] mapTypes(final String[] types){
        for(final String type : types){
            this.addType(type);
        }
        return super.mapTypes(types);
    }

    private void addType(final String type){
        final String className = type.replace('/','.');
        if(className.startsWith(this.prefix)){
            try{
                this.classNames.add(Class.forName(className));
            } catch(final ClassNotFoundException e){
                throw new IllegalStateException(e);
            }
        }
    }

    @Override
    public String mapType(final String type){
        this.addType(type);
        return type;
    }

}

public static Set<Class<?>> getClassesUsedBy(
    final String name,// class name
    final String prefix  // common prefix for all classes
                         // that will be retrieved
    ) throws IOException{
    final ClassReader reader = new ClassReader(name);
    final Set<Class<?>> classes =
        new TreeSet<Class<?>>(new Comparator<Class<?>>(){

            @Override
            public int compare(final Class<?> o1,final Class<?> o2){
                return o1.getName().compareTo(o2.getName());
            }
        });
    final Remapper remapper = new Collector(classes,prefix);
    final ClassVisitor inner = new EmptyVisitor();
    final RemappingClassAdapter visitor =
        new RemappingClassAdapter(inner,remapper);
    reader.accept(visitor,0);
    return classes;
}

这是一个使用以下方式测试它的主要类:

public static void main(final String[] args) throws Exception{
    final Collection<Class<?>> classes =
        getClassesUsedBy(Collections.class.getName(),"java.util");
    System.out.println("Used classes:");
    for(final Class<?> cls : classes){
        System.out.println(" - " + cls.getName());
    }

}

这里是输出

Used classes:
 - java.util.ArrayList
 - java.util.Arrays
 - java.util.Collection
 - java.util.Collections
 - java.util.Collections$1
 - java.util.Collections$AsLIFOQueue
 - java.util.Collections$CheckedCollection
 - java.util.Collections$CheckedList
 - java.util.Collections$CheckedMap
 - java.util.Collections$CheckedRandomAccessList
 - java.util.Collections$CheckedSet
 - java.util.Collections$CheckedSortedMap
 - java.util.Collections$CheckedSortedSet
 - java.util.Collections$CopiesList
 - java.util.Collections$EmptyList
 - java.util.Collections$EmptyMap
 - java.util.Collections$EmptySet
 - java.util.Collections$ReverseComparator
 - java.util.Collections$ReverseComparator2
 - java.util.Collections$SelfComparable
 - java.util.Collections$SetFromMap
 - java.util.Collections$SingletonList
 - java.util.Collections$SingletonMap
 - java.util.Collections$SingletonSet
 - java.util.Collections$SynchronizedCollection
 - java.util.Collections$SynchronizedList
 - java.util.Collections$SynchronizedMap
 - java.util.Collections$SynchronizedRandomAccessList
 - java.util.Collections$SynchronizedSet
 - java.util.Collections$SynchronizedSortedMap
 - java.util.Collections$SynchronizedSortedSet
 - java.util.Collections$UnmodifiableCollection
 - java.util.Collections$UnmodifiableList
 - java.util.Collections$UnmodifiableMap
 - java.util.Collections$UnmodifiableRandomAccessList
 - java.util.Collections$UnmodifiableSet
 - java.util.Collections$UnmodifiableSortedMap
 - java.util.Collections$UnmodifiableSortedSet
 - java.util.Comparator
 - java.util.Deque
 - java.util.Enumeration
 - java.util.Iterator
 - java.util.List
 - java.util.ListIterator
 - java.util.Map
 - java.util.Queue
 - java.util.Random
 - java.util.RandomAccess
 - java.util.Set
 - java.util.SortedMap
 - java.util.SortedSet

猜你在找的Java相关文章