我正在尝试检查(在字节码级别,ASM)类实现一些特定的接口(在本例中为java.sql.Connection),并发现在某些情况下,库有另一个接口扩展了我的集合接口...然后他们的类实现THAT接口。 (在这种情况下,新的扩展接口com.mysql.jdbc.Connection扩展java.sql.Connection,然后实现它们的实现,例如,ConnectionImpl实现com.mysql.jdbc.Connection。)因此,我错过了将ConnectionImpl标识为目标类的方法。
所以..结果是我需要在加载类时将com.mysql.jdbc.Connection识别为'有趣'的接口。但我无法看到如何将类AS识别为接口而不仅仅是普通类。 ClassReader中有什么东西能给我这样的信息吗?
答案 0 :(得分:2)
根据标题,如果你想检查一个类是否是一个接口:
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
接口将被传递并找到。此外,如果您想跳过redundencies,您可以将每个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;
}
答案 1 :(得分:1)
正如您已经提到的,您需要检查其接口的每种接口类型,以确定这种子类型关系。但是,如果您可以访问所有资源,这并不难。
当您使用ASM时,您只需要获取原始类的接口名称,并找到每个此类接口的类文件。然后,您可以解析每个类文件的接口,依此类推。这样,您就可以确定整个图形并确定子类型关系。
如果您不想手动执行此操作,可以使用Byte Buddy,它为您提供类似于卸载类型的反射API的方法:
ClassFileLocator cfl = ... // can be file system, class loader, etc.
TypePool.Default.of(cfl).describe("your.initial.type")
.resolve()
.isAssignableTo(someInterface);
如果目标界面不可用,您也可以使用TypePool
来阅读目标界面。
答案 2 :(得分:1)
使用 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);
}
答案 3 :(得分:0)
有一种方法可以为您检查Class#isInterface()
if (yourClass.isInterface()) {
//do something
}
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#isInterface%28%29
答案 4 :(得分:-1)
您可以使用isInterface()
java.lang.Class
方法检查某个类是否为接口。