在我的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;
}
实际获取所有类的字节码是您的责任。
我接受这个答案,但是由于上面的代码不太正确,因此我将插入我的用法:
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
问题内容: 如何在Linux上从TrueType或嵌入式OpenType字体中提取受支持的Unicode字符列表? 我是否可以使用工具或库来处理.ttf或.eot文件并构建字体提供的代码点列表(例如U + 0123,U + 1234等)? 问题答案: 这是使用FontTools模块的方法(您可以使用来安装该模块): 该脚本将字体路径作为参数:
本文向大家介绍HTML5标准提供了哪些新的API?你有用过哪些?相关面试题,主要包含被问及HTML5标准提供了哪些新的API?你有用过哪些?时的应答技巧和注意事项,需要的朋友参考一下 两个选择器API 地理定位API 多媒体API 拖放API 文件API XHR2 本地储存API canvas svg
问题内容: 在Unix / Linux中,如何通过命令行找出给定用户所在的组? 问题答案: 要么
问题内容: 简单的问题: 有哪些Python GUI API,任何给定API的优点是什么? 我不是要在这里发动一场宗教战争,我只是想就Python GUI API方面的所有问题取得良好的解决。 问题答案: 这是一个很好的清单。
我有以下图表 如果我写一个查询g.V('a')。Out(),我如何才能得到被遍历的边和在traveral中遇到的顶点的值?
本文向大家介绍Kafka的主要API有哪些?相关面试题,主要包含被问及Kafka的主要API有哪些?时的应答技巧和注意事项,需要的朋友参考一下 答:Apache Kafka有4个主要API: 生产者API 消费者API 流 API 连接器API