2016-10-18 46 views
3

我试图检查(在字节码级别,ASM)类实现一些特定的接口(在这种情况下,java.sql.Connection),并发现在某些情况下,库有另一个接口扩展从我的一套接口...然后他们的类实现THAT接口。 (在这种情况下,新的扩展接口com.mysql.jdbc.Connection扩展了java.sql.Connection,然后它们的实现,例如ConnectionImpl实现了com.mysql.jdbc.Connection。)因此我错过了将ConnectionImpl识别为目标类。有没有办法判断一个类是否是一个接口?

所以..结果是我需要在加载类时将com.mysql.jdbc.Connection识别为“有趣”的接口。但是我看不出如何将类作为接口而不是普通类。 ClassReader中有什么比给我提供那种信息的东西?

+0

最后,我认为我被洗脑了。即使我可以做这样的事情,也没有什么可以确保界面事实上在课前加载。例如,从我所看到的,ConnectionImpl在mysql.jdbc.Connection之前加载,因此我无法知道ConnectionImpl实际上实现了java.sql.Connection。 – ticktock

回答

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所以它不会被检测为孩子/实施。对于这样的问题,你需要做的是旅行类层次结构。如果我处于你的情况,我会加载一个ClassNode <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; 
} 
-1

您可以使用isInterface()方法java.lang.Class来检查类是否为接口。

+0

欢迎来到堆栈溢出!虽然这可能是解决问题的有价值的提示,但答案确实需要证明解决方案。请[编辑]提供示例代码来展示你的意思。或者,可以考虑将其写为注释。 –

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读取目标接口,如果它不可用。

0

使用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); 
    } 
相关问题