unageanu-javaclass 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|