有没有办法判断一个类是否是一个接口?

时间:2016-10-18 23:38:34

标签: java-bytecode-asm

我正在尝试检查(在字节码级别,ASM)类实现一些特定的接口(在本例中为java.sql.Connection),并发现在某些情况下,库有另一个接口扩展了我的集合接口...然后他们的类实现THAT接口。 (在这种情况下,新的扩展接口com.mysql.jdbc.Connection扩展java.sql.Connection,然后实现它们的实现,例如,ConnectionImpl实现com.mysql.jdbc.Connection。)因此,我错过了将ConnectionImpl标识为目标类的方法。

所以..结果是我需要在加载类时将com.mysql.jdbc.Connection识别为'有趣'的接口。但我无法看到如何将类AS识别为接口而不仅仅是普通类。 ClassReader中有什么东西能给我这样的信息吗?

5 个答案:

答案 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方法检查某个类是否为接口。