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
@@ -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
|
-
|
13
|
+
#++
|
3
14
|
require 'javaclass/classlist/jar_searcher'
|
4
|
-
|
5
|
-
|
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
|
-
|
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,
|
14
|
-
JDK_CONFIG.new(1,
|
15
|
-
JDK_CONFIG.new(2,
|
16
|
-
JDK_CONFIG.new(3,
|
17
|
-
JDK_CONFIG.new(4,
|
18
|
-
JDK_CONFIG.new(5,
|
19
|
-
JDK_CONFIG.new(6,
|
20
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
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
|
-
#
|
39
|
-
|
40
|
-
|
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
|
-
#
|
55
|
+
# 3) create a new JavaClass::ClassList::List to contain the classes
|
56
|
+
list = JavaClass::ClassList::List.new
|
47
57
|
|
48
|
-
|
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
|
-
|
51
|
-
conf.paths.each { |p|
|
52
|
-
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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("
|
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
|
-
*
|
5
|
-
*
|
6
|
-
*
|
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
|
-
*
|
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
|
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
|