Javaクラス解析機を作る 5日目
属性の読み込みに着手。クラス属性を読み込む部分を書いて、次の2つの属性の読み込みに対応。
- 定数値(ConstantValue)
- ソースファイル(SourceFile)
あと、いろいろリファクタしました。
- 長くなってきたのでファイルを分割して、クラス構成も大幅変更。
- ClassとかConstantのコンストラクタでIOからデータを読み込むのをやめ、専用の関数で読むようにした。
現在の読み込み対応データ
★付きが今日対応したモノ。
クラスデータ
名称 | サイズ | 説明 |
---|---|---|
magic | 4byte | クラスファイルを識別するためのマジックナンバー。0xCAFEBABEが入る。 |
minor_version | 2byte | クラスのマイナーバージョン |
major_version | 2byte | クラスのメジャーバージョン |
constant_pool_count | 2byte | constant_pool (クラス名メソッド名などの定数が格納されるテーブル)の数 |
constant_pool | 可変 | クラス名メソッド名などの定数が格納されるテーブル。constant_pool_count-(1+Double or Longのconstantの数)個のconstant_poolが並ぶ。「文字列」や「Class情報」など種類がいくつかあって、それぞれデータ形式/サイズが異なる。 |
access_flags | 2byte | クラス/インターフェイスのアクセス権限情報 |
this_class | 2byte | このクラスファイルで定義されているクラスを示すconstant_poolのid。 |
super_class | 2byte | このクラスファイルで定義されているクラスの親クラスを示すconstant_poolのid。 |
interfaces_count | 2byte | 実装しているインターフェイスの数。 |
interfaces | 可変(2byte*interfaces_count) | 実装しているインターフェイスを示すconstant_poolのid。interfaces_count数だけ続く。 |
fields_count | 2byte | クラス/インターフェイスで定義されているフィールドの数。 |
field_info | 可変 | クラス/インターフェイスで定義されているフィールド。データ形式は「フィールドデータ」を参照。fields_count数だけ続く。 |
methods_count | 2byte | クラス/インターフェイスで定義されているメソッドの数。 |
method_info | 可変 | クラス/インターフェイスで定義されているメソッド。データ形式は「メソッドデータ」を参照。methods_count数だけ続く。 |
★attributes_count | 2byte | クラス/インターフェイスの属性の数。 |
★attribute_info | 可変 | クラス/インターフェイスの属性。コンパイル元のソースファイルの情報などが含まれる。データ形式は各種「属性」を参照。methods_count数だけ続く。 |
フィールドデータ
名称 | サイズ | 説明 |
---|---|---|
access_flags | 2byte | フィールドのアクセス権限情報 |
name_index | 2byte | フィールド名を示すconstant_poolのid |
descriptor_index | 2byte | フィールドの型の文字列表現を示すconstant_poolのid |
attributes_count | 2byte | フィールドに付加された属性の数 |
attribute_info | 可変 | フィールドの属性。定数の値やdeplicatedの情報なんかが属性として指定される。attributes_count数だけ続く |
メソッドデータ
名称 | サイズ | 説明 |
---|---|---|
access_flags | 2byte | メソッドのアクセス権限情報 |
name_index | 2byte | メソッド名を示すconstant_poolのid |
descriptor_index | 2byte | メソッドの引数と戻り値の型の文字列表現を示すconstant_poolのid。「(<引き数の型><引き数の型>..)<戻り値の型>」形式。 |
attributes_count | 2byte | メソッドに付加された属性の数 |
attribute_info | 可変 | メソッドの属性。メソッドの処理コード、発生する例外などが属性として指定される。attributes_count数だけ続く |
ConstantValue属性
文字列とプリミティブ型の定数の値を示す、フィールドの属性。
名称 | サイズ | 説明 |
---|---|---|
★attribute_name_index | 2byte | 属性名"ConstantValue"を示すconstant_poolのid。 |
★attribute_length | 4byte | 属性値の長さ。2で固定 |
★constantvalue_index | 2byte | 定数値を示すconstant_poolのid。 |
SourceFile属性
クラスのコンパイル前のソースファイル名(パスではない。)の情報を保持する、クラス属性。
名称 | サイズ | 説明 |
---|---|---|
★attribute_name_index | 2byte | 属性名"SourceFile"を示すconstant_poolのid。 |
★attribute_length | 4byte | 属性値の長さ。2で固定 |
★sourcefile_index | 2byte | ソースファイル名を示すconstant_poolのid。 |
ここまでの解析コード
zipにしました。
→Javaクラス解析機 080414
動作サンプル
解析対象のJavaクラス(のソース)
package com.example; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public interface Constants extends Serializable { static final String stringConstant = "aaa"; static int intConstant = 1; public static long longConstant = 100L; public static final List<String> listConstant = new ArrayList<String>(); }
解析!
require "javaclass" open( "./Constants.class", "r+b" ) {|io| jc = JavaClass.from io puts jc.to_s }
実行結果です。
// version 49.0 // source Constants.java public abstract interface com.example.Constants extends java.lang.Object implements java.io.Serializable { public static final java.lang.String stringConstant = "aaa"; public static final int intConstant = 1; public static final long longConstant = 100L; public static final java.util.List listConstant; static void <clinit> ( ) {}; }
オブジェクト型の定数はConstantValue属性で保持されない様子。「