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
@@ -1,43 +1,45 @@
|
|
1
1
|
require 'javaclass/classfile/constant_pool'
|
2
2
|
|
3
3
|
module JavaClass
|
4
|
-
module ClassFile
|
5
|
-
|
4
|
+
module ClassFile
|
5
|
+
|
6
6
|
# Container class for list of all classes, methods and fields referenced by this class.
|
7
7
|
# This information is derived from the constant pool, no analysis.
|
8
8
|
# Author:: Peter Kofler
|
9
9
|
class References
|
10
|
-
|
11
|
-
# Create a references container with the constant _pool_ and skip references to index _classidx_ which is the host class itself.
|
10
|
+
|
11
|
+
# Create a references container with the constant _pool_ and skip references to index _classidx_ which is the host class itself.
|
12
12
|
def initialize(pool, classidx)
|
13
13
|
@constant_pool = pool
|
14
14
|
@class_idx = classidx
|
15
15
|
end
|
16
|
-
|
17
|
-
# Return the constants referring to fields (Constants::ConstantField).
|
18
|
-
# If _includeown_ is +true+ then fields of this class are returned also.
|
16
|
+
|
17
|
+
# Return the constants referring to fields (Constants::ConstantField).
|
18
|
+
# If _includeown_ is +true+ then fields of this class are returned also.
|
19
19
|
def referenced_fields(includeown=false)
|
20
|
-
@constant_pool.find(ConstantPool::FIELD_TAG).find_all do |field|
|
20
|
+
@constant_pool.find(ConstantPool::FIELD_TAG).find_all do |field|
|
21
21
|
includeown || field.class_index != @class_idx
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
# Return the constants referring to methods (Constants::ConstantMethod) in classes or interfaces.
|
26
|
-
# If _includeown_ is +true+ then methods of this class are returned also.
|
24
|
+
|
25
|
+
# Return the constants referring to methods (Constants::ConstantMethod) in classes or interfaces.
|
26
|
+
# If _includeown_ is +true+ then methods of this class are returned also.
|
27
27
|
def referenced_methods(includeown=false)
|
28
|
-
@constant_pool.find(ConstantPool::METHOD_TAG, ConstantPool::INTERFACE_METHOD_TAG).find_all do |method|
|
29
|
-
includeown || method.class_index != @class_idx
|
28
|
+
@constant_pool.find(ConstantPool::METHOD_TAG, ConstantPool::INTERFACE_METHOD_TAG).find_all do |method|
|
29
|
+
includeown || method.class_index != @class_idx
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
33
|
-
# Return the list of all
|
32
|
+
|
33
|
+
# Return the list of all constant pool constantss containing class names of all used classes.
|
34
|
+
# Returns a list of ConstantClass.
|
34
35
|
def used_classes
|
35
|
-
@constant_pool.
|
36
|
-
|
36
|
+
my_class_name = @constant_pool[@class_idx].class_name
|
37
|
+
@constant_pool.find(ConstantPool::CLASS_TAG).find_all do |cl|
|
38
|
+
cl.class_name != my_class_name
|
37
39
|
end
|
38
40
|
end
|
39
|
-
|
41
|
+
|
40
42
|
end
|
41
|
-
|
43
|
+
|
42
44
|
end
|
43
45
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
require 'javaclass/java_name'
|
2
2
|
|
3
3
|
module JavaClass
|
4
|
-
module ClassList
|
5
|
-
|
6
|
-
# An entry in the list. A ClassEntry belongs to a PackageEntry and has a list
|
4
|
+
module ClassList
|
5
|
+
|
6
|
+
# An entry in the list. A ClassEntry belongs to a PackageEntry and has a list of versions it exists in.
|
7
7
|
# Author:: Peter Kofler
|
8
8
|
class ClassEntry
|
9
|
-
|
9
|
+
|
10
10
|
# Return the short (simple) name of this class.
|
11
11
|
attr_reader :name
|
12
12
|
attr_reader :full_name
|
13
13
|
# Return the list of versions this class exists.
|
14
14
|
attr_reader :version
|
15
|
-
|
16
|
-
# Create a new entry. _parent_ must provide a +version+ field to compare against. _vers_ is the
|
17
|
-
# base version of this class.
|
15
|
+
|
16
|
+
# Create a new entry. _parent_ must provide a +version+ field to compare against. _vers_ is the base version of this class.
|
18
17
|
def initialize(parent, full_name, is_public, vers)
|
19
18
|
@parent = parent
|
20
19
|
@full_name = full_name.to_javaname.to_classname
|
@@ -22,68 +21,68 @@ module JavaClass
|
|
22
21
|
@is_public = is_public
|
23
22
|
@version = [vers]
|
24
23
|
end
|
25
|
-
|
24
|
+
|
26
25
|
def public?
|
27
26
|
@is_public
|
28
27
|
end
|
29
|
-
|
28
|
+
|
30
29
|
# Update the _version_ this class also exists in.
|
31
30
|
def update(version, is_public=@is_public)
|
32
31
|
raise "update class #{@name} is older than its last version: latest version=#{@version.last}, new version=#{version}" if version <= @version.last
|
33
32
|
# check for holes in versions
|
34
33
|
if version > @version.last+1
|
35
|
-
warn "#{@full_name} last in version #{@version.last}, not in #{@version.last+1}, but again in #{version}"
|
34
|
+
warn "#{@full_name} last in version #{@version.last}, not in #{@version.last+1}, but again in #{version}"
|
36
35
|
end
|
37
|
-
@version << version
|
38
|
-
|
36
|
+
@version << version
|
37
|
+
|
39
38
|
if !is_public && @is_public
|
40
39
|
warn "#{@full_name} changed from public to package in version #{version}"
|
41
40
|
@is_public = is_public
|
42
41
|
@version = [version] # skip older versions
|
43
42
|
elsif is_public && ! @is_public
|
44
|
-
|
43
|
+
puts "#{@full_name} changed from package to public in version #{version}"
|
45
44
|
@is_public = is_public
|
46
45
|
@version = [version] # skip older versions
|
47
46
|
end
|
48
47
|
end
|
49
|
-
|
48
|
+
|
50
49
|
# Sorts by simple +name+ inside the package.
|
51
50
|
def <=>(other)
|
52
51
|
@name.casecmp other.name
|
53
52
|
end
|
54
|
-
|
53
|
+
|
55
54
|
def to_s
|
56
55
|
@full_name
|
57
56
|
end
|
58
|
-
|
59
|
-
# Return a string containing the full qualified name together with first and last version
|
60
|
-
#
|
57
|
+
|
58
|
+
# Return a string containing the full qualified name together with first and last version of this class. Ignore package versions, but
|
59
|
+
# obey _minversion_ and _maxversion_ .
|
61
60
|
# Print all versions, first to last, but skip <code>first<=minversion</code> and <code>last>=maxversion</code>.
|
62
61
|
def to_full_qualified_s(minversion, maxversion)
|
63
62
|
format_version(@full_name, minversion, maxversion)
|
64
63
|
end
|
65
|
-
|
64
|
+
|
66
65
|
# Return a string containing the simple name and the version, if it is different from the package version.
|
67
66
|
def to_package_shortcut_s
|
68
67
|
vp = @parent.version
|
69
68
|
format_version(" #{@name}", vp.first, vp.last)
|
70
69
|
end
|
71
|
-
|
70
|
+
|
72
71
|
private
|
73
|
-
|
72
|
+
|
74
73
|
def format_version(start, minversion, maxversion)
|
75
74
|
# this class has a set of versions where it exists
|
76
75
|
# the parent has a set of versions where it exists, contains class versions
|
77
76
|
is_newer = @version.first > minversion
|
78
77
|
is_outdated = @version.last < maxversion
|
79
|
-
line = start +
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
78
|
+
line = start +
|
79
|
+
" [#{ is_newer || (!@is_public && @version.first>0) ? @version.first.to_s : ''}" +
|
80
|
+
"#{is_outdated ? '-' + @version.last.to_s : ''}" +
|
81
|
+
"#{!@is_public ? 'p' : '' }]" +
|
82
|
+
" - \n"
|
84
83
|
line.sub(/\[-0/, "[0-0").sub(/(\d)-\1/, "only \\1").sub(/ \[\]/, '')
|
85
84
|
end
|
86
85
|
end
|
87
|
-
|
86
|
+
|
88
87
|
end
|
89
88
|
end
|
@@ -1,30 +1,40 @@
|
|
1
|
-
require 'javaclass/classpath/
|
1
|
+
require 'javaclass/classpath/any_classpath'
|
2
2
|
require 'javaclass/classfile/java_class_header'
|
3
3
|
|
4
4
|
module JavaClass
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
|
6
|
+
# The module ClassList is for separating namespaces. It contains the logic
|
7
|
+
# to create a list of all classes of all JDK versions. The main logic is
|
8
|
+
# performed in ClassList::JarSearcher, which creates the ClassList::List.
|
9
|
+
# It uses a
|
10
|
+
# Classpath::CompositeClasspath to find all classes and ClassFile::JavaClassHeader
|
11
|
+
# to read the class information from. The generated list contains packages
|
12
|
+
# and these packages contain the names of classes, their accessibility
|
13
|
+
# and the versions they were added (or removed) from JDK. ClassList is an
|
14
|
+
# "application" using the JavaClass infrastructure. For a full example see
|
15
|
+
# {how to generate lists of JDK classes}[link:/files/lib/generated/examples/generate_class_lists_txt.html].
|
16
|
+
# Author:: Peter Kofler
|
17
|
+
module ClassList
|
18
|
+
|
19
|
+
# Search in zip or JAR files for Java class files, check for package access or inner classes and call back a list of all these.
|
9
20
|
# Author:: Peter Kofler
|
10
21
|
class JarSearcher
|
11
|
-
|
22
|
+
|
12
23
|
attr_accessor :skip_inner_classes
|
13
24
|
attr_accessor :skip_package_classes
|
14
|
-
|
25
|
+
|
15
26
|
# Create a new searcher.
|
16
27
|
def initialize
|
17
28
|
@skip_inner_classes = true
|
18
29
|
@skip_package_classes = false
|
19
30
|
@package_filters = []
|
20
31
|
end
|
21
|
-
|
22
|
-
# The given _filters_ will be dropped during searching.
|
23
|
-
# _filters_ contain the beginning of package paths, i.e. <code>com/sun/</code>.
|
32
|
+
|
33
|
+
# The given _filters_ will be dropped during searching. _filters_ contain the beginning of package paths, i.e. <code>com/sun/</code>.
|
24
34
|
def filters=(filters)
|
25
35
|
@package_filters = filters.collect{ |f| /^#{f}/ }
|
26
36
|
end
|
27
|
-
|
37
|
+
|
28
38
|
# Return the list of classnames of this list of _classes_ .
|
29
39
|
# Skips inner classes if +skip_inner_classes+ is true.
|
30
40
|
# Skips classes that are in the filtered packages.
|
@@ -33,37 +43,36 @@ module JavaClass
|
|
33
43
|
!(@skip_inner_classes && name =~ /\$/) && (@package_filters.find { |filter| name =~ filter } == nil)
|
34
44
|
end
|
35
45
|
end
|
36
|
-
|
37
|
-
# Return true if the _classfile_ in the given _classpath_ is public. This is expensive because
|
38
|
-
#
|
46
|
+
|
47
|
+
# Return true if the _classfile_ in the given _classpath_ is public. This is expensive because the JAR file is opened and the
|
48
|
+
# _classfile_ is extracted and read.
|
39
49
|
def public?(classpath, classfile)
|
40
50
|
begin
|
41
51
|
header = ClassFile::JavaClassHeader.new(classpath.load_binary(classfile))
|
42
|
-
rescue
|
43
|
-
|
44
|
-
raise
|
52
|
+
rescue JavaClass::ClassFile::ClassFormatError => ex
|
53
|
+
ex.add_classname(classfile, classpath.to_s)
|
54
|
+
raise ex
|
45
55
|
end
|
46
|
-
|
56
|
+
header.magic.check("invalid java class #{classfile}")
|
47
57
|
header.access_flags.accessible?
|
48
58
|
end
|
49
|
-
|
50
|
-
# Compile the class list for the given _version_ of Java. This searches the _path_ for zips and
|
59
|
+
|
60
|
+
# Compile the class list for the given _version_ of Java. This searches the _path_ for zips and JARs
|
51
61
|
# and adds them to the given _list_ of found classes. _version_ is a number >= 0, e.g. 2 for JDK 1.2.
|
52
62
|
# _list_ must provide a <code>add_class(entry, is_public, version)</code> method.
|
53
63
|
def compile_list(version, path, list)
|
54
|
-
cpe =
|
55
|
-
cpe.find_jars(path)
|
64
|
+
cpe = Classpath::AnyClasspath.new(path)
|
56
65
|
filter_classes(cpe.names).each do |entry|
|
57
66
|
is_public = public?(cpe, entry)
|
58
67
|
next if @skip_package_classes && !is_public
|
59
68
|
list.add_class(entry, is_public, version) if list
|
60
69
|
yield(entry, is_public, version) if block_given?
|
61
70
|
end
|
62
|
-
|
71
|
+
|
63
72
|
list
|
64
73
|
end
|
65
|
-
|
74
|
+
|
66
75
|
end
|
67
|
-
|
76
|
+
|
68
77
|
end
|
69
78
|
end
|
@@ -2,31 +2,31 @@ require 'javaclass/java_name'
|
|
2
2
|
require 'javaclass/classlist/package_entry'
|
3
3
|
|
4
4
|
module JavaClass
|
5
|
-
module ClassList
|
6
|
-
|
7
|
-
# Classes to form a list of JDK classes to find classes which have been
|
8
|
-
#
|
5
|
+
module ClassList
|
6
|
+
|
7
|
+
# Classes to form a list of JDK classes to find classes which have been
|
8
|
+
# added in new releases. This is the list containing packages (PackageEntry).
|
9
9
|
# Author:: Peter Kofler
|
10
10
|
class List
|
11
|
-
|
11
|
+
|
12
12
|
def initialize
|
13
|
-
@packages =
|
13
|
+
@packages = Hash.new # package_name (String) => PackageEntry
|
14
14
|
end
|
15
|
-
|
16
|
-
# Add a _fileentry_ to the list. The _fileentry_ is the file name of the class in the
|
15
|
+
|
16
|
+
# Add a _fileentry_ to the list. The _fileentry_ is the file name of the class in the JAR file. _version_
|
17
17
|
# is the version of the JDK scanned and is used if the class is new.
|
18
18
|
def add_class(fileentry, is_public, version)
|
19
19
|
class_name = fileentry.to_javaname.to_classname
|
20
20
|
package_name = class_name.package
|
21
21
|
@packages[package_name] = PackageEntry.new(package_name, version) unless @packages.has_key?(package_name)
|
22
|
-
@packages[package_name].add_class(class_name, is_public, version)
|
22
|
+
@packages[package_name].add_class(class_name.full_name, is_public, version)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
# Parse a _line_ from a <code>fullClassList</code> and fill the list again. _maxversion_ is the maximum
|
26
26
|
# max version from the list, i.e. the highest possible value, so we can continue to use it.
|
27
27
|
def parse_line(line, maxversion)
|
28
28
|
class_name, versions = line.scan(/^([^\s]+)\s(?:\[(.*)\]\s)?-\s*$/)[0]
|
29
|
-
|
29
|
+
|
30
30
|
# no [], so we have it from always and it is public
|
31
31
|
first_vers = 0
|
32
32
|
last_vers = maxversion
|
@@ -35,7 +35,7 @@ module JavaClass
|
|
35
35
|
# extract package access and drop it
|
36
36
|
is_public = (versions !~ /p/)
|
37
37
|
versions = versions.gsub(/p/, '')
|
38
|
-
|
38
|
+
|
39
39
|
# \d, \d-\d, only \d, -\d, oder leer
|
40
40
|
if versions =~ /^(\d)$/
|
41
41
|
first_vers = $1.to_i
|
@@ -51,54 +51,54 @@ module JavaClass
|
|
51
51
|
raise "can't match version number #{versions} in line #{line.chomp}" unless versions == ''
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
55
|
-
first_vers.upto(last_vers) do |v|
|
56
|
-
add_class(class_name, is_public, v)
|
54
|
+
|
55
|
+
first_vers.upto(last_vers) do |v|
|
56
|
+
add_class(class_name, is_public, v)
|
57
57
|
end
|
58
58
|
rescue
|
59
59
|
raise "#{$!} in line #{line.chomp}: class_name=#{class_name}, versions=#{versions}, first_vers=#{first_vers}, last_vers=#{last_vers}, is_public=#{is_public}"
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def packages
|
63
63
|
@packages.values.sort
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
# Return the version list of all packages.
|
67
67
|
def version
|
68
68
|
packages.collect { |p| p.version }.flatten.uniq.sort
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Return the first and last version of this list.
|
72
72
|
def first_last_versions
|
73
73
|
v = version
|
74
74
|
[v.first, v.last]
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
def to_s
|
78
78
|
packages.collect { |p| p.to_s }.join("\n")
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
# Return the number of classes in this list.
|
82
82
|
def size
|
83
83
|
@packages.values.inject(0) {|sum, p| sum + p.size }
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
# The access list is the raw list of all package access classes for one version. It was used to differ
|
87
87
|
# normal classes from hidden classes and was saved in <code>doc/AccessLists/*_p.txt</code>.
|
88
|
-
# This works only if JarSearcher was used with
|
89
|
-
# If there are more versions loaded, then only the last version is printed. So we get consecutive lists
|
88
|
+
# This works only if JarSearcher was used with <i>skip_package_classes</i> set to false (default).
|
89
|
+
# If there are more versions loaded, then only the last version is printed. So we get consecutive lists
|
90
90
|
# of new package access classes with every JDK version.
|
91
91
|
def old_access_list
|
92
92
|
v = first_last_versions
|
93
|
-
packages.collect { |pkg|
|
93
|
+
packages.collect { |pkg|
|
94
94
|
pkg.classes.find_all { |c| !c.public? && c.version == [v[1]]}.collect { |c| c.to_full_qualified_s(v[0], v[1]) }
|
95
95
|
}.flatten.sort{|a,b| a.casecmp b }
|
96
96
|
end
|
97
|
-
|
98
|
-
# The class list is the raw list of all classes for one version without version or package access
|
97
|
+
|
98
|
+
# The class list is the raw list of all classes for one version without version or package access
|
99
99
|
# descriptors. It was used to find differences and was saved in <code>doc/ClassLists/*_classes.txt</code>.
|
100
100
|
# This usually was done with JarSearcher set +skip_package_classes+ to false.
|
101
|
-
# If a block is given it is invoked with ClassEntry and should return if to add the class or not.
|
101
|
+
# If a block is given it is invoked with ClassEntry and should return if to add the class or not.
|
102
102
|
def plain_class_list
|
103
103
|
packages.collect { |pkg|
|
104
104
|
cls = pkg.classes
|
@@ -108,19 +108,19 @@ module JavaClass
|
|
108
108
|
cls.collect { |c| c.full_name + "\n" }
|
109
109
|
}.flatten.sort{|a,b| a.casecmp b }
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
# Create a full class list with version numbers and different versions to compare.
|
113
113
|
# This was the base for classlists and was saved in <code>doc/fullClassList1x.txt</code>.
|
114
114
|
# This usually was done with JarSearcher set +skip_package_classes+ to false and
|
115
115
|
# contained different classlists merged together.
|
116
116
|
def full_class_list
|
117
117
|
v = first_last_versions
|
118
|
-
packages.collect { |pkg|
|
118
|
+
packages.collect { |pkg|
|
119
119
|
pkg.classes.collect { |c| c.to_full_qualified_s(v[0], v[1]) }
|
120
120
|
}.flatten.sort{|a,b| a.casecmp b }
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
end
|
126
126
|
end
|
@@ -1,34 +1,35 @@
|
|
1
1
|
require 'javaclass/classlist/class_entry'
|
2
2
|
|
3
3
|
module JavaClass
|
4
|
-
module ClassList
|
5
|
-
|
6
|
-
# A package in the List.
|
4
|
+
module ClassList
|
5
|
+
|
6
|
+
# A package in the List. A package contains ClassEntry.
|
7
7
|
# Author:: Peter Kofler
|
8
8
|
class PackageEntry # ZenTest FULL to find method <=>
|
9
|
-
|
9
|
+
|
10
10
|
attr_reader :name
|
11
11
|
# Return the list of versions this package exists. This is the sum of all versions of all classes in the package.
|
12
12
|
attr_reader :version
|
13
|
-
|
13
|
+
|
14
14
|
# Create a new package with name _name_ and first version _vers_ which is the version of the first class in the package.
|
15
15
|
def initialize(name, vers=0)
|
16
16
|
@name = name
|
17
17
|
@version = [vers]
|
18
|
-
@classes =
|
18
|
+
@classes = Hash.new # class_name (most likely String) => ClassEntry
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def add_class(class_name, is_public, version)
|
22
22
|
@version << version unless @version.include? version
|
23
23
|
@version = @version.sort
|
24
|
-
|
24
|
+
|
25
25
|
unless @classes.has_key?(class_name)
|
26
26
|
@classes[class_name] = ClassEntry.new(self, class_name, is_public, version)
|
27
|
+
# class_name does not need to be frozen because it's not read from the keys
|
27
28
|
else
|
28
29
|
@classes[class_name].update(version, is_public)
|
29
30
|
end
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
# Sorting in packages is: <code>java.lang</code>, other <code>java.*</code>, <code>javax.*</code> and then others.
|
33
34
|
def <=>(other)
|
34
35
|
if @name =~ /^java\.lang$/ and other.name !~ /^java\.lang$/
|
@@ -47,41 +48,41 @@ module JavaClass
|
|
47
48
|
@name <=> other.name
|
48
49
|
end
|
49
50
|
end
|
50
|
-
|
51
|
+
|
51
52
|
# Return the classes in this package.
|
52
53
|
def classes
|
53
54
|
@classes.values.sort
|
54
55
|
end
|
55
|
-
|
56
|
+
|
56
57
|
# Return the number of classes in this package.
|
57
58
|
def size
|
58
59
|
@classes.size
|
59
60
|
end
|
60
|
-
|
61
|
+
|
61
62
|
def to_s
|
62
63
|
@name
|
63
64
|
end
|
64
|
-
|
65
|
-
# Special version of +to_s+ for package shortcut. A package needs _minversion_ and _maxversion_ to
|
66
|
-
#
|
65
|
+
|
66
|
+
# Special version of +to_s+ for package shortcut. A package needs _minversion_ and _maxversion_ to determine if the whole package was
|
67
|
+
# dropped.
|
67
68
|
def to_package_shortcut_s(minversion, maxversion)
|
68
|
-
|
69
|
+
"#{@name}#{format_version(minversion, maxversion)} - \n" +
|
69
70
|
classes.collect { |c| c.to_package_shortcut_s }.join
|
70
71
|
end
|
71
|
-
|
72
|
+
|
72
73
|
private
|
73
|
-
|
74
|
+
|
74
75
|
def format_version(minversion, maxversion)
|
75
76
|
is_newer = @version.first > minversion
|
76
77
|
is_outdated = @version.last < maxversion
|
77
|
-
line =
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
line =
|
79
|
+
" [#{ is_newer ? @version.first.to_s : ''}" +
|
80
|
+
"#{is_outdated ? '-' + @version.last.to_s : ''}" +
|
81
|
+
"]"
|
81
82
|
line.sub(/(\d)-\1/, "only \\1").sub(/ \[\]/, '')
|
82
83
|
end
|
83
|
-
|
84
|
+
|
84
85
|
end
|
85
|
-
|
86
|
+
|
86
87
|
end
|
87
88
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'javaclass/classpath/composite_classpath'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Classpath
|
5
|
+
|
6
|
+
# Classpath containing everything under a folder. This is for an unstructured
|
7
|
+
# collection of JARs and class files.
|
8
|
+
# Author:: Peter Kofler
|
9
|
+
class AnyClasspath < CompositeClasspath
|
10
|
+
|
11
|
+
# Create a classpath with all classes found under this _folder_ wherever they are.
|
12
|
+
def initialize(folder)
|
13
|
+
super(File.join(folder, '*'))
|
14
|
+
find_jars(folder)
|
15
|
+
|
16
|
+
# TODO Implement "find_classes_under(folder)" to find all class folders under this path.
|
17
|
+
# Search for classes, open the first one, check its package, backtrack to its base folder,
|
18
|
+
# add it to this classpath "add_file_name(sub_folders)", skip it in further analysis and continue.
|
19
|
+
end
|
20
|
+
|
21
|
+
# Search the given _path_ recursively for zips or jars. Add all found jars to this classpath.
|
22
|
+
def find_jars(path)
|
23
|
+
if FileTest.file?(path) && path =~ /\.jar$|\.zip$/
|
24
|
+
add_file_name File.expand_path(path)
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
current = Dir.getwd
|
29
|
+
begin
|
30
|
+
Dir.chdir File.expand_path(path)
|
31
|
+
|
32
|
+
Dir['*'].collect do |name|
|
33
|
+
if FileTest.directory?(name)
|
34
|
+
find_jars(name)
|
35
|
+
elsif name =~ /\.jar$|\.zip$/
|
36
|
+
add_file_name File.expand_path(name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ensure
|
41
|
+
Dir.chdir current
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module JavaClass
|
2
|
+
module Classpath
|
3
|
+
|
4
|
+
# An error in the classpath. The requested classfile could not be found.
|
5
|
+
# Author:: Peter Kofler
|
6
|
+
class ClassNotFoundError < IOError
|
7
|
+
|
8
|
+
attr_reader :classname
|
9
|
+
attr_reader :classpath
|
10
|
+
|
11
|
+
def initialize(classname, classpath=nil)
|
12
|
+
@classname = classname
|
13
|
+
@classpath = classpath
|
14
|
+
super("class #{@classname} not found in classpath #{@classpath}")
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
*
|
1
|
+
TODO other classpath abstractions:
|
2
|
+
* WARs and EARs contain JARs and a folder
|