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
@@ -0,0 +1,44 @@
1
+ # Example usage of the class analysis featuress of JavaClass::ClassScanner and JavaClass::Analyse.
2
+ # After defining a classpath, use dependency analysis to find all used classes of a codebase.
3
+ # This code uses in turn the method <i>imported_3rd_party_types</i> of
4
+ # JavaClass::ClassScanner::ImportedTypes to find all imported classes.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:Lib]
17
+ prod_location = File.join(location, '..', 'classes')
18
+ test_location = File.join(location, 'classes')
19
+ conf_location = location
20
+ #++
21
+ require 'javaclass/dsl/mixin'
22
+
23
+ # 1) create the classpath of production classes
24
+ cp = classpath(prod_location)
25
+
26
+ # 2) remember all types defined on this classpath from JavaClass::Analyse::Dependencies
27
+ prod_classnames = cp.types
28
+
29
+ # 3) collect all dependencies of all classes defined there
30
+ imported_classnames = cp.used_types
31
+
32
+ # 4) also collect all classes referenced from config files, defined in JavaClass::JavaNameScanner
33
+ hardcoded_classnames = scan_config_for_3rd_party_class_names(conf_location)
34
+
35
+ # 5) now we know all classes imported/used by production classes
36
+ puts '---------- used 3rd party types in production'
37
+ used_classnames = (imported_classnames + hardcoded_classnames).uniq.sort - prod_classnames
38
+ puts used_classnames
39
+
40
+ # 6) do the same for test classes, at least org.junit.* should show up here
41
+ test_cp = classpath(test_location)
42
+ puts '---------- used 3rd party types only in tests'
43
+ test_classes = test_cp.external_types - prod_classnames - used_classnames
44
+ puts test_classes
@@ -0,0 +1,53 @@
1
+ # Example usage of JavaClass::Classpath and JavaClass::Classpath::TrackingClasspath:
2
+ # Use the classes of one module and mark all their dependencies. Then find all modules
3
+ # which were not referenced. This list contains *potential* unused libraries (modules).
4
+ # Note that the libraries may still be used by reflection or internal from other libraries.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:HBD]
17
+ location = Corpus[:RCP]
18
+ location = Corpus[:BIA]
19
+
20
+ main_location = File.join(location, 'classes')
21
+ test_location = File.join(location, 'test-classes')
22
+ #++
23
+ require 'javaclass/dsl/mixin'
24
+
25
+ # 1) create a classpath of the main module(s) under test
26
+ main_classpath = classpath("#{main_location};#{test_location}")
27
+ puts "#{main_classpath.count} classes found in main classpath:"
28
+ puts " #{main_classpath.elements.join("\n ")}"
29
+
30
+ # 2) mix in JavaClass::Classpath::TrackingClasspath before creating any new classpaths
31
+ require 'javaclass/classpath/tracking_classpath'
32
+
33
+ # 3) create the (tracking) composite classpath of the given workspace
34
+ cp = workspace(location)
35
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}"
36
+ puts " #{cp.elements.join("\n ")}"
37
+ puts "#{cp.count} classes found in classpaths"
38
+
39
+ # 4) mark all their referenced types as accessed in the workspace
40
+ puts 'mapping referenced classes... (can take several minutes)'
41
+ cp.reset_access
42
+ main_classpath.external_types.each { |clazz| cp.mark_accessed(clazz) }
43
+ puts 'referenced classes mapped'
44
+
45
+ # 5a) now find non accessed modules/libraries (i.e. classpath elements)
46
+ unused = cp.elements.find_all { |clp| clp.jar? && clp.accessed == 0 }
47
+ puts "\n#{unused.size} unused modules found:\n #{unused.join("\n ")}"
48
+
49
+ # 5b) or print the list of classpath elements (e.g. JARs) with their access
50
+ puts "\nlibrary (module path): number of accessed classes"
51
+ puts cp.elements.map { |clp| [clp.to_s, clp.accessed] }.
52
+ sort { |a,b| a[1] <=> b[1] }.
53
+ map { |e| " #{e[0]}: #{e[1]}" }
@@ -0,0 +1,65 @@
1
+ # Advanced example usage of JavaClass::Classpath::TrackingClasspath. Load all
2
+ # classes of an Eclipse workspace. Then mark all referenced classes. In the end
3
+ # report remaining classes as unreferenced. This lists *potential* unused classes.
4
+ # Note that the classes may still be used by reflection.
5
+ # Author:: Peter Kofler
6
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
7
+ # License:: {BSD License}[link:/files/license_txt.html]
8
+ #
9
+ # === Steps
10
+
11
+ #--
12
+ # add the lib of this gem to the load path
13
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
14
+ require File.join(File.dirname(__FILE__), 'corpus')
15
+
16
+ location = Corpus[:RCP]
17
+ package1 = 'com.ibm.arc.sdm'
18
+ package2 = 'pricingTool'
19
+ #++
20
+ require 'javaclass/dsl/mixin'
21
+ require 'javaclass/classpath/tracking_classpath'
22
+
23
+ # speed up loading by skipping non source file classpaths
24
+ Eclipse.skip_lib
25
+
26
+ # 1) create the (tracking) composite classpath of the given workspace
27
+ cp = workspace(location)
28
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}:"
29
+ puts " #{cp.elements.join("\n ")}"
30
+
31
+ # create a filter to limit all operations to the classes of two base packages
32
+ filter = Proc.new { |clazz| clazz.same_or_subpackage_of?(package1) ||
33
+ clazz.same_or_subpackage_of?(package2) }
34
+
35
+ # 2) load all classes in the given packages
36
+ puts 'loading all *filtered* classes... (can take several minutes)'
37
+ classes = cp.values(&filter)
38
+ puts "#{classes.size} classes loaded from classpaths"
39
+
40
+ # 3) mark all referenced types in the given packages as accessed
41
+ cp.reset_access
42
+ classes.map { |clazz| clazz.imported_types }.
43
+ flatten.
44
+ find_all(&filter).
45
+ each { |classname| cp.mark_accessed(classname) }
46
+ puts '*filtered* classes mapped'
47
+
48
+ # 4) also mark all classes referenced from config files (e.g. hardcoded class names)
49
+ hardcoded_classnames = scan_config_for_3rd_party_class_names(location).find_all(&filter)
50
+ puts "#{hardcoded_classnames.size} classes references found in configs"
51
+ hardcoded_classnames.each { |classname| cp.mark_accessed(classname) }
52
+ puts 'hardcoded classes mapped'
53
+
54
+ # 5) mark unit tests (all classes ending in Test) on the test projects (classpath elements ending in .test)
55
+ test_projects = cp.elements.find_all { |cpe| cpe.to_s =~ /\.test\// }
56
+ test_projects.each do |project|
57
+ project.names { |classname| classname =~ /Test(?:Case|Suite|s)?\.class/ }.
58
+ each { |classname| project.mark_accessed(classname) }
59
+ end
60
+ puts 'test classes mapped'
61
+
62
+ # 6) find non accessed classes in specific packages and report them
63
+ unused_classes = classes.find_all { |clazz| cp.accessed(clazz) == 0 }
64
+ report = unused_classes.map { |clazz| "#{clazz.to_classname}" }
65
+ puts "#{report.size} unused classes found:\n #{report.join("\n ")}"
@@ -1,61 +1,85 @@
1
+ # Generate a JavaClass::ClassList, which contains all class
2
+ # names with version numbers when introduced. The list is created
3
+ # iterating all JDKs, opening the RT.jars and loading all classes.
4
+ # Author:: Peter Kofler
5
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
6
+ # License:: {BSD License}[link:/files/license_txt.html]
7
+ #
8
+ # === Usage
9
+
10
+ #--
11
+ # add the lib of this gem to the load path
1
12
  $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
- require 'javaclass/classlist/list'
13
+ #++
3
14
  require 'javaclass/classlist/jar_searcher'
4
-
5
- # Generate the full class lists starting from a saved one.
6
- # Author:: Peter Kofler
7
- puts "create full class lists for JDKs (by search and open class)"
15
+ require 'javaclass/classpath/jar_classpath'
16
+ require 'javaclass/classlist/list'
8
17
 
9
18
  # Struct to keep configuration what kind of JDK classes should be searched and added.
10
19
  JDK_CONFIG = Struct.new(:version, :label, :paths)
11
- # Define information about JDK to process one after another.
20
+
21
+ #--
22
+ # Windows 7 configuration for 32bit Sun/Oracle JVMs
23
+ PROGRAMS = 'C:\Program Files (x86)\Java'
12
24
  JDKS = [
13
- JDK_CONFIG.new(0, "1.0.2", ['E:\Develop\Java\Compiler\jdk1.0.2\lib']),
14
- JDK_CONFIG.new(1, "1.1.8-09", ['E:\Develop\Java\Compiler\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
15
- JDK_CONFIG.new(2, "1.2.2-13", ['C:\Programme\Java\jdk1.2.2_13\jre\lib', 'C:\Programme\Java\jdk1.2.2_13\lib\dt.jar']),
16
- JDK_CONFIG.new(3, "1.3.1-08", ['C:\Programme\Java\jdk1.3.1_08\jre\lib', 'C:\Programme\Java\jdk1.3.1_08\lib\dt.jar']),
17
- JDK_CONFIG.new(4, "1.4.2-03", ['C:\Programme\Java\jdk1.4.2_03\jre\lib', 'C:\Programme\Java\jdk1.4.2_03\lib\dt.jar']),
18
- JDK_CONFIG.new(5, "1.5.0-07", ['C:\Programme\Java\jdk1.5.0_07\jre\lib', 'C:\Programme\Java\jdk1.5.0_07\lib\dt.jar']),
19
- JDK_CONFIG.new(6, "1.6.0-11", ['C:\Programme\Java\jdk1.6.0_21\jre\lib', 'C:\Programme\Java\jdk1.6.0_21\lib\dt.jar']),
20
- #JDK_CONFIG.new(7, "1.7.0-xx", ['C:\Programme\Java\jdk1.7.0_xx\jre\lib']),
25
+ JDK_CONFIG.new(0, '1.0.2', ['E:\Develop\Java\Compiler\jdk1.0.2\lib']),
26
+ JDK_CONFIG.new(1, '1.1.8-09', ['E:\Develop\Java\Compiler\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
27
+ JDK_CONFIG.new(2, '1.2.2-13', [PROGRAMS + '\jdk1.2.2_13\jre\lib', PROGRAMS + '\jdk1.2.2_13\lib\dt.jar']),
28
+ JDK_CONFIG.new(3, '1.3.1-08', [PROGRAMS + '\jdk1.3.1_08\jre\lib', PROGRAMS + '\jdk1.3.1_08\lib\dt.jar']),
29
+ JDK_CONFIG.new(4, '1.4.2-03', [PROGRAMS + '\jdk1.4.2_03\jre\lib', PROGRAMS + '\jdk1.4.2_03\lib\dt.jar']),
30
+ JDK_CONFIG.new(5, '1.5.0-07', [PROGRAMS + '\jdk1.5.0_07\jre\lib', PROGRAMS + '\jdk1.5.0_07\lib\dt.jar']),
31
+ JDK_CONFIG.new(6, '1.6.0-26', [PROGRAMS + '\jdk1.6.0_26\jre\lib', PROGRAMS + '\jdk1.6.0_26\lib\dt.jar']),
32
+ JDK_CONFIG.new(7, '1.7.0', [PROGRAMS + '\jdk1.7.0\jre\lib', PROGRAMS + '\jdk1.7.0\lib\dt.jar']),
21
33
  ]
34
+ #++
35
+ # configuration for some JDKs
36
+ # JDKS = [ JDK_CONFIG.new(...), ... ]
22
37
 
23
- BASE_NAME = 'fullClassList'
24
-
25
- # Create a new list
26
- @list = JavaClass::ClassList::List.new
27
-
28
- # load already good list if we do not start with JDK 1.0
29
- if JDKS[0].version > 0
30
- old_version = JDKS[0].version-1
31
- old_class_list_name = Dir["./#{BASE_NAME}?#{old_version}?.txt"].first
32
- if FileTest.exist?(old_class_list_name)
33
- puts "loading #{old_version}"
34
- IO.readlines(old_class_list_name).each {|line| @list.parse_line(line, old_version) }
35
- end
36
- end
38
+ # 1) create a JavaClass::ClassList::JarSearcher
39
+ JavaClass.unpack_jars!(:unpack)
40
+ searcher = JavaClass::ClassList::JarSearcher.new
37
41
 
38
- # init the searcher
39
- @searcher = JavaClass::ClassList::JarSearcher.new
40
- @searcher.filters = %w[sun/ sunw/ com/sun/ netscape/ COM/rsa/ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
42
+ # 2) filter out unwanted classes, e.g. vendor classes
43
+ searcher.filters = %w[sun/ sunw/ com/oracle/ com/sun/ netscape/ COM/rsa/
44
+ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
45
+ #--
41
46
  # netscape ... applet js security [2]
42
47
  # COM/rsa/ ... jsafe [4]
43
48
  # quicktime ... quicktime [5]
44
49
  # org/jcp/xml/dsig/internal ... xml dsig [6]
50
+ # com/oracle/ ... com.oracle.net.Sdp [7]
51
+
52
+ Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
53
+ #++
45
54
 
46
- #Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
55
+ # 3) create a new JavaClass::ClassList::List to contain the classes
56
+ list = JavaClass::ClassList::List.new
47
57
 
48
- # Work on all lists defined in +JDK+ and yield the block with the jdk label and the class list.
58
+ #--
59
+ # load an already good list if we do not start with JDK 1.0
60
+ if JDKS[0].version > 0
61
+ full_class_list_version = JDKS[0].version - 1
62
+ full_class_list = "fullClassList1#{full_class_list_version}0.txt"
63
+ IO.readlines(full_class_list).each {|line| list.parse_line(line, full_class_list_version) }
64
+ puts "loaded full class list #{full_class_list} with versions #{list.version}"
65
+ end
66
+ #++
67
+
68
+ # Work on all lists defined in +JDKS+, add to the list and write list files.
49
69
  JDKS.each do |conf|
50
- puts "processing #{conf.version}"
51
- conf.paths.each { |p| @list = @searcher.compile_list(conf.version, p, @list) }
52
-
53
- #basename = "jdk#{conf.label.gsub(/\./, '')}"
54
- #File.open("./ClassLists/#{basename}_new_package_classes.txt", "w") { |f| f.print @list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
55
- #File.open("./ClassLists/#{basename}_all_classes.txt", "w") { |f| f.print @list.plain_class_list }
56
- #File.open("./ClassLists/#{basename}_all_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? } }
57
- #File.open("./ClassLists/#{basename}_new_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
58
-
70
+ # 4) iterate JARs and compile a list
71
+ conf.paths.each { |p| list = searcher.compile_list(conf.version, p, list) }
72
+
73
+ # 5) save various kind of lists
74
+ basename = "./ClassLists/jdk#{conf.label.gsub(/\./, '')}"
75
+ File.open("#{basename}_new_package_classes.txt", "w") { |f| f.print list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
76
+ File.open("#{basename}_all_classes.txt", "w") { |f| f.print list.plain_class_list }
77
+ File.open("#{basename}_all_packages.txt", "w") { |f| f.print list.to_s }
78
+ File.open("#{basename}_all_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? } }
79
+ File.open("#{basename}_new_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
80
+
59
81
  baseversion = conf.label.gsub(/\.|-.+$/, '')
60
- File.open("./#{BASE_NAME}#{baseversion}.txt", "w") { |f| f.print @list.full_class_list }
82
+ File.open("./fullClassList#{baseversion}.txt", "w") { |f| f.print list.full_class_list }
83
+
84
+ puts "processed #{conf.label}"
61
85
  end
@@ -0,0 +1,33 @@
1
+ # :nodoc:
2
+ # Scratchpad script for profiler execution.
3
+
4
+ require 'ruby-prof'
5
+
6
+ # add the lib of this gem to the load path
7
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
8
+ require 'javaclass/dsl/mixin'
9
+ require File.join(File.dirname(__FILE__), 'corpus')
10
+
11
+ location = File.join(Corpus[:BIA], 'classes')
12
+
13
+ # 1) create a classpath of the given workspace
14
+ #RubyProf.start
15
+ cp = classpath(location)
16
+ puts "#{cp.elements.size} classpaths found under the workspace #{location}:\n #{cp.elements.join("\n ")}"
17
+ puts "#{cp.count} classes found in classpaths"
18
+ #result = RubyProf.stop
19
+
20
+ # 2) load all classes
21
+ RubyProf.start
22
+ cp.values
23
+ result = RubyProf.stop
24
+
25
+ # 3) iterate all constant pool entries
26
+ #RubyProf.start
27
+ # workspace.external_types
28
+ #result = RubyProf.stop
29
+
30
+ # Print a flat profile to text
31
+ printer = RubyProf::GraphPrinter.new(result)
32
+ # printer = RubyProf::FlatPrinter.new(result)
33
+ printer.print(STDOUT)
@@ -0,0 +1,42 @@
1
+ # Example of basic usage of JavaClass to load and inspect class files.
2
+ # Author:: Peter Kofler
3
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
4
+ # License:: {BSD License}[link:/files/license_txt.html]
5
+ #
6
+ # === Usage
7
+
8
+ #--
9
+ # add the lib of this gem to the load path
10
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
11
+ #++
12
+ # 1) require the basic module
13
+ require 'javaclass'
14
+
15
+ # 2a) load a class directly from the file system
16
+ clazz = JavaClass.load_fs('./test/data/access_flags/AccessFlagsTestPublic.class')
17
+
18
+ # 2b) or get a class from the system classpath which needs _JAVA_HOME_ to be set
19
+ cp = JavaClass.environment_classpath
20
+ puts cp.includes?('java/lang/String.class') # => 1 (true)
21
+
22
+ # 2c) or look up the class from some JavaClass::Classpath by its Java qualified name
23
+ cp = JavaClass.classpath('./test/data/access_flags')
24
+ puts cp.includes?('AccessFlagsTestPublic') # => 1 (true)
25
+ clazz = JavaClass.load_cp('AccessFlagsTestPublic', cp)
26
+
27
+ # 3) then retrieve low level information about the class
28
+ puts clazz.version # => "50.0"
29
+ puts clazz.constant_pool.items[1] # => "packagename/AccessFlagsTestPublic"
30
+ puts clazz.access_flags.public? # => true
31
+ puts clazz.access_flags.final? # => false
32
+ puts clazz.this_class # => "packagename/AccessFlagsTestPublic"
33
+ puts clazz.super_class # => "java/lang/Object"
34
+ puts clazz.super_class.to_classname # => "java.lang.Object"
35
+ puts clazz.references.referenced_methods[0] # => "java/lang/Object.<init>:()V"
36
+ puts clazz.interfaces # => []
37
+
38
+ # Returned class names are not just Strings, but JavaClass::JavaQualifiedName
39
+ puts clazz.this_class.to_java_file # => "packagename/AccessFlagsTestPublic.java"
40
+ puts clazz.this_class.full_name # => "packagename.AccessFlagsTestPublic"
41
+ puts clazz.this_class.package # => "packagename"
42
+ puts clazz.this_class.simple_name # => "AccessFlagsTestPublic"
data/history.txt CHANGED
@@ -1,9 +1,31 @@
1
+ === 0.0.4 19/12/2011
2
+
3
+ * convert examples to RDOC using example_task
4
+ * added transitive dependency trees from references
5
+ * patched the rubyzip for invalid flags found in some JARs
6
+ * add some examples
7
+ * fixed generate_class_lists.rb
8
+ * finish first version of DSL with loading/values
9
+ * added Eclipse project aware classpath
10
+ * added Maven aware classpath
11
+ * added ZipFile abstraction over rubyzip gem
12
+ * added class scanning "framework" and imported types Scanners
13
+ * added CachingClasspath
14
+ * added usage of system 7za/unzip (if available) which unpack much faster
15
+ * added option to unpack JARs for faster access later
16
+ * added support for Java Enum and Annotations
17
+ * added DSL like shortcuts for java.* and javax.* package and class names.
18
+ * added interfaces implemented by the class
19
+ * fixed string ux problem in Ruby 1.9
20
+ * replaced leading 0 in exponent of float/double because of Linux printf
21
+ * split Gemspec from Rakefile as proposed by Yeguda Katz
22
+
1
23
  === 0.0.3 02/10/2010
2
24
 
3
25
  * integrated ClassList from another project as first analyser
4
- * add JavaName to all class names that are returned
5
- * fix links in RDoc, update documentation
6
- * move classes into submodules for classpath, classfile, etc.
26
+ * added abstraction of Java names to all class names that are returned
27
+ * fixed links in RDoc, update documentation
28
+ * moved classes into submodules for classpath, classfile, etc.
7
29
  * migrated to Google Code and Mercurial repository
8
30
  * added access flag $1000
9
31
  * added references to used classes
@@ -14,10 +36,10 @@
14
36
  * refactored code to smaller objects for version and constant pool
15
37
  * fixed float and double constant pool items
16
38
  * added tests
17
- * continued implementation with class names and references
39
+ * added implementation with class name and references of a class file
18
40
 
19
41
  === 0.0.1 01/03/2009
20
-
21
- * initial version extracted from ClassList project
42
+
43
+ * extracted initial version of javaclass-rb from ClassList project
22
44
  * reads the class version and package/public flag of a class
23
- * understands the constant pool but does not use it
45
+ * understands the constant pool of class file but does not use it
data/javaclass.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ GEM_NAME = 'javaclass'
2
+ GOOGLE_PROJECT = "#{GEM_NAME}-rb"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.version = '0.0.4'
6
+ s.name = GEM_NAME
7
+ s.rubyforge_project = 'javaclass' # old, just redirects
8
+ s.summary = 'A parser and disassembler for Java class files'
9
+ s.description = 'Provides access to the package, protected, and public fields and methods of the classes passed to it together with a list of all outgoing references.'
10
+ s.license = 'BSD'
11
+ s.homepage = "http://code.google.com/p/#{GOOGLE_PROJECT}/"
12
+ s.author = 'Peter Kofler'
13
+ s.email = 'peter dot kofler at code minus cop dot org'
14
+ s.date = Time::gm(2011, 12, 19)
15
+
16
+ s.files = Dir.glob('*.txt') + Dir.glob('{lib,test,examples}/**/*') + ['javaclass.gemspec', 'Rakefile', 'example_task.rb']
17
+ s.test_files = Dir.glob('test/**/test_*.rb')
18
+ s.require_path = 'lib'
19
+ s.add_dependency('rubyzip', '>= 0.9.1')
20
+ s.required_ruby_version = '>= 1.8.6'
21
+ s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
22
+ s.platform = Gem::Platform::RUBY
23
+ s.add_development_dependency('rake', '>= 0.8.4')
24
+ s.add_development_dependency('rcov', '>= 0.8.1.2')
25
+ # s.add_development_dependency('ZenTest', '>= 4.4.0')
26
+
27
+ s.has_rdoc = true
28
+ s.extra_rdoc_files = Dir.glob('*.txt')
29
+ s.rdoc_options << '--title' << "#{s.name}-#{s.version} Documentation" <<
30
+ '--main' << 'Readme.txt'
31
+ end
@@ -0,0 +1,92 @@
1
+ # A node in the AdderTree.
2
+ # Author:: Peter Kofler
3
+ class AdderTreeNode
4
+
5
+ attr_reader :parent
6
+ attr_reader :data
7
+
8
+ def initialize(data, parent)
9
+ @data = data
10
+ @parent = parent
11
+ @children = []
12
+ end
13
+
14
+ def children
15
+ @children.dup
16
+ end
17
+
18
+ def add(o)
19
+ node = AdderTreeNode.new(o, self)
20
+ @children << node
21
+ node
22
+ end
23
+
24
+ def contain?(o)
25
+ if @data == o
26
+ self
27
+ else
28
+ @children.find { |child| child.contain?(o) }
29
+ end
30
+ end
31
+
32
+ def level
33
+ @parent.level + 1
34
+ end
35
+
36
+ def root
37
+ @parent.root
38
+ end
39
+
40
+ # Return the number of nodes this this (sub-)tree.
41
+ def size
42
+ @children.inject(1) { |sum, child| sum + child.size }
43
+ end
44
+
45
+ def levels
46
+ ( [1] + @children.map { |child| 1 + child.levels } ).max
47
+ end
48
+
49
+ # Return an array of all children. Each child has its own array. For example
50
+ # tree = AdderTree.new(0)
51
+ # tree.add(1)
52
+ # tree.to_a # => [0, [1]]
53
+ def to_a
54
+ if @children.size > 0
55
+ sublist = []
56
+ @children.each { |child| child.to_a.each { |c| sublist << c } }
57
+ [data, sublist]
58
+ else
59
+ [data]
60
+ end
61
+ end
62
+
63
+ # Prints the tree to the console. Each level of the tree is intended by a blank.
64
+ def debug_print
65
+ puts ' ' * level + data
66
+ @children.each { |child| child.debug_print }
67
+ end
68
+
69
+ end
70
+
71
+ # The root node of the adder tree. The "adder tree" is a simple add-only tree.
72
+ # Once the tree is build it can't be changed. Only new elements can be added.
73
+ # The tree's main functionality is defined in AdderTreeNode.
74
+ # Author:: Peter Kofler
75
+ class AdderTree < AdderTreeNode
76
+
77
+ attr_reader :parent
78
+ attr_reader :data
79
+
80
+ def initialize(data)
81
+ super(data, nil)
82
+ end
83
+
84
+ def level
85
+ 0
86
+ end
87
+
88
+ def root
89
+ self
90
+ end
91
+
92
+ end
@@ -0,0 +1,52 @@
1
+ module JavaClass
2
+
3
+ # The module Analyse is for separating namespaces. It contains various methods
4
+ # to analyse classes accross a whole whole code bases (Classpath). The functionality
5
+ # of all analysers is collected in Dsl::ClasspathAnalysers.
6
+ # Author:: Peter Kofler
7
+ module Analyse
8
+
9
+ # Analyser to get dependencies of a whole Classpath (to be mixed into Dsl::LoadingClasspath).
10
+ # For an example see
11
+ # {how to list all imported types}[link:/files/lib/generated/examples/find_all_imported_types_txt.html].
12
+ # Author:: Peter Kofler
13
+ module Dependencies
14
+
15
+ # Return all types in this classpath. An additional block is used as _filter_ on class names.
16
+ # Returns a list of JavaQualifiedName. Requires a method _names_ in the base class.
17
+ def types(&filter)
18
+ names(&filter).collect { |c| c.to_classname }.sort
19
+ end
20
+
21
+ # Determine all imported types from all classes in this classpath together with count of imports.
22
+ # An additional block is used as _filter_ on class names. Requires a method _values_ in the base class.
23
+ def used_types_map(&filter)
24
+ type_map = Hash.new(0) # class_name (JavaQualifiedName) => cnt
25
+ values(&filter).collect { |clazz| clazz.imported_3rd_party_types }.flatten.each do |type|
26
+
27
+ # hash keys need to be frozen to keep state
28
+ if !type_map.include?(type)
29
+ type = type.freeze
30
+ end
31
+
32
+ type_map[type] += 1
33
+ end
34
+ type_map
35
+ end
36
+
37
+ # Determine all imported types from all classes in this classpath.
38
+ # An additional block is used as _filter_ on class names.
39
+ def used_types(&filter)
40
+ used_types_map(&filter).keys.sort
41
+ end
42
+
43
+ # Determine all foreign imported types from all classes in this classpath.
44
+ # An additional block is used as _filter_ on class names.
45
+ def external_types(&filter)
46
+ used_types(&filter) - types(&filter)
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -1,4 +1,4 @@
1
- === Metrics
1
+ === Metrics/Analysis across a whole classpath
2
2
 
3
3
  * "metric" if all referencing classes of a class is another package, propose moving it there.
4
4
  * "Greed Detector"
@@ -6,7 +6,7 @@
6
6
  * which signatures are called how often
7
7
  * maybe move current method there?
8
8
  * CRSS Metric
9
- * CCD
9
+ * CCD: lazy init, classpath sits inside the analyser and works recursively through all elements
10
10
 
11
11
  * {Chidamber and Kemerer Java Metrics (ckjm)}[http://www.spinellis.gr/sw/ckjm/]
12
12
  * {The CRSS Metric for Package Design Quality}[http://crpit.com/confpapers/CRPITV62Melton2.pdf]
@@ -0,0 +1,52 @@
1
+ require 'javaclass/adder_tree'
2
+
3
+ module JavaClass
4
+ module Analyse
5
+
6
+ # Transitive dependency analysis to be mixed into Dsl::LoadingClasspath. For an example see
7
+ # {how to get cumulative dependencies of a class}[link:/files/lib/generated/examples/cumulative_dependencies_txt.html].
8
+ # For plain dependencies of a Classpath see Dependencies.
9
+ # Author:: Peter Kofler
10
+ module TransitiveDependencies
11
+
12
+ # Creates the tree of all transitive dependencies of _classname_ where every dependency is only
13
+ # listed once at its first occurence. It returns an AdderTree containing all found dependencies.
14
+ # An additional block is used as _filter_ on class names to work with, e.g. the main classes.
15
+ # Requires methods <i>includes?</i> and _load_ in the base class.
16
+ def transitive_dependency_tree(classname, tree=nil, &filter)
17
+ return if block_given? && !filter.call(classname)
18
+ return if tree && tree.root.contain?(classname)
19
+
20
+ if tree
21
+ tree = tree.add(classname.to_classname)
22
+ else
23
+ tree = AdderTree.new(classname.to_classname)
24
+ end
25
+
26
+ if includes?(classname)
27
+ load(classname).imported_3rd_party_types.each do |classname|
28
+ transitive_dependency_tree(classname, tree, &filter)
29
+ end
30
+ end
31
+
32
+ tree
33
+ end
34
+
35
+ # Creates the tree of all transitive dependencies of the Java _package_ where every dependency is only
36
+ # listed once at its first occurence. It returns an AdderTree containing all found dependencies.
37
+ # An additional block is used as _filter_ on class names to work with, e.g. the main classes.
38
+ # Requires a method _names_ in the base class.
39
+ def transitive_dependencies_package(package, &filter)
40
+ tree = AdderTree.new(package)
41
+
42
+ names { |classname| classname.same_or_subpackage_of?(package) }.each do |classname|
43
+ transitive_dependency_tree(classname, tree, &filter)
44
+ end
45
+
46
+ tree
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end