参加レポは別で書くよん
BCELについて
BCELはClassファイルを解析するためのライブラリです!
findBugsでも使われていて、『このclassでこういうmethodを使用しているときにはbugを検知する』っていう解析ができる!
前に仕事で、findBugsの解析クラスを作成したことがあって、そのときにBCELを知りました!
今回のLTでは、クラスファイル名とメソッド名を調べるだけだったけど、
アクセス修飾子(publicなのかprivateなのか)のような、MethodやClassの属性を調べることもできる
ただし、開発自体は2006年でとまってる…(^p^)
LT終わった後に、@miyakawa_takuさんにASM - Home Pageを教えてもらった!
こちらは、今も開発されているので、Java8環境での解析をする場合は、ASMの方がイイ!!らしい
ASMの話はまた別でする!*1
BCEL
準備
mavenリポジトリがある!
Maven Repository: org.apache.bcel » bcel » 5.2
ので、準備も簡単!
<dependency> <groupId>org.apache.bcel</groupId> <artifactId>bcel</artifactId> <version>5.2</version> </dependency>
コードの解析
Classの取得
Classを取得したいときはこう書けばOK!
JavaClass javaClass = new ClassParser(<<解析したいClassファイルのファイルパス>>).parse();
Methodの取得
ClassファイルのMethodを取得して、Listとしてもつときはこう
List<Method> methods = Arrays.asList(javaClass.getMethods());
methodを一つ取得して、アクセス修飾子を調べたい場合はこう書けばいい
methods.get(1).isPrivate()
Codeの解析
↓こうかけば、javapしたときに表示される情報が一行ずつ詰まってるStreamができる*2
methods.stream() .map(Method::getCode) .map(code -> Utility.codeToString(code.getCode(), javaClass.getConstantPool(), 0, 1, false)) .flatMap(s -> Arrays.stream(s.split("\n")))
↓この情報が入ってるよ!
173: invokevirtual java.lang.StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ちなみに
- invokevirtual : インスタンスのメソッド呼び出し
- StringBuilder.append : 使用クラスと使用メソッド
- (Ljava/lang/String;) : appendに渡す引数の型
- Ljava/lang/StringBuilder; : appendメソッドの戻り値
を確認することができるよ!
ちなみに、LTしたときのソースはこんな感じでした!
import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.classfile.Utility; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; public class SyobochimJyoshiryokuDetector { static final String PATH = "/Users/syobochim/dev/gist/build/classes/main/jjugccc2014/"; public static void main(String[] args) { File dir = new File(PATH); List<File> files = Arrays.asList(dir.listFiles()); files.stream() .filter(File::isFile) .forEach(file -> { try { JavaClass javaClass = new ClassParser(file.getPath()).parse(); System.out.print(javaClass.getClassName() + " : "); if (hasJyoshiryoku(javaClass)) { System.out.println("女子力あります"); } else { System.out.println("女子力ないです"); } System.out.println(); } catch (IOException e) { e.printStackTrace(); } }); } private static boolean hasJyoshiryoku(final JavaClass javaClass) { List<Method> methods = Arrays.asList(javaClass.getMethods()); return methods.stream() .map(Method::getCode) .map(code -> Utility.codeToString(code.getCode(), javaClass.getConstantPool(), 0, 1, false)) .flatMap(s -> Arrays.stream(s.split("\n"))) .anyMatch(s -> s.matches(".*Syobochim\\.jyoshiryoku.*")); } }