javaclass 0.0.3 → 0.0.4
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/Rakefile +67 -56
- data/Readme.txt +42 -39
- data/example_task.rb +172 -0
- data/examples/check_interface_names.rb +44 -0
- data/examples/corpus.rb +19 -0
- data/examples/count_classes_in_modules.rb +38 -0
- data/examples/cumulative_dependencies.rb +39 -0
- data/examples/find_all_imported_types.rb +44 -0
- data/examples/find_referenced_modules.rb +53 -0
- data/examples/find_unreferenced_classes.rb +65 -0
- data/examples/generate_class_lists.rb +67 -43
- data/examples/profiler_scratchpad.rb +33 -0
- data/examples/simple_usage.rb +42 -0
- data/history.txt +29 -7
- data/javaclass.gemspec +31 -0
- data/lib/javaclass/adder_tree.rb +92 -0
- data/lib/javaclass/analyse/dependencies.rb +52 -0
- data/lib/javaclass/{metric/metrics.txt → analyse/ideas.txt} +2 -2
- data/lib/javaclass/analyse/transitive_dependencies.rb +52 -0
- data/lib/javaclass/classfile/access_flag_constants.rb +24 -0
- data/lib/javaclass/classfile/access_flags.rb +49 -26
- data/lib/javaclass/classfile/class_format_error.rb +37 -0
- data/lib/javaclass/classfile/class_magic.rb +16 -8
- data/lib/javaclass/classfile/class_version.rb +19 -25
- data/lib/javaclass/classfile/constant_pool.rb +110 -45
- data/lib/javaclass/classfile/constants/base.rb +33 -12
- data/lib/javaclass/classfile/constants/double_reference.rb +55 -41
- data/lib/javaclass/classfile/constants/single_reference.rb +29 -21
- data/lib/javaclass/classfile/constants/value.rb +43 -33
- data/lib/javaclass/classfile/java_class_header.rb +72 -46
- data/lib/javaclass/classfile/java_class_header_as_java_name.rb +33 -0
- data/lib/javaclass/classfile/java_class_header_shortcuts.rb +19 -0
- data/lib/javaclass/classfile/references.rb +21 -19
- data/lib/javaclass/classlist/class_entry.rb +26 -27
- data/lib/javaclass/classlist/jar_searcher.rb +34 -25
- data/lib/javaclass/classlist/list.rb +31 -31
- data/lib/javaclass/classlist/package_entry.rb +25 -24
- data/lib/javaclass/classpath/any_classpath.rb +48 -0
- data/lib/javaclass/classpath/class_not_found_error.rb +20 -0
- data/lib/javaclass/classpath/classpaths.txt +2 -2
- data/lib/javaclass/classpath/composite_classpath.rb +56 -54
- data/lib/javaclass/classpath/convention_classpath.rb +38 -0
- data/lib/javaclass/classpath/eclipse_classpath.rb +74 -0
- data/lib/javaclass/classpath/factory.rb +65 -0
- data/lib/javaclass/classpath/file_classpath.rb +47 -0
- data/lib/javaclass/classpath/folder_classpath.rb +42 -44
- data/lib/javaclass/classpath/jar_classpath.rb +91 -52
- data/lib/javaclass/classpath/java_home_classpath.rb +24 -13
- data/lib/javaclass/classpath/maven_classpath.rb +44 -0
- data/lib/javaclass/classpath/temporary_unpacker.rb +111 -0
- data/lib/javaclass/classpath/tracking_classpath.rb +144 -0
- data/lib/javaclass/classscanner/ideas.txt +3 -0
- data/lib/javaclass/classscanner/imported_types.rb +29 -0
- data/lib/javaclass/classscanner/scanners.rb +29 -0
- data/lib/javaclass/delegate_directive.rb +15 -0
- data/lib/javaclass/dsl/caching_classpath.rb +38 -0
- data/lib/javaclass/dsl/classpath_analysers.rb +27 -0
- data/lib/javaclass/dsl/java_name_factory.rb +79 -0
- data/lib/javaclass/dsl/loader.rb +42 -0
- data/lib/javaclass/dsl/loading_classpath.rb +53 -0
- data/lib/javaclass/dsl/mixin.rb +54 -0
- data/lib/javaclass/gems/zip_file.rb +154 -0
- data/lib/javaclass/java_language.rb +50 -0
- data/lib/javaclass/java_name.rb +329 -55
- data/lib/javaclass/java_name_scanner.rb +95 -0
- data/lib/javaclass/resources/iso_3166_countries.txt +240 -0
- data/lib/javaclass/resources/jdk0_packages.txt +6 -0
- data/lib/javaclass/resources/jdk1_packages.txt +6 -0
- data/lib/javaclass/resources/jdk2_packages.txt +4 -0
- data/lib/javaclass/resources/jdk3_packages.txt +6 -0
- data/lib/javaclass/resources/jdk4_packages.txt +22 -0
- data/lib/javaclass/resources/jdk5_packages.txt +5 -0
- data/lib/javaclass/resources/jdk6_packages.txt +7 -0
- data/lib/javaclass/resources/jdk7_packages.txt +0 -0
- data/lib/javaclass/resources/jdk_packages.txt +53 -0
- data/lib/javaclass/resources/reserved_words.txt +50 -0
- data/lib/javaclass/string_hexdump.rb +76 -0
- data/lib/javaclass/string_ux.rb +21 -10
- data/lib/javaclass.rb +16 -41
- data/license.txt +28 -0
- data/planned.txt +13 -0
- data/test/data/Object_102.class +0 -0
- data/test/data/Runnable_102.class +0 -0
- data/test/data/access_flags/AccessFlagsTestAnnotation.class +0 -0
- data/test/data/access_flags/AccessFlagsTestAnnotation.java +3 -0
- data/test/data/access_flags/AccessFlagsTestEnum$1.class +0 -0
- data/test/data/access_flags/AccessFlagsTestEnum.class +0 -0
- data/test/data/access_flags/AccessFlagsTestEnum.java +6 -0
- data/test/data/access_flags/AccessFlagsTestInner$1.class +0 -0
- data/test/data/access_flags/AccessFlagsTestInner$2.class +0 -0
- data/test/data/access_flags/AccessFlagsTestInner.class +0 -0
- data/test/data/access_flags/AccessFlagsTestInner.java +13 -0
- data/test/data/access_flags/AccessFlagsTestPackage.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPackage.java +1 -1
- data/test/data/api/packagename/AccessFlagsTestPublic.class +0 -0
- data/test/data/class_version/ClassVersionTest17.class +0 -0
- data/test/data/class_version/make.bat +6 -2
- data/test/data/eclipse_classpath/classes/ClassVersionTest12.class +0 -0
- data/test/data/eclipse_classpath/lib/JarClasspathTest.jar +0 -0
- data/test/data/eclipse_classpath/test-classes/ClassVersionTest13.class +0 -0
- data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/ClassVersionTest10.class +0 -0
- data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/package/ClassVersionTest11.class +0 -0
- data/test/data/jar_classpath/JarClasspathTest.jar +0 -0
- data/test/data/jar_classpath/JarClasspathTest.zip +0 -0
- data/test/data/jar_classpath/JarClasspathTestManifest.jar +0 -0
- data/test/data/jar_classpath/JarClasspathTestMultiManifest.jar +0 -0
- data/test/data/jar_classpath/make.bat +6 -2
- data/test/data/jar_searcher/BrokenRunnable_102.class +0 -0
- data/test/data/java_home_classpath/jdk118/lib/classes.zip +0 -0
- data/test/data/java_name_scanner/META-INF/MANIFEST.MF +12 -0
- data/test/data/java_name_scanner/plugin.xml +18 -0
- data/test/data/maven_classpath/module/pom.xml +8 -0
- data/test/data/maven_classpath/module/target/classes/ClassVersionTest12.class +0 -0
- data/test/data/maven_classpath/pom.xml +8 -0
- data/test/data/maven_classpath/target/classes/ClassVersionTest10.class +0 -0
- data/test/data/maven_classpath/target/test-classes/ClassVersionTest11.class +0 -0
- data/test/data/transitive_dependencies/A.class +0 -0
- data/test/data/transitive_dependencies/A.java +5 -0
- data/test/data/transitive_dependencies/B.class +0 -0
- data/test/data/transitive_dependencies/B.java +3 -0
- data/test/data/transitive_dependencies/C.class +0 -0
- data/test/data/transitive_dependencies/C.java +3 -0
- data/test/data/transitive_dependencies/Start.class +0 -0
- data/test/data/transitive_dependencies/Start.java +4 -0
- data/test/data/transitive_dependencies/make.bat +3 -0
- data/test/data/zip_file/commons-math-2.2-broken.zip +0 -0
- data/test/data/zip_file/regenerated-with-7zip.zip +0 -0
- data/test/data/zip_file/regenerated-with-jar.zip +0 -0
- data/test/dot_classpath.rb +33 -0
- data/test/logging_folder_classpath.rb +19 -0
- data/test/setup.rb +1 -1
- data/test/test_access_flags.rb +58 -32
- data/test/test_adder_tree.rb +78 -0
- data/test/test_any_classpath.rb +39 -0
- data/test/test_base.rb +9 -7
- data/test/test_caching_classpath.rb +41 -0
- data/test/test_class_entry.rb +60 -60
- data/test/test_class_magic.rb +31 -0
- data/test/test_class_version.rb +25 -25
- data/test/test_composite_classpath.rb +22 -23
- data/test/test_constant_pool.rb +37 -13
- data/test/test_convention_classpath.rb +39 -0
- data/test/test_eclipse_classpath.rb +73 -0
- data/test/test_factory.rb +61 -0
- data/test/test_folder_classpath.rb +26 -10
- data/test/test_imported_types.rb +34 -0
- data/test/test_jar_classpath.rb +29 -14
- data/test/test_jar_searcher.rb +27 -14
- data/test/test_java_class_header.rb +22 -10
- data/test/test_java_class_header_as_java_name.rb +41 -0
- data/test/test_java_home_classpath.rb +17 -11
- data/test/test_java_name.rb +204 -64
- data/test/test_java_name_factory.rb +52 -0
- data/test/test_java_name_scanner.rb +24 -0
- data/test/test_javaclass_api.rb +43 -0
- data/test/test_list.rb +58 -44
- data/test/test_load_directive.rb +34 -0
- data/test/test_maven_classpath.rb +46 -0
- data/test/test_package_entry.rb +27 -22
- data/test/test_references.rb +14 -14
- data/test/test_string_hexdump.rb +24 -0
- data/test/test_string_ux.rb +18 -106
- data/test/test_tracking_classpath.rb +112 -0
- data/test/test_transitive_dependencies.rb +31 -0
- data/test/test_unpacking_jar_classpath.rb +43 -0
- data/test/test_zip_file.rb +33 -0
- data/test/ts_all_tests.rb +80 -18
- data/thanks.txt +2 -0
- metadata +151 -22
- data/lib/javaclass/classpath/port_ClassPathEntry.java +0 -202
- data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +0 -311
- data/lib/javaclass/classpath/port_DirectoryRepository.java +0 -24
- data/lib/javaclass/metric/ccd.rb +0 -68
- data/lib/javaclass/metric/class_usage.rb +0 -41
- data/test/test_javaclass.rb +0 -22
data/lib/javaclass/java_name.rb
CHANGED
@@ -1,90 +1,364 @@
|
|
1
|
+
require 'javaclass/java_language'
|
2
|
+
require 'javaclass/delegate_directive'
|
3
|
+
|
1
4
|
module JavaClass
|
2
|
-
|
3
|
-
#
|
5
|
+
|
6
|
+
# Mixin with logic to work with Java package names. The "mixer" needs to declare a String field @package.
|
4
7
|
# Author:: Peter Kofler
|
5
|
-
|
6
|
-
|
7
|
-
# Return the package name of a classname or the
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
attr_reader :simple_name
|
12
|
-
# Full normalized class name of this class.
|
13
|
-
attr_reader :full_name
|
14
|
-
|
15
|
-
def initialize(string)
|
16
|
-
super string
|
17
|
-
@full_name = string.gsub(/\/|\\/,'.').sub(/\.(class|java|".*|<.*)?$/, '')
|
18
|
-
|
19
|
-
matches = @full_name.scan(/^(.+)\.([A-Z][^.]*)$/)[0]
|
20
|
-
if matches
|
21
|
-
@package = matches[0].to_javaname
|
22
|
-
@simple_name = matches[1].to_javaname
|
23
|
-
elsif @full_name =~ /^[A-Z][^.]*$/
|
24
|
-
# simple name
|
25
|
-
@package = ''
|
26
|
-
@simple_name = self
|
27
|
-
else
|
28
|
-
# only package
|
29
|
-
@package = self
|
30
|
-
@simple_name = ''
|
31
|
-
end
|
8
|
+
module PackageLogic
|
9
|
+
|
10
|
+
# Return the package name of a classname or the name of the package. Return an empty String if default package.
|
11
|
+
# This returns just the plain String.
|
12
|
+
def package
|
13
|
+
@package
|
32
14
|
end
|
33
|
-
|
15
|
+
|
34
16
|
# Return +true+ if this class is in same or in a subpackage of the given Java _packages_ or
|
35
17
|
# if this package is same or a subpackage (with .).
|
36
18
|
def same_or_subpackage_of?(packages)
|
37
19
|
packages.find {|pkg| @package == pkg } != nil || subpackage_of?(packages)
|
38
20
|
end
|
39
|
-
|
21
|
+
|
40
22
|
# Return +true+ if this class is in a subpackage of the given Java _packages_ .
|
41
23
|
def subpackage_of?(packages)
|
42
|
-
packages.find {|pkg| @package =~ /^#{Regexp.escape(pkg)}
|
24
|
+
packages.find {|pkg| @package =~ /^#{Regexp.escape(pkg)}#{JavaLanguage::SEPARATOR_REGEX}/ } != nil
|
43
25
|
end
|
44
|
-
|
26
|
+
|
27
|
+
# Is this package or class in the JDK? Return the first JDK package this is inside or +nil+.
|
28
|
+
def in_jdk?
|
29
|
+
if @package && @package != ''
|
30
|
+
package_dot = @package + JavaLanguage::SEPARATOR
|
31
|
+
JavaLanguage::JDK_PACKAGES_REGEX.find { |package| package_dot =~ package }
|
32
|
+
else
|
33
|
+
# default package is never in JDK
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def package_remove_trailing_dot!
|
41
|
+
@package = @package[0..-2] if @package.size > 0 && @package[-1..-1] == JavaLanguage::SEPARATOR
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
# Mixin with logic to work with Java simple names. The "mixer" needs to declare a String field @simple_name.
|
47
|
+
# Author:: Peter Kofler
|
48
|
+
module SimpleNameLogic
|
49
|
+
|
50
|
+
# Return the simple name of this class or package.
|
51
|
+
# This returns just the plain String.
|
52
|
+
def simple_name
|
53
|
+
@simple_name
|
54
|
+
end
|
55
|
+
|
56
|
+
# Split the simple name at the camel case boundary _pos_ and return two parts. _pos_ may be < 0 for counting backwards.
|
57
|
+
def split_simple_name(pos)
|
58
|
+
parts = @simple_name.scan(/([A-Z][^A-Z]+)/).flatten
|
59
|
+
pos = parts.size + pos +1 if pos < 0
|
60
|
+
return ['', @simple_name] if pos <= 0
|
61
|
+
return [@simple_name, ''] if pos >= parts.size
|
62
|
+
[parts[0...pos].join, parts[pos..-1].join]
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# A full qualified package name. That is like <code>a.b.c</code>.
|
68
|
+
# Author:: Peter Kofler
|
69
|
+
class JavaPackageName < String
|
70
|
+
include PackageLogic
|
71
|
+
|
72
|
+
VALID_REGEX = /^ (?: #{JavaLanguage::IDENTIFIER_REGEX}#{JavaLanguage::SEPARATOR_REGEX} )*
|
73
|
+
#{JavaLanguage::LOWER_IDENTIFIER_REGEX}#{JavaLanguage::SEPARATOR_REGEX}? $/x
|
74
|
+
|
75
|
+
# Is _string_ a valid package name?
|
76
|
+
def self.valid?(string)
|
77
|
+
string =~ VALID_REGEX
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create a new package name _string_.
|
81
|
+
def initialize(string)
|
82
|
+
super string
|
83
|
+
if string =~ VALID_REGEX
|
84
|
+
@package = string
|
85
|
+
else
|
86
|
+
raise ArgumentError, "#{string} is no valid package name"
|
87
|
+
end
|
88
|
+
package_remove_trailing_dot!
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_javaname
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
# A full qualified class name. That is like <code>a.b.C</code>. Care has to be taken
|
98
|
+
# if this is used as hash key. String is treated special and the additional fields are lost
|
99
|
+
# when the key is retrieved from the Hash (because it is frozen).
|
100
|
+
# Author:: Peter Kofler
|
101
|
+
class JavaQualifiedName < String
|
102
|
+
include PackageLogic
|
103
|
+
include SimpleNameLogic
|
104
|
+
|
105
|
+
VALID_REGEX = /^ ( (?: #{JavaLanguage::IDENTIFIER_REGEX}#{JavaLanguage::SEPARATOR_REGEX} )* )
|
106
|
+
( #{JavaLanguage::IDENTIFIER_REGEX} ) $/x
|
107
|
+
|
108
|
+
# Is _string_ a valid qualified name?
|
109
|
+
def self.valid?(string)
|
110
|
+
string =~ VALID_REGEX
|
111
|
+
end
|
112
|
+
|
113
|
+
# Create a new qualified name _string_ with optional _jvmname_ and _classname_ classes which may be available.
|
114
|
+
def initialize(string, jvmname=nil, classname=nil)
|
115
|
+
super string
|
116
|
+
if string =~ VALID_REGEX
|
117
|
+
@package = $1 || ''
|
118
|
+
@simple_name = $2
|
119
|
+
@full_name = string
|
120
|
+
else
|
121
|
+
# TODO Implement qualified name logic for inner classes (e.g. CollectionUtils$IChecker)
|
122
|
+
raise ArgumentError, "#{string} is no valid qualified name"
|
123
|
+
end
|
124
|
+
package_remove_trailing_dot!
|
125
|
+
|
126
|
+
@jvm_name = jvmname
|
127
|
+
@class_name = classname
|
128
|
+
end
|
129
|
+
|
130
|
+
# Full normalized class name of this class. This returns just the plain String.
|
131
|
+
def full_name
|
132
|
+
@full_name
|
133
|
+
end
|
134
|
+
|
45
135
|
def to_javaname
|
46
136
|
self
|
47
137
|
end
|
48
138
|
|
49
139
|
# Return the full classname of this class, e.g. <code>java.lang.Object</code>.
|
50
140
|
def to_classname
|
51
|
-
|
141
|
+
self
|
52
142
|
end
|
53
|
-
|
143
|
+
|
54
144
|
# Return the VM name of this class, e.g. <code>java/lang/Object</code>.
|
55
145
|
def to_jvmname
|
56
|
-
|
146
|
+
return @jvm_name if @jvm_name
|
147
|
+
new_val = JavaVMName.new(@full_name.gsub(JavaLanguage::SEPARATOR, JavaVMName::SEPARATOR), self)
|
148
|
+
if frozen?
|
149
|
+
new_val
|
150
|
+
else
|
151
|
+
@jvm_name = new_val
|
152
|
+
end
|
57
153
|
end
|
58
|
-
|
59
|
-
# Return the Java source file name of this class, e.g. <code>java/lang/Object.java</code>.
|
154
|
+
|
155
|
+
# Return the Java source file name of this class, e.g. <code>java/lang/Object.java</code>. This is a plain String.
|
60
156
|
def to_java_file
|
61
|
-
(
|
157
|
+
@full_name.gsub(JavaLanguage::SEPARATOR, JavaClassFileName::SEPARATOR) + JavaLanguage::SOURCE
|
62
158
|
end
|
63
|
-
|
159
|
+
|
64
160
|
# Return the Java class file name of this class, e.g. <code>java/lang/Object.class</code>.
|
65
161
|
def to_class_file
|
66
|
-
|
162
|
+
return @class_name if @class_name
|
163
|
+
new_val = JavaClassFileName.new(@full_name.gsub(JavaLanguage::SEPARATOR, JavaClassFileName::SEPARATOR) + JavaLanguage::CLASS, self)
|
164
|
+
if frozen?
|
165
|
+
new_val
|
166
|
+
else
|
167
|
+
@class_name = new_val
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
# Delegation of JavaQualifiedName's methods. The "mixer" needs to define a method
|
174
|
+
# _to_classname_ which returns a JavaQualifiedName.
|
175
|
+
# Author:: Peter Kofler
|
176
|
+
module JavaQualifiedNameDelegation # :nodoc:
|
177
|
+
extend DelegateDirective
|
178
|
+
|
179
|
+
def to_javaname
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
delegate :package, :to_classname
|
184
|
+
delegate :simple_name, :to_classname
|
185
|
+
delegate :full_name, :to_classname
|
186
|
+
delegate :same_or_subpackage_of?, :to_classname
|
187
|
+
delegate :subpackage_of?, :to_classname
|
188
|
+
delegate :split_simple_name, :to_classname
|
189
|
+
delegate :in_jdk?, :to_classname
|
190
|
+
end
|
191
|
+
|
192
|
+
# A class name from the JVM. That is <code>a/b/C</code>. These names are read from the constant pool.
|
193
|
+
# Atoms and arrays are expressed as JVM names as well.
|
194
|
+
# Author:: Peter Kofler
|
195
|
+
class JavaVMName < String
|
196
|
+
include JavaQualifiedNameDelegation
|
197
|
+
|
198
|
+
SEPARATOR = '/'
|
199
|
+
SEPARATOR_REGEX = Regexp::escape(SEPARATOR)
|
200
|
+
ARRAY_REGEX = /^\[+L(.+);$|^\[+([A-Z])$/
|
201
|
+
VALID_REGEX = /^ (?: #{JavaLanguage::IDENTIFIER_REGEX}#{SEPARATOR_REGEX} )*
|
202
|
+
#{JavaLanguage::IDENTIFIER_REGEX} $/x
|
203
|
+
# Mapping of atoms to wrappers.
|
204
|
+
ATOMS = { 'B' => 'java/lang/Byte', 'S' => 'java/lang/Short', 'I' => 'java/lang/Integer', 'J' => 'java/lang/Long',
|
205
|
+
'F' => 'java/lang/Float', 'D' => 'java/lang/Double', 'Z' => 'java/lang/Booleam', 'C' => 'java/lang/Character' }
|
206
|
+
|
207
|
+
# Is _string_ a valid JVM name?
|
208
|
+
def self.valid?(string)
|
209
|
+
string =~ ARRAY_REGEX || string =~ VALID_REGEX
|
210
|
+
end
|
211
|
+
|
212
|
+
# Create a new JVM name _string_ with optional _qualified_ class which may be available.
|
213
|
+
def initialize(string, qualified=nil)
|
214
|
+
super string
|
215
|
+
|
216
|
+
if string =~ ARRAY_REGEX
|
217
|
+
@is_array = string[/^\[+/].length
|
218
|
+
string = string.sub(ARRAY_REGEX, '\1\2')
|
219
|
+
|
220
|
+
if string =~ /^[BSIJFDZC]$/
|
221
|
+
@is_atom = string
|
222
|
+
string = ATOMS[string]
|
223
|
+
else
|
224
|
+
@is_atom = false
|
225
|
+
end
|
226
|
+
|
227
|
+
else
|
228
|
+
@is_array = false
|
229
|
+
end
|
230
|
+
|
231
|
+
if string =~ VALID_REGEX
|
232
|
+
@jvm_name = string
|
233
|
+
else
|
234
|
+
raise ArgumentError, "#{string} is no valid JVM name"
|
235
|
+
end
|
236
|
+
@qualified_name = qualified
|
237
|
+
@class_name = nil
|
238
|
+
end
|
239
|
+
|
240
|
+
# Is this a bytecode array, e.g. represented by <code>[B</code>.
|
241
|
+
def array?
|
242
|
+
@is_array
|
243
|
+
end
|
244
|
+
|
245
|
+
def to_classname
|
246
|
+
return @qualified_name if @qualified_name
|
247
|
+
new_val = JavaQualifiedName.new(@jvm_name.gsub(SEPARATOR, JavaLanguage::SEPARATOR), self, nil)
|
248
|
+
if frozen?
|
249
|
+
new_val
|
250
|
+
else
|
251
|
+
@qualified_name = new_val
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def to_jvmname
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
def to_java_file
|
260
|
+
@jvm_name + JavaLanguage::SOURCE
|
67
261
|
end
|
68
262
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
263
|
+
def to_class_file
|
264
|
+
return @class_name if @class_name
|
265
|
+
new_val = JavaClassFileName.new(@jvm_name + JavaLanguage::CLASS, @qualified_name)
|
266
|
+
if frozen?
|
267
|
+
new_val
|
268
|
+
else
|
269
|
+
@class_name = new_val
|
270
|
+
end
|
77
271
|
end
|
272
|
+
|
78
273
|
end
|
79
|
-
|
274
|
+
|
275
|
+
# A Java class file name from the file system. That is <code>a/b/C.class</code>.
|
276
|
+
# These names are read from the FolderClasspath.
|
277
|
+
# Author:: Peter Kofler
|
278
|
+
class JavaClassFileName < String
|
279
|
+
include JavaQualifiedNameDelegation
|
280
|
+
|
281
|
+
SEPARATOR = '/'
|
282
|
+
SEPARATOR_REGEX = /\/|\\/
|
283
|
+
VALID_REGEX = /^ (?: #{JavaLanguage::IDENTIFIER_REGEX}#{SEPARATOR_REGEX} )*
|
284
|
+
#{JavaLanguage::IDENTIFIER_REGEX}
|
285
|
+
#{JavaLanguage::CLASS_REGEX} /x
|
286
|
+
|
287
|
+
# Is _string_ a valid class file name?
|
288
|
+
def self.valid?(string)
|
289
|
+
string =~ VALID_REGEX
|
290
|
+
end
|
291
|
+
|
292
|
+
# The plain file name of this class file.
|
293
|
+
attr_reader :file_name
|
294
|
+
|
295
|
+
# Create a new class file name _string_ with optional _qualified_ class which may be available.
|
296
|
+
def initialize(string, qualified=nil)
|
297
|
+
super string
|
298
|
+
if string =~ VALID_REGEX
|
299
|
+
@file_name = string.gsub(SEPARATOR_REGEX, SEPARATOR)
|
300
|
+
else
|
301
|
+
raise ArgumentError, "#{string} is no valid class file name"
|
302
|
+
end
|
303
|
+
@qualified_name = qualified
|
304
|
+
@jvm_name = nil
|
305
|
+
end
|
306
|
+
|
307
|
+
def to_classname
|
308
|
+
return @qualified_name if @qualified_name
|
309
|
+
new_val = JavaQualifiedName.new(
|
310
|
+
@file_name.gsub(SEPARATOR_REGEX, JavaLanguage::SEPARATOR).sub(JavaLanguage::CLASS_REGEX, ''),
|
311
|
+
nil, self)
|
312
|
+
if frozen?
|
313
|
+
new_val
|
314
|
+
else
|
315
|
+
@qualified_name = new_val
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def to_jvmname
|
320
|
+
return @jvm_name if @jvm_name
|
321
|
+
new_val = JavaVMName.new(@file_name.sub(JavaLanguage::CLASS_REGEX, ''), @qualified_name)
|
322
|
+
if frozen?
|
323
|
+
new_val
|
324
|
+
else
|
325
|
+
@jvm_name = new_val
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def to_java_file
|
330
|
+
@file_name.sub(JavaLanguage::CLASS_REGEX, JavaLanguage::SOURCE)
|
331
|
+
end
|
332
|
+
|
333
|
+
def to_class_file
|
334
|
+
self
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
|
80
339
|
end
|
81
340
|
|
82
341
|
class String
|
83
|
-
|
84
|
-
|
85
|
-
|
342
|
+
|
343
|
+
TYPES = [JavaClass::JavaClassFileName, JavaClass::JavaVMName, JavaClass::JavaPackageName, JavaClass::JavaQualifiedName]
|
344
|
+
|
345
|
+
# Convert a Java classname or Java class filename to special String with methods to work with Java
|
346
|
+
# class or package names. If it's a pathname then it must be relative to the classpath.
|
347
|
+
# Source extension and additional JVM method declarations are dropped.
|
86
348
|
def to_javaname
|
87
|
-
|
349
|
+
|
350
|
+
match = TYPES.find { |type| type.valid?(self) }
|
351
|
+
if match
|
352
|
+
return match.new(self)
|
353
|
+
end
|
354
|
+
|
355
|
+
plain_name = self.sub(/#{JavaClass::JavaLanguage::SOURCE_REGEX}|".*$|\.<.*$/, '').gsub(/\\/, '/')
|
356
|
+
match = TYPES.find { |type| type.valid?(plain_name) }
|
357
|
+
if match
|
358
|
+
match.new(plain_name)
|
359
|
+
else
|
360
|
+
raise ArgumentError, "unknown Java name #{self}"
|
361
|
+
end
|
88
362
|
end
|
89
|
-
|
363
|
+
|
90
364
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'javaclass/java_name'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
|
5
|
+
# TODO Implement hard coded class searching in ClassHeader as well
|
6
|
+
# 1) extract common usage classes from here, to be used from 2 places
|
7
|
+
# 2) make nice convenience methods here, which get mixed into the DSL, so it's easy
|
8
|
+
# 3) add logic to ImportedTypes, which returnes the hardcoded_types, and hardcoded_3rd_party_types
|
9
|
+
# wich scans Java String constants of classes to find Class.Forname
|
10
|
+
# will use the JavaNameScanner module as private inclusion!
|
11
|
+
# ImportedTypes new method all_types = is the old one so calling code stays the same
|
12
|
+
# and a new one is declared_types and hardcoded ,
|
13
|
+
# 4) add 2 methods to Dependencies, so it's also with all hardcoded types possible - automatically, no extra method
|
14
|
+
# will use the JavaNameScanner module as private inclusion!
|
15
|
+
|
16
|
+
# Mixin with logic to scan for hard coded class names.
|
17
|
+
# Author:: Peter Kofler
|
18
|
+
module JavaNameScanner
|
19
|
+
|
20
|
+
def scan_config_for_3rd_party_class_names(path)
|
21
|
+
scan_config_for_class_names(path).reject { |name| name.in_jdk? }
|
22
|
+
# need abstraction for - .reject { |name| name.in_jdk? } - have it three times
|
23
|
+
# maybe a mixin for enumerables containing JavaTypes
|
24
|
+
#JavaNameEnumerable with - .reject { |name| name.in_jdk? } - und anderen? reject_in_jdk = 3rd Party
|
25
|
+
# and find_all { |n| n.same_or_subpackage_of?(x) } -- also very often = in_package()
|
26
|
+
end
|
27
|
+
|
28
|
+
# Find all possible class names in all XML and property files under _path_
|
29
|
+
def scan_config_for_class_names(path)
|
30
|
+
return unless File.exist? path
|
31
|
+
if File.file?(path)
|
32
|
+
if path =~ /\.xml$|\.properties$|MANIFEST.MF$/
|
33
|
+
scan_text_for_class_names(IO.readlines(path).join)
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
else
|
38
|
+
Dir.entries(path).reject { |n| n=~/^\./ }.map { |n| scan_config_for_class_names(File.join(path, n)) }.flatten.sort
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
TEXT_REGEX = /
|
43
|
+
(?:^|>|"|'|=|:)
|
44
|
+
\s*
|
45
|
+
( (?:#{JavaLanguage::IDENTIFIER_REGEX}#{JavaLanguage::SEPARATOR_REGEX})+#{JavaLanguage::TYPE_REGEX} )
|
46
|
+
\s*
|
47
|
+
(?:$|<|"|'|:)
|
48
|
+
/x
|
49
|
+
|
50
|
+
# Extract the list of possible class names from the given _string_ . This will only find
|
51
|
+
# names with at least one package name.
|
52
|
+
def scan_text_for_class_names(string)
|
53
|
+
string.scan(TEXT_REGEX).flatten.map { |match| JavaQualifiedName.new(match) }
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# -- Class Scanner
|
59
|
+
# init
|
60
|
+
# @hardcoded_types = scan_config_for_class_names
|
61
|
+
#
|
62
|
+
# # Determine the imported types of this class and return their names. This does not contain the name if this class itself.
|
63
|
+
# def hardcoded_types
|
64
|
+
# @hardcoded_types
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# # Determine the imported types of this class which are not from the JDK. This are all hardcoded_types - all jdk types.
|
68
|
+
# def hardcoded_3rd_party_types
|
69
|
+
# hardcoded_types.reject { |name| name.in_jdk? }
|
70
|
+
# end
|
71
|
+
|
72
|
+
# -- Analyse - add to Dependencies (automatically, no extra method)
|
73
|
+
# # Determine all imported types from all classes in this classpath together with count of imports.
|
74
|
+
# # An additional block is used as _filter_ on class names.
|
75
|
+
# def hardcoded_types(&filter)
|
76
|
+
# type_map = Hash.new(0) # class_name (JavaQualifiedName) => cnt
|
77
|
+
# hardcoded_3rd_party_types.each do |type|
|
78
|
+
# # hash keys need to be frozen to keep state
|
79
|
+
# if !type_map.include?(type)
|
80
|
+
# type = type.freeze
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# type_map[type] += 1
|
84
|
+
# end
|
85
|
+
# type_map
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # Determine all hardcoded types from all classes in this classpath.
|
89
|
+
# # An additional block is used as _filter_ on class names.
|
90
|
+
# def external_types(&filter)
|
91
|
+
# used_types(&filter).keys.sort
|
92
|
+
# end
|
93
|
+
|
94
|
+
end
|
95
|
+
|