【问题标题】:Reduce visibility of classes and methods减少类和方法的可见性
【发布时间】:2017-05-01 21:54:14
【问题描述】:

TL;DR:给定字节码,我如何找出给定方法中使用了哪些类和方法?


在我的代码中,我想以编程方式找到所有具有过多访问限定符的类和方法。这应该基于对继承、静态使用以及我提供的提示的分析(例如,使用一些自制注释,如 @KeepPublic)来完成。作为一种特殊情况,会找到未使用的类和方法。

我只是做了一些类似但更简单的事情,即将final 关键字添加到所有有意义的类中(即,它是允许的,并且该类不会被例如 Hibernate 代理)。我以测试的形式进行了测试,它知道要忽略的类(例如实体)并抱怨所有不必要的非最终类。

对于我的所有类,我想找到它使用的所有方法和类。关于课程,有this answer using ASM's Remapper。关于方法,我找到了an answer proposing instrumentation,这不是我现在想要的。我也不是在寻找像 ucdetector 这样与 Eclipse AST 一起使用的工具。 如何根据字节码检查方法主体?我想自己做,这样我就可以以编程方式消除不需要的警告(在使用 Lombok 时,ucdetector 有很多警告)。

【问题讨论】:

标签: java bytecode access-modifiers unreachable-code


【解决方案1】:

查看每个方法的使用情况,即通过分析所有指令,有一些陷阱。除了method invocations,可能还有方法引用,它们将使用invokedynamic instruction 进行编码,在其bsm 参数中具有目标方法的handle。如果字节码不是从普通 Java 代码生成的(或源自未来版本),您必须准备好可能遇到指向 handleldc instructions,这将在运行时产生 MethodHandle

既然你已经提到了“继承分析”,我只想指出一些极端情况,即for

package foo;

class A {
    public void method() {}
}
class B implements bar.If {
}

package bar;

public interface If {
    void method();
}

很容易忽略A.method() 必须保持public

如果您保持保守,即当您无法确定 B 实例是否最终会成为应用程序中其他位置的 If.method() 调用的目标时,您必须假设这是可能的,您找不到太多优化。我认为您至少需要内联桥方法和合成的内部/外部类访问器来识别继承关系中未使用的成员。

当涉及到类引用时,确实有更多的可能性,使每条指令的分析容易出错。它们不仅可能作为成员访问指令的所有者出现,而且还出现在 newcheckcastinstanceof 和特定于数组的指令、注释、异常处理程序中,更糟糕的是,出现在 signatures 中可能出现在成员引用、注解、局部变量调试提示等处。ldc 指令可能会引用类,产生一个Class 实例,该实例实际上用于普通 Java 代码,例如对于类文字,但如前所述,理论上也有可能产生 MethodHandles ,它可能引用所有者类,但也有签名承载参数类型和返回类型,或者产生代表签名的 MethodType .

您最好分析常量池,但是 ASM 不提供。准确地说,ClassReader 具有访问池的方法,但它们实际上并不打算由客户端代码使用(如其文档所述)。即使在那里,你也必须意识到陷阱。基本上,CONSTANT_Utf8_info 的内容带有类或签名引用,如果 CONSTANT_Class_info 相应。 CONSTANT_NameAndType_infoCONSTANT_MethodType_info 的描述符索引指向它。但是,声明的类成员直接引用CONSTANT_Utf8_info 池条目来描述它们的签名,请参阅MethodsFields。同样,注释不遵循该模式,而是直接引用池中的 CONSTANT_Utf8_info 条目,为其分配类型或签名语义,请参阅 enum_const_valueclass_info_index...

【讨论】:

  • 冬青莫莉,详细...!
  • 确实是一个很棒的答案。我是否正确假设 asm 是这项工作的唯一工具?水平太低了+++ 无论如何,我不害怕错过参考,因为这将成为我自己的工具。当它出错时,我会得到一个编译时错误,修复代码(git rulez)并修复工具。
  • 我没有评估其他库。 Afaik,Javassist 在其公共 API 中提供了常量池的表示,但我不知道它对其他目的的服务效果如何。如果您认为 ASM 是“该死的低级”,请注意我通常什至不使用 ASM,因为它对于我的某些任务来说“太大”(仪器必须蜂拥而至)。参见例如 printing the poolfinding class dependencies in the pool or iterating an instruction sequence 没有 ASM...
  • 但是可能会有更高级别的库解决像 ASM、Javassist 或 BCEL 这样​​的低级别库,为您的实际任务提供一些东西。但这更像是搜索网络而不是编程任务。
猜你喜欢
  • 1970-01-01
  • 2014-07-20
  • 2010-09-25
  • 2011-01-14
  • 2017-06-05
  • 1970-01-01
  • 2021-09-04
  • 2023-02-08
  • 2014-03-06
相关资源
最近更新 更多