在我的
Java项目中,我想从程序中找出使用给定API的哪些类.有没有办法做到这一点?可以通过源代码解析或字节码解析?因为反思不会有任何用处,恐怕.
为了使事情更简单:我的项目中的任何地方都没有通配符导入(import com.mycompany.api.*;),没有完全限定字段或变量定义(private com.mycompany.api.MyThingy thingy;)也没有任何Class.forName(...)结构.鉴于这些限制,它归结为解析导入语句,我猜.是否有首选方法?
解决方法
您可以使用
ASM的
Remapper课程(相信或不相信)发现课程.这个类实际上是为了替换字节码中所有出现的类名.但是,为了您的目的,它不需要更换任何东西.
这可能不是很有意义的,所以这里是一个例子…
首先,您创建一个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