javaclass 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|