unageanu-javaclass 0.2.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +5 -0
- data/javaclass.gemspec +18 -0
- data/lib/javaclass.rb +1 -0
- data/lib/javaclass/accessflag.rb +1 -1
- data/lib/javaclass/attribute.rb +293 -2
- data/lib/javaclass/base.rb +33 -4
- data/lib/javaclass/code.rb +78 -0
- data/lib/javaclass/constant.rb +2 -2
- data/lib/javaclass/member.rb +18 -18
- data/lib/javaclass/reader.rb +460 -6
- data/sample/caller.rb +95 -0
- data/sample/java_class/com/example/Constants.class +0 -0
- data/sample/java_class/com/example/Deprecated.class +0 -0
- data/sample/java_class/com/example/InnerClass.class +0 -0
- data/sample/java_class/com/example/InnerClassImpl.class +0 -0
- data/sample/java_class/com/example/Kitten.class +0 -0
- data/sample/java_class/com/example/ThrowsException.class +0 -0
- data/sample/java_class/com/example/annotation/Annotated.class +0 -0
- data/sample/java_class/com/example/annotation/AnnotatedMethod.class +0 -0
- data/sample/java_class/com/example/annotation/ClassAnnotationA.class +0 -0
- data/sample/java_class/com/example/annotation/HasDefaultValue.class +0 -0
- data/sample/java_class/com/example/annotation/RuntimeAnnotationA.class +0 -0
- data/sample/java_class/com/example/annotation/RuntimeAnnotationB.class +0 -0
- data/sample/java_class/com/example/annotation/RuntimeAnnotationC.class +0 -0
- data/sample/java_class/com/example/annotation/SourceAnnotationA.class +0 -0
- data/sample/java_class/com/example/caller/A.class +0 -0
- data/sample/java_class/com/example/caller/B.class +0 -0
- data/sample/java_class/com/example/caller/C.class +0 -0
- data/sample/java_class/com/example/caller/CallSample$A.class +0 -0
- data/sample/java_class/com/example/caller/CallSample$B.class +0 -0
- data/sample/java_class/com/example/caller/CallSample$C.class +0 -0
- data/sample/java_class/com/example/caller/CallSample.class +0 -0
- data/sample/java_class/com/example/caller/D.class +0 -0
- data/sample/java_class/com/example/code/Statement.class +0 -0
- data/sample/java_class/com/example/types/TypeVariables.class +0 -0
- data/sample/java_src/com/example/caller/A.java +19 -0
- data/sample/java_src/com/example/caller/B.java +7 -0
- data/sample/java_src/com/example/caller/C.java +7 -0
- data/sample/java_src/com/example/caller/CallSample.java +23 -0
- data/sample/java_src/com/example/caller/D.java +5 -0
- data/sample/java_src/com/example/code/Statement.java +41 -0
- data/sample/sample.rb +3 -3
- data/test/all_tests.rb +9 -0
- data/test/java_src/com/example/TestClass1.java +35 -0
- data/test/test_attribute.rb +150 -2
- data/test/test_class.rb +0 -1
- data/test/test_member.rb +4 -1
- metadata +44 -46
data/sample/caller.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "zip/zip"
|
5
|
+
require "javaclass"
|
6
|
+
require "kconv"
|
7
|
+
|
8
|
+
# クラスプール
|
9
|
+
class ClassPool
|
10
|
+
def initialize
|
11
|
+
@classes = {}
|
12
|
+
@classes_r = {}
|
13
|
+
end
|
14
|
+
def <<( jc )
|
15
|
+
jc.methods.each {|m|
|
16
|
+
key = jc.name + "#" + m.name + m.descriptor
|
17
|
+
@classes[key] ||= []
|
18
|
+
next unless m.attributes.key? "Code"
|
19
|
+
m.attributes["Code"].codes.each {|code|
|
20
|
+
case code.opcode
|
21
|
+
when 0xB6,0xB7,0xB8,0xB9
|
22
|
+
m = jc.get_constant( code.operands[0].value )
|
23
|
+
add_caller( key,
|
24
|
+
m.class_name.name + "#" +
|
25
|
+
m.name_and_type.name + m.name_and_type.descriptor
|
26
|
+
)
|
27
|
+
when 0xB2,0xB3,0xB4,0xB5
|
28
|
+
m = jc.get_constant( code.operands[0].value )
|
29
|
+
add_caller( key,
|
30
|
+
m.class_name.name + "." + m.name_and_type.name
|
31
|
+
)
|
32
|
+
end
|
33
|
+
}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
attr_reader :classes
|
37
|
+
attr_reader :classes_r
|
38
|
+
private
|
39
|
+
def add_caller( from, to )
|
40
|
+
@classes[from] ||= []
|
41
|
+
@classes[from] << to
|
42
|
+
@classes_r[to] ||= []
|
43
|
+
@classes_r[to] << from
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#ノード
|
48
|
+
class Node
|
49
|
+
def initialize( name )
|
50
|
+
@name = name
|
51
|
+
@children = []
|
52
|
+
end
|
53
|
+
def <<(child)
|
54
|
+
@children << child
|
55
|
+
end
|
56
|
+
def to_s( indent="" )
|
57
|
+
str = indent.dup
|
58
|
+
str << name.to_s << "\n"
|
59
|
+
child_indent = indent.gsub(/├/, "│").gsub(/└/, " ")
|
60
|
+
@children.each_index {|i|
|
61
|
+
next if children[i] == nil
|
62
|
+
tmp = child_indent + ( i >= children.length-1 ? "└" : "├" )
|
63
|
+
str << children[i].to_s( tmp )
|
64
|
+
}
|
65
|
+
return str
|
66
|
+
end
|
67
|
+
attr :name, true
|
68
|
+
attr :children, true
|
69
|
+
end
|
70
|
+
|
71
|
+
#呼び出し元を収集する。
|
72
|
+
def collect( pool, start, stop=[], node=nil, checked=[] )
|
73
|
+
node ||= Node.new(start.to_s)
|
74
|
+
return node unless pool.classes_r.key? start
|
75
|
+
pool.classes_r[start].each {|caller|
|
76
|
+
next if checked.find{|i| i==caller }
|
77
|
+
next if stop && stop.find{|i| caller =~ i }
|
78
|
+
checked.push start.to_s
|
79
|
+
node << collect( pool, caller, stop, Node.new( caller ), checked )
|
80
|
+
checked.pop
|
81
|
+
}
|
82
|
+
return node
|
83
|
+
end
|
84
|
+
|
85
|
+
# クラス情報を収集
|
86
|
+
pool = ClassPool.new
|
87
|
+
JavaClass::Utils.each_class( *ARGV[0].split(";") ){|jc|
|
88
|
+
pool << jc
|
89
|
+
}
|
90
|
+
# 呼び出し元をツリー表示
|
91
|
+
puts collect(pool, ARGV[1]).to_s
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
package com.example.caller;
|
2
|
+
|
3
|
+
public class CallSample {
|
4
|
+
static class A {
|
5
|
+
void aaa() {
|
6
|
+
new B().bbb();
|
7
|
+
}
|
8
|
+
void aaa2() {
|
9
|
+
new C().ccc();
|
10
|
+
}
|
11
|
+
void aaa3() {
|
12
|
+
aaa2();
|
13
|
+
}
|
14
|
+
}
|
15
|
+
static class B {
|
16
|
+
void bbb() {
|
17
|
+
new C().ccc();
|
18
|
+
}
|
19
|
+
}
|
20
|
+
static class C {
|
21
|
+
void ccc() {}
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
package com.example.code;
|
2
|
+
|
3
|
+
import java.net.URI;
|
4
|
+
import java.net.URISyntaxException;
|
5
|
+
|
6
|
+
public class Statement {
|
7
|
+
|
8
|
+
public void basic( int i ) {
|
9
|
+
if ( i < 10 ) System.out.println( "a" );
|
10
|
+
if ( i > 10 ) {
|
11
|
+
System.out.println( "b" );
|
12
|
+
} else {
|
13
|
+
System.out.println( "c" );
|
14
|
+
}
|
15
|
+
for ( int j=0;j<10;j++ ) {
|
16
|
+
System.out.println( j );
|
17
|
+
}
|
18
|
+
for ( String str : new String[]{"a","b","c"} ) {
|
19
|
+
System.out.println( str );
|
20
|
+
}
|
21
|
+
int j = 9;
|
22
|
+
while ( j-- > 10 ) {
|
23
|
+
System.out.println( j );
|
24
|
+
}
|
25
|
+
switch (i) {
|
26
|
+
case 1 : System.out.println( "1" ); break;
|
27
|
+
case 2 : System.out.println( "2" );
|
28
|
+
default : System.out.println( "3" );
|
29
|
+
}
|
30
|
+
try {
|
31
|
+
new URI( "http://foo" + i );
|
32
|
+
} catch ( RuntimeException e ) {
|
33
|
+
e.printStackTrace();
|
34
|
+
} catch (URISyntaxException e) {
|
35
|
+
e.printStackTrace();
|
36
|
+
} finally {
|
37
|
+
System.out.println( "x" );
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
}
|
data/sample/sample.rb
CHANGED
@@ -17,11 +17,11 @@ require "kconv"
|
|
17
17
|
"./java_class/com/example/Deprecated.class",
|
18
18
|
"./java_class/com/example/annotation/Annotated.class",
|
19
19
|
"./java_class/com/example/annotation/HasDefaultValue.class",
|
20
|
-
"./java_class/com/example/annotation/AnnotatedMethod.class"
|
20
|
+
"./java_class/com/example/annotation/AnnotatedMethod.class",
|
21
|
+
"./java_class/com/example/code/Statement.class"
|
21
22
|
].each { |c|
|
22
23
|
open( c, "r+b" ) {|io|
|
23
24
|
jc = JavaClass.from io
|
24
|
-
puts jc.to_s
|
25
|
-
puts ""
|
25
|
+
puts jc.to_s
|
26
26
|
}
|
27
27
|
}
|
data/test/all_tests.rb
ADDED
@@ -3,6 +3,8 @@ package com.example;
|
|
3
3
|
import java.io.Closeable;
|
4
4
|
import java.io.IOException;
|
5
5
|
import java.io.Serializable;
|
6
|
+
import java.net.URI;
|
7
|
+
import java.net.URISyntaxException;
|
6
8
|
import java.util.ArrayList;
|
7
9
|
import java.util.List;
|
8
10
|
|
@@ -25,4 +27,37 @@ implements Serializable, Closeable{
|
|
25
27
|
static boolean booleanConstant = false;
|
26
28
|
|
27
29
|
public void close() throws IOException {}
|
30
|
+
|
31
|
+
public void statement( int i ) {
|
32
|
+
if ( i < 10 ) System.out.println( "a" );
|
33
|
+
if ( i > 10 ) {
|
34
|
+
System.out.println( "b" );
|
35
|
+
} else {
|
36
|
+
System.out.println( "c" );
|
37
|
+
}
|
38
|
+
for ( int j=0;j<10;j++ ) {
|
39
|
+
System.out.println( j );
|
40
|
+
}
|
41
|
+
for ( String str : new String[]{"a","b","c"} ) {
|
42
|
+
System.out.println( str );
|
43
|
+
}
|
44
|
+
int j = 9;
|
45
|
+
while ( j-- > 10 ) {
|
46
|
+
System.out.println( j );
|
47
|
+
}
|
48
|
+
switch (i) {
|
49
|
+
case 1 : System.out.println( "1" ); break;
|
50
|
+
case 2 : System.out.println( "2" );
|
51
|
+
default : System.out.println( "3" );
|
52
|
+
}
|
53
|
+
try {
|
54
|
+
new URI( "http://foo" + i );
|
55
|
+
} catch ( RuntimeException e ) {
|
56
|
+
e.printStackTrace();
|
57
|
+
} catch (URISyntaxException e) {
|
58
|
+
e.printStackTrace();
|
59
|
+
} finally {
|
60
|
+
System.out.println( "x" );
|
61
|
+
}
|
62
|
+
}
|
28
63
|
}
|
data/test/test_attribute.rb
CHANGED
@@ -36,6 +36,7 @@ module JavaClass
|
|
36
36
|
@java_class.constant_pool[14] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "LineNumberTable" )
|
37
37
|
@java_class.constant_pool[15] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "LocalVariableTable" )
|
38
38
|
@java_class.constant_pool[16] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "LocalVariableTypeTable" )
|
39
|
+
@java_class.constant_pool[17] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "StackMapTable" )
|
39
40
|
|
40
41
|
@java_class.constant_pool[30] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "aaa" )
|
41
42
|
@java_class.constant_pool[31] = UTF8Constant.new( @java_class, Constant::CONSTANT_Utf8, "bbb" )
|
@@ -274,12 +275,13 @@ module JavaClass
|
|
274
275
|
def test_CodeAttribute
|
275
276
|
|
276
277
|
exceptions = [Excpetion.new( @java_class, 1, 10, 16, 103 )]
|
277
|
-
|
278
|
+
codes = [Code.new(@java_class, 0, 0x05), Code.new(@java_class, 1, 0x06)]
|
279
|
+
attr = CodeAttribute.new( @java_class, 13, 10, 8, codes, exceptions, {} )
|
278
280
|
assert_attribute( attr ) {|a|
|
279
281
|
assert_equal a.name, "Code"
|
280
282
|
assert_equal a.max_stack, 10
|
281
283
|
assert_equal a.max_locals, 8
|
282
|
-
assert_equal a.codes,
|
284
|
+
assert_equal a.codes, codes
|
283
285
|
assert_equal a.exception_table, exceptions
|
284
286
|
assert_equal a.attributes, {}
|
285
287
|
assert_equal a.dump, "000D0000 0016000A 00080000 00020506\n00010001 000A0010 00670000"
|
@@ -896,6 +898,139 @@ module JavaClass
|
|
896
898
|
assert_equal a.to_bytes, [0x00, 0x66, 0x00, 0x65, 0x00, 0x1F, 0x02, 0x01]
|
897
899
|
}
|
898
900
|
end
|
901
|
+
|
902
|
+
#
|
903
|
+
#=== StackMapTableAttributeのテスト
|
904
|
+
#
|
905
|
+
def test_StackMapTableAttribute
|
906
|
+
|
907
|
+
vals = [
|
908
|
+
VariableInfo.new( 3 ),
|
909
|
+
ObjectVariableInfo.new( 7, 10 ),
|
910
|
+
UninitializedVariableInfo .new( 8, 2 )
|
911
|
+
]
|
912
|
+
entries = [
|
913
|
+
SameFrame.new( 3 ),
|
914
|
+
SameLocals1StackItemFrame.new( 70, [UninitializedVariableInfo .new( 8, 2 )] ),
|
915
|
+
FullFrame.new( 255, 3, vals, vals[0..1] )
|
916
|
+
]
|
917
|
+
attr = StackMapTableAttribute.new( @java_class, 17, entries )
|
918
|
+
assert_attribute( attr ) {|a|
|
919
|
+
assert_equal a.name, "StackMapTable"
|
920
|
+
assert_equal a.stack_map_frame_entries, entries
|
921
|
+
assert_equal a.dump, "00110000 00190003 03460800 02FF0003\n"+
|
922
|
+
"00030307 000A0800 02000203 07000A"
|
923
|
+
assert_equal a.to_bytes, [
|
924
|
+
0x00, 0x11, 0x00, 0x00, 0x00, 0x19, 0x00, 0x03, 0x03, 0x46, 0x08, 0x00,
|
925
|
+
0x02, 0xFF, 0x00, 0x03, 0x00, 0x03, 0x03, 0x07, 0x00, 0x0A, 0x08, 0x00,
|
926
|
+
0x02, 0x00, 0x02, 0x03, 0x07, 0x00, 0x0A
|
927
|
+
]
|
928
|
+
}
|
929
|
+
|
930
|
+
attr.stack_map_frame_entries = []
|
931
|
+
assert_attribute( attr ) {|a|
|
932
|
+
assert_equal a.name, "StackMapTable"
|
933
|
+
assert_equal a.stack_map_frame_entries, []
|
934
|
+
assert_equal a.dump, "00110000 00020000"
|
935
|
+
assert_equal a.to_bytes, [0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00]
|
936
|
+
}
|
937
|
+
end
|
938
|
+
|
939
|
+
#
|
940
|
+
#=== StackMapFrameのテスト
|
941
|
+
#
|
942
|
+
def test_StackMapFrame
|
943
|
+
|
944
|
+
vals = [
|
945
|
+
VariableInfo.new( 3 ),
|
946
|
+
ObjectVariableInfo.new( 7, 10 ),
|
947
|
+
UninitializedVariableInfo .new( 8, 2 )
|
948
|
+
]
|
949
|
+
|
950
|
+
value = SameFrame.new( 3 )
|
951
|
+
assert_stack_map_frame( value ) {|a|
|
952
|
+
assert_equal a.frame_type, 3
|
953
|
+
assert_equal a.dump, "03"
|
954
|
+
assert_equal a.to_bytes, [0x03]
|
955
|
+
}
|
956
|
+
value = SameLocals1StackItemFrame.new( 70, vals[0..0] )
|
957
|
+
assert_stack_map_frame( value ) {|a|
|
958
|
+
assert_equal a.frame_type, 70
|
959
|
+
assert_equal a.verification_type_info, vals[0..0]
|
960
|
+
assert_equal a.dump, "4603"
|
961
|
+
assert_equal a.to_bytes, [0x46, 0x03]
|
962
|
+
}
|
963
|
+
value = SameLocals1StackItemFrameExtended.new( 247, 3, vals[1..1] )
|
964
|
+
assert_stack_map_frame( value ) {|a|
|
965
|
+
assert_equal a.frame_type, 247
|
966
|
+
assert_equal a.offset_delta, 3
|
967
|
+
assert_equal a.verification_type_info, vals[1..1]
|
968
|
+
assert_equal a.dump, "F7000307 000A"
|
969
|
+
assert_equal a.to_bytes, [0xF7, 0x00, 0x03, 0x07, 0x00, 0x0A]
|
970
|
+
}
|
971
|
+
value = ChopFrame.new( 248, 5 )
|
972
|
+
assert_stack_map_frame( value ) {|a|
|
973
|
+
assert_equal a.frame_type, 248
|
974
|
+
assert_equal a.offset_delta, 5
|
975
|
+
assert_equal a.dump, "F80005"
|
976
|
+
assert_equal a.to_bytes, [0xF8, 0x00, 0x05]
|
977
|
+
}
|
978
|
+
value = SameFrameExtended.new( 251, 16 )
|
979
|
+
assert_stack_map_frame( value ) {|a|
|
980
|
+
assert_equal a.frame_type, 251
|
981
|
+
assert_equal a.offset_delta, 16
|
982
|
+
assert_equal a.dump, "FB0010"
|
983
|
+
assert_equal a.to_bytes, [0xFB, 0x00, 0x10]
|
984
|
+
}
|
985
|
+
value = AppendFrame.new( 254, 10, vals )
|
986
|
+
assert_stack_map_frame( value ) {|a|
|
987
|
+
assert_equal a.frame_type, 254
|
988
|
+
assert_equal a.offset_delta, 10
|
989
|
+
assert_equal a.verification_type_info, vals
|
990
|
+
assert_equal a.dump, "FE000A03 07000A08 0002"
|
991
|
+
assert_equal a.to_bytes, [0xFE, 0x00, 0x0A, 0x03, 0x07, 0x00, 0x0A, 0x08, 0x00, 0x02]
|
992
|
+
}
|
993
|
+
value = FullFrame.new( 255, 3, vals, vals[0..1] )
|
994
|
+
assert_stack_map_frame( value ) {|a|
|
995
|
+
assert_equal a.frame_type, 255
|
996
|
+
assert_equal a.offset_delta, 3
|
997
|
+
assert_equal a.verification_type_info_local, vals
|
998
|
+
assert_equal a.verification_type_info_stack, vals[0..1]
|
999
|
+
assert_equal a.dump, "FF000300 03030700 0A080002 00020307\n" +
|
1000
|
+
"000A"
|
1001
|
+
assert_equal a.to_bytes, [
|
1002
|
+
0xFF, 0x00, 0x03, 0x00, 0x03, 0x03, 0x07, 0x00, 0x0A, 0x08, 0x00, 0x02,
|
1003
|
+
0x00, 0x02, 0x03, 0x07, 0x00, 0x0A
|
1004
|
+
]
|
1005
|
+
}
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
#
|
1009
|
+
#=== VariableInfoのテスト
|
1010
|
+
#
|
1011
|
+
def test_VariableInfo
|
1012
|
+
|
1013
|
+
value = VariableInfo.new( 3 )
|
1014
|
+
assert_variable_info( value ) {|a|
|
1015
|
+
assert_equal a.tag, 3
|
1016
|
+
assert_equal a.dump, "03"
|
1017
|
+
assert_equal a.to_bytes, [0x03]
|
1018
|
+
}
|
1019
|
+
value = ObjectVariableInfo.new( 7, 10 )
|
1020
|
+
assert_variable_info( value ) {|a|
|
1021
|
+
assert_equal a.tag, 7
|
1022
|
+
assert_equal a.cpool_index, 10
|
1023
|
+
assert_equal a.dump, "07000A"
|
1024
|
+
assert_equal a.to_bytes, [0x07, 0x00, 0x0A]
|
1025
|
+
}
|
1026
|
+
value = UninitializedVariableInfo .new( 8, 2 )
|
1027
|
+
assert_variable_info( value ) {|a|
|
1028
|
+
assert_equal a.tag, 8
|
1029
|
+
assert_equal a.offset, 2
|
1030
|
+
assert_equal a.dump, "080002"
|
1031
|
+
assert_equal a.to_bytes, [0x08, 0x00, 0x02]
|
1032
|
+
}
|
1033
|
+
end
|
899
1034
|
|
900
1035
|
def assert_attribute( a, &block )
|
901
1036
|
assert_to_byte_and_read a, block, proc {|io|
|
@@ -950,6 +1085,19 @@ module JavaClass
|
|
950
1085
|
JavaClass.read_local_variable_type( io, @java_class )
|
951
1086
|
}
|
952
1087
|
end
|
1088
|
+
|
1089
|
+
def assert_stack_map_frame( a, &block )
|
1090
|
+
assert_to_byte_and_read a, block, proc {|io|
|
1091
|
+
JavaClass.read_stack_map_frame_entry( io, @java_class )
|
1092
|
+
}
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
def assert_variable_info( a, &block )
|
1096
|
+
assert_to_byte_and_read a, block, proc {|io|
|
1097
|
+
JavaClass.read_variable_info( io, @java_class )
|
1098
|
+
}
|
1099
|
+
end
|
1100
|
+
|
953
1101
|
end
|
954
1102
|
|
955
1103
|
end
|