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.
Files changed (175) hide show
  1. data/Rakefile +67 -56
  2. data/Readme.txt +42 -39
  3. data/example_task.rb +172 -0
  4. data/examples/check_interface_names.rb +44 -0
  5. data/examples/corpus.rb +19 -0
  6. data/examples/count_classes_in_modules.rb +38 -0
  7. data/examples/cumulative_dependencies.rb +39 -0
  8. data/examples/find_all_imported_types.rb +44 -0
  9. data/examples/find_referenced_modules.rb +53 -0
  10. data/examples/find_unreferenced_classes.rb +65 -0
  11. data/examples/generate_class_lists.rb +67 -43
  12. data/examples/profiler_scratchpad.rb +33 -0
  13. data/examples/simple_usage.rb +42 -0
  14. data/history.txt +29 -7
  15. data/javaclass.gemspec +31 -0
  16. data/lib/javaclass/adder_tree.rb +92 -0
  17. data/lib/javaclass/analyse/dependencies.rb +52 -0
  18. data/lib/javaclass/{metric/metrics.txt → analyse/ideas.txt} +2 -2
  19. data/lib/javaclass/analyse/transitive_dependencies.rb +52 -0
  20. data/lib/javaclass/classfile/access_flag_constants.rb +24 -0
  21. data/lib/javaclass/classfile/access_flags.rb +49 -26
  22. data/lib/javaclass/classfile/class_format_error.rb +37 -0
  23. data/lib/javaclass/classfile/class_magic.rb +16 -8
  24. data/lib/javaclass/classfile/class_version.rb +19 -25
  25. data/lib/javaclass/classfile/constant_pool.rb +110 -45
  26. data/lib/javaclass/classfile/constants/base.rb +33 -12
  27. data/lib/javaclass/classfile/constants/double_reference.rb +55 -41
  28. data/lib/javaclass/classfile/constants/single_reference.rb +29 -21
  29. data/lib/javaclass/classfile/constants/value.rb +43 -33
  30. data/lib/javaclass/classfile/java_class_header.rb +72 -46
  31. data/lib/javaclass/classfile/java_class_header_as_java_name.rb +33 -0
  32. data/lib/javaclass/classfile/java_class_header_shortcuts.rb +19 -0
  33. data/lib/javaclass/classfile/references.rb +21 -19
  34. data/lib/javaclass/classlist/class_entry.rb +26 -27
  35. data/lib/javaclass/classlist/jar_searcher.rb +34 -25
  36. data/lib/javaclass/classlist/list.rb +31 -31
  37. data/lib/javaclass/classlist/package_entry.rb +25 -24
  38. data/lib/javaclass/classpath/any_classpath.rb +48 -0
  39. data/lib/javaclass/classpath/class_not_found_error.rb +20 -0
  40. data/lib/javaclass/classpath/classpaths.txt +2 -2
  41. data/lib/javaclass/classpath/composite_classpath.rb +56 -54
  42. data/lib/javaclass/classpath/convention_classpath.rb +38 -0
  43. data/lib/javaclass/classpath/eclipse_classpath.rb +74 -0
  44. data/lib/javaclass/classpath/factory.rb +65 -0
  45. data/lib/javaclass/classpath/file_classpath.rb +47 -0
  46. data/lib/javaclass/classpath/folder_classpath.rb +42 -44
  47. data/lib/javaclass/classpath/jar_classpath.rb +91 -52
  48. data/lib/javaclass/classpath/java_home_classpath.rb +24 -13
  49. data/lib/javaclass/classpath/maven_classpath.rb +44 -0
  50. data/lib/javaclass/classpath/temporary_unpacker.rb +111 -0
  51. data/lib/javaclass/classpath/tracking_classpath.rb +144 -0
  52. data/lib/javaclass/classscanner/ideas.txt +3 -0
  53. data/lib/javaclass/classscanner/imported_types.rb +29 -0
  54. data/lib/javaclass/classscanner/scanners.rb +29 -0
  55. data/lib/javaclass/delegate_directive.rb +15 -0
  56. data/lib/javaclass/dsl/caching_classpath.rb +38 -0
  57. data/lib/javaclass/dsl/classpath_analysers.rb +27 -0
  58. data/lib/javaclass/dsl/java_name_factory.rb +79 -0
  59. data/lib/javaclass/dsl/loader.rb +42 -0
  60. data/lib/javaclass/dsl/loading_classpath.rb +53 -0
  61. data/lib/javaclass/dsl/mixin.rb +54 -0
  62. data/lib/javaclass/gems/zip_file.rb +154 -0
  63. data/lib/javaclass/java_language.rb +50 -0
  64. data/lib/javaclass/java_name.rb +329 -55
  65. data/lib/javaclass/java_name_scanner.rb +95 -0
  66. data/lib/javaclass/resources/iso_3166_countries.txt +240 -0
  67. data/lib/javaclass/resources/jdk0_packages.txt +6 -0
  68. data/lib/javaclass/resources/jdk1_packages.txt +6 -0
  69. data/lib/javaclass/resources/jdk2_packages.txt +4 -0
  70. data/lib/javaclass/resources/jdk3_packages.txt +6 -0
  71. data/lib/javaclass/resources/jdk4_packages.txt +22 -0
  72. data/lib/javaclass/resources/jdk5_packages.txt +5 -0
  73. data/lib/javaclass/resources/jdk6_packages.txt +7 -0
  74. data/lib/javaclass/resources/jdk7_packages.txt +0 -0
  75. data/lib/javaclass/resources/jdk_packages.txt +53 -0
  76. data/lib/javaclass/resources/reserved_words.txt +50 -0
  77. data/lib/javaclass/string_hexdump.rb +76 -0
  78. data/lib/javaclass/string_ux.rb +21 -10
  79. data/lib/javaclass.rb +16 -41
  80. data/license.txt +28 -0
  81. data/planned.txt +13 -0
  82. data/test/data/Object_102.class +0 -0
  83. data/test/data/Runnable_102.class +0 -0
  84. data/test/data/access_flags/AccessFlagsTestAnnotation.class +0 -0
  85. data/test/data/access_flags/AccessFlagsTestAnnotation.java +3 -0
  86. data/test/data/access_flags/AccessFlagsTestEnum$1.class +0 -0
  87. data/test/data/access_flags/AccessFlagsTestEnum.class +0 -0
  88. data/test/data/access_flags/AccessFlagsTestEnum.java +6 -0
  89. data/test/data/access_flags/AccessFlagsTestInner$1.class +0 -0
  90. data/test/data/access_flags/AccessFlagsTestInner$2.class +0 -0
  91. data/test/data/access_flags/AccessFlagsTestInner.class +0 -0
  92. data/test/data/access_flags/AccessFlagsTestInner.java +13 -0
  93. data/test/data/access_flags/AccessFlagsTestPackage.class +0 -0
  94. data/test/data/access_flags/AccessFlagsTestPackage.java +1 -1
  95. data/test/data/api/packagename/AccessFlagsTestPublic.class +0 -0
  96. data/test/data/class_version/ClassVersionTest17.class +0 -0
  97. data/test/data/class_version/make.bat +6 -2
  98. data/test/data/eclipse_classpath/classes/ClassVersionTest12.class +0 -0
  99. data/test/data/eclipse_classpath/lib/JarClasspathTest.jar +0 -0
  100. data/test/data/eclipse_classpath/test-classes/ClassVersionTest13.class +0 -0
  101. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/ClassVersionTest10.class +0 -0
  102. data/test/data/folder_classpath/{JarClasspathTestFolder → classes}/package/ClassVersionTest11.class +0 -0
  103. data/test/data/jar_classpath/JarClasspathTest.jar +0 -0
  104. data/test/data/jar_classpath/JarClasspathTest.zip +0 -0
  105. data/test/data/jar_classpath/JarClasspathTestManifest.jar +0 -0
  106. data/test/data/jar_classpath/JarClasspathTestMultiManifest.jar +0 -0
  107. data/test/data/jar_classpath/make.bat +6 -2
  108. data/test/data/jar_searcher/BrokenRunnable_102.class +0 -0
  109. data/test/data/java_home_classpath/jdk118/lib/classes.zip +0 -0
  110. data/test/data/java_name_scanner/META-INF/MANIFEST.MF +12 -0
  111. data/test/data/java_name_scanner/plugin.xml +18 -0
  112. data/test/data/maven_classpath/module/pom.xml +8 -0
  113. data/test/data/maven_classpath/module/target/classes/ClassVersionTest12.class +0 -0
  114. data/test/data/maven_classpath/pom.xml +8 -0
  115. data/test/data/maven_classpath/target/classes/ClassVersionTest10.class +0 -0
  116. data/test/data/maven_classpath/target/test-classes/ClassVersionTest11.class +0 -0
  117. data/test/data/transitive_dependencies/A.class +0 -0
  118. data/test/data/transitive_dependencies/A.java +5 -0
  119. data/test/data/transitive_dependencies/B.class +0 -0
  120. data/test/data/transitive_dependencies/B.java +3 -0
  121. data/test/data/transitive_dependencies/C.class +0 -0
  122. data/test/data/transitive_dependencies/C.java +3 -0
  123. data/test/data/transitive_dependencies/Start.class +0 -0
  124. data/test/data/transitive_dependencies/Start.java +4 -0
  125. data/test/data/transitive_dependencies/make.bat +3 -0
  126. data/test/data/zip_file/commons-math-2.2-broken.zip +0 -0
  127. data/test/data/zip_file/regenerated-with-7zip.zip +0 -0
  128. data/test/data/zip_file/regenerated-with-jar.zip +0 -0
  129. data/test/dot_classpath.rb +33 -0
  130. data/test/logging_folder_classpath.rb +19 -0
  131. data/test/setup.rb +1 -1
  132. data/test/test_access_flags.rb +58 -32
  133. data/test/test_adder_tree.rb +78 -0
  134. data/test/test_any_classpath.rb +39 -0
  135. data/test/test_base.rb +9 -7
  136. data/test/test_caching_classpath.rb +41 -0
  137. data/test/test_class_entry.rb +60 -60
  138. data/test/test_class_magic.rb +31 -0
  139. data/test/test_class_version.rb +25 -25
  140. data/test/test_composite_classpath.rb +22 -23
  141. data/test/test_constant_pool.rb +37 -13
  142. data/test/test_convention_classpath.rb +39 -0
  143. data/test/test_eclipse_classpath.rb +73 -0
  144. data/test/test_factory.rb +61 -0
  145. data/test/test_folder_classpath.rb +26 -10
  146. data/test/test_imported_types.rb +34 -0
  147. data/test/test_jar_classpath.rb +29 -14
  148. data/test/test_jar_searcher.rb +27 -14
  149. data/test/test_java_class_header.rb +22 -10
  150. data/test/test_java_class_header_as_java_name.rb +41 -0
  151. data/test/test_java_home_classpath.rb +17 -11
  152. data/test/test_java_name.rb +204 -64
  153. data/test/test_java_name_factory.rb +52 -0
  154. data/test/test_java_name_scanner.rb +24 -0
  155. data/test/test_javaclass_api.rb +43 -0
  156. data/test/test_list.rb +58 -44
  157. data/test/test_load_directive.rb +34 -0
  158. data/test/test_maven_classpath.rb +46 -0
  159. data/test/test_package_entry.rb +27 -22
  160. data/test/test_references.rb +14 -14
  161. data/test/test_string_hexdump.rb +24 -0
  162. data/test/test_string_ux.rb +18 -106
  163. data/test/test_tracking_classpath.rb +112 -0
  164. data/test/test_transitive_dependencies.rb +31 -0
  165. data/test/test_unpacking_jar_classpath.rb +43 -0
  166. data/test/test_zip_file.rb +33 -0
  167. data/test/ts_all_tests.rb +80 -18
  168. data/thanks.txt +2 -0
  169. metadata +151 -22
  170. data/lib/javaclass/classpath/port_ClassPathEntry.java +0 -202
  171. data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +0 -311
  172. data/lib/javaclass/classpath/port_DirectoryRepository.java +0 -24
  173. data/lib/javaclass/metric/ccd.rb +0 -68
  174. data/lib/javaclass/metric/class_usage.rb +0 -41
  175. data/test/test_javaclass.rb +0 -22
@@ -1,90 +1,364 @@
1
+ require 'javaclass/java_language'
2
+ require 'javaclass/delegate_directive'
3
+
1
4
  module JavaClass
2
-
3
- # Special string with methods to work with Java class or package names.
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
- class JavaName < String
6
-
7
- # Return the package name of a classname or the superpackage of a package. Return an empty String if default package.
8
- attr_reader :package
9
-
10
- # Return the simple name of this class or package.
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)}\./ } != nil
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
- @full_name.to_javaname
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
- (@full_name.gsub(/\./, '/')).to_javaname
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
- (to_jvmname + '.java').to_javaname
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
- (to_jvmname + '.class').to_javaname
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
- # Split the simple name at the camel case boundary _pos_ and return two parts. _pos_ may
70
- # be < 0 for counting backwards.
71
- def split_simple_name(pos)
72
- parts = @simple_name.scan(/([A-Z][^A-Z]+)/).flatten
73
- pos = parts.size + pos +1 if pos < 0
74
- return ['', @simple_name] if pos <= 0
75
- return [@simple_name, ''] if pos >= parts.size
76
- [parts[0...pos].join, parts[pos..-1].join]
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
- # Convert a Java classname or Java class filename to JavaClass::JavaName instance.
85
- # If it's a pathname then it must be relative to the classpath.
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
- JavaClass::JavaName.new(self)
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
+