我试图检查(在字节码级别,ASM)实现一些特定接口的类(在本例中是java.sql.Connection),并发现在某些情况下,库有另一个接口扩展了我的一组接口.然后他们的类实现了这个接口。(在本例中,一个新的扩展接口com.mysql.jdbc.Connection扩展java.sql.Connection,然后扩展它们的实现,例如,ConnectionImpl实现com.mysql.jdbc.Connection。)因此,我怀念将ConnectionImpl识别为目标类。
所以..。其结果是,在加载类时,我需要将com.mysql.jdbc.Connection标识为“有趣的”接口。但我不知道如何将类识别为接口,而不是普通的类。ClassReader中有什么东西能给我提供这样的信息吗?
发布于 2016-10-19 21:51:26
根据标题,如果您想检查一个类是否是一个接口:
ClassNode node = // However you wish to load the class
if ((node.access & Opcodes.ACC_INTERFACE) != 0){
// is interface
} else {
// is not an interface
}在您的文章中,您指出您希望找到java.sql.Connection的子/实现。
你现在面临的问题是:
java.sql.Connection -> com.mysql.jdbc.Connection -> ConnectionImpl
ConnectionImpl不直接实现java.sql.Connection,因此不会检测到它是子/实现。对于这样的问题,您必须做的是遍历类的层次结构。如果是在您的情况下,我将加载一个ClassNodes <String, ClassNode>映射,其中字符串是ClassNode的名称。然后,我将使用递归方法来检查给定的类是否是预期的类型。因此,如果您在其中发送一个ClassNode,它将使用节点的父节点调用自己,然后调用接口。最终,如果最初给定的节点是正确的类型,那么最终将传递并找到java.sql.Connection接口。另外,如果您想跳过冗余,您可以将每个ClassNode的结果存储在一个映射中,这样您就不必一次又一次地检查整个层次结构。
编辑:就像这样
public static boolean isMatch(ClassNode cn, Map<String,ClassNode> nodes, String target){
if (cn.name.equals(target)) return true;
else{
if (nodes.containsKey(cn.superName) && isMatch(nodes.get(cn.superName),nodes,target)) return true;
for (String interf : cn.interfaces){
if (nodes.containsKey(interf) && isMatch(nodes.get(interf),nodes,target)) return true;
}
}
return false;
}发布于 2016-10-19 09:54:53
正如您已经提到的,您需要检查每个接口类型的接口,以确定这样一个子类型关系。但是,如果您可以访问所有资源,这并不困难。
在使用ASM时,只需获取原始类的接口名称,并在每个此类接口上查找类文件。然后,您可以解析其接口的每个类文件,等等。这样,您就可以确定整个图并决定子类型关系。
如果不想手动执行此操作,则可以使用字节巴迪,它提供了类似于卸载类型的反射API的方法:
ClassFileLocator cfl = ... // can be file system, class loader, etc.
TypePool.Default.of(cfl).describe("your.initial.type")
.resolve()
.isAssignableTo(someInterface);如果目标接口不可用,也可以使用TypePool读取它。
发布于 2017-02-07 05:48:19
使用org.objectweb.asm.ClassReader,我们可以识别加载的类实际上是一个类或接口。示例代码片段如下
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException{
ClassReader classReader = null;
try{
classReader=new ClassReader(classfileBuffer);
if(isInterface(classReader)){
return classfileBuffer;
}
}
catch(Throwable exp){
return classfileBuffer;
}
// Remaining logic here
}
public boolean isInterface(ClassReader cr) {
return ((cr.getAccess() & 0x200) != 0);
}https://stackoverflow.com/questions/40119773
复制相似问题