javaclass 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +208 -23
- data/Readme.txt +56 -19
- data/examples/generate_class_lists.rb +61 -0
- data/history.txt +13 -19
- data/lib/javaclass/classfile/access_flags.rb +52 -0
- data/lib/javaclass/classfile/class_magic.rb +29 -0
- data/lib/javaclass/classfile/class_version.rb +67 -0
- data/lib/javaclass/classfile/constant_pool.rb +91 -0
- data/lib/javaclass/classfile/constants/base.rb +33 -0
- data/lib/javaclass/classfile/constants/double_reference.rb +99 -0
- data/lib/javaclass/classfile/constants/single_reference.rb +65 -0
- data/lib/javaclass/classfile/constants/value.rb +116 -0
- data/lib/javaclass/classfile/java_class_header.rb +102 -0
- data/lib/javaclass/classfile/references.rb +43 -0
- data/lib/javaclass/classlist/class_entry.rb +89 -0
- data/lib/javaclass/classlist/jar_searcher.rb +69 -0
- data/lib/javaclass/classlist/list.rb +126 -0
- data/lib/javaclass/classlist/package_entry.rb +87 -0
- data/lib/javaclass/classpath/classpaths.txt +2 -0
- data/lib/javaclass/classpath/composite_classpath.rb +99 -0
- data/lib/javaclass/classpath/folder_classpath.rb +83 -0
- data/lib/javaclass/classpath/jar_classpath.rb +100 -0
- data/lib/javaclass/classpath/java_home_classpath.rb +40 -0
- data/lib/javaclass/classpath/port_ClassPathEntry.java +202 -0
- data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +311 -0
- data/lib/javaclass/classpath/port_DirectoryRepository.java +24 -0
- data/lib/javaclass/java_name.rb +90 -0
- data/lib/javaclass/metric/ccd.rb +68 -0
- data/lib/javaclass/metric/class_usage.rb +41 -0
- data/lib/javaclass/metric/metrics.txt +15 -0
- data/lib/javaclass.rb +44 -11
- data/test/data/ShortClientData$1-4000Wert.class +0 -0
- data/test/data/{AccessFlagsTestAbstract.class → access_flags/AccessFlagsTestAbstract.class} +0 -0
- data/test/data/{AccessFlagsTestAbstract.java → access_flags/AccessFlagsTestAbstract.java} +0 -0
- data/test/data/{AccessFlagsTestFinal.class → access_flags/AccessFlagsTestFinal.class} +0 -0
- data/test/data/{AccessFlagsTestFinal.java → access_flags/AccessFlagsTestFinal.java} +0 -0
- data/test/data/{AccessFlagsTestInterface.class → access_flags/AccessFlagsTestInterface.class} +0 -0
- data/test/data/{AccessFlagsTestInterface.java → access_flags/AccessFlagsTestInterface.java} +0 -0
- data/test/data/{AccessFlagsTestPackage.class → access_flags/AccessFlagsTestPackage.class} +0 -0
- data/test/data/{AccessFlagsTestPackage.java → access_flags/AccessFlagsTestPackage.java} +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$Inner.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$InnerInterface.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$StaticInner.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic.java +11 -0
- data/test/data/access_flags/AccessFlagsTestPublic_javap.txt +29 -0
- data/test/data/{makeAccessFlagsTest.bat → access_flags/make.bat} +0 -0
- data/test/data/{ClassVersionTest.java → class_version/ClassVersionTest.java} +0 -0
- data/test/data/{ClassVersionTest10.class → class_version/ClassVersionTest10.class} +0 -0
- data/test/data/{ClassVersionTest11.class → class_version/ClassVersionTest11.class} +0 -0
- data/test/data/{ClassVersionTest12.class → class_version/ClassVersionTest12.class} +0 -0
- data/test/data/{ClassVersionTest13.class → class_version/ClassVersionTest13.class} +0 -0
- data/test/data/{ClassVersionTest14.class → class_version/ClassVersionTest14.class} +0 -0
- data/test/data/{ClassVersionTest15.class → class_version/ClassVersionTest15.class} +0 -0
- data/test/data/{ClassVersionTest16.class → class_version/ClassVersionTest16.class} +0 -0
- data/test/data/{makeClassVersionTest.bat → class_version/make.bat} +0 -0
- data/test/data/{ConstantPoolTest.class → constant_pool/ConstantPoolTest.class} +0 -0
- data/test/data/{ConstantPoolTest.java → constant_pool/ConstantPoolTest.java} +0 -0
- data/test/data/{makeConstantPoolTest.bat → constant_pool/make.bat} +0 -0
- data/test/data/folder_classpath/JarClasspathTestFolder/ClassVersionTest10.class +0 -0
- data/test/data/folder_classpath/JarClasspathTestFolder/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 +24 -0
- data/test/data/jar_searcher/JarClassListTest.jar +0 -0
- data/test/data/jar_searcher/PublicClass.java +12 -0
- data/test/data/jar_searcher/PublicInterface.java +5 -0
- data/test/data/jar_searcher/make.bat +13 -0
- data/test/data/java_home_classpath/jdk/jre/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/jre/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/jre-ext/lib/ext/ext.jar +0 -0
- data/test/data/java_home_classpath/jre-ext/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/make.bat +13 -0
- data/test/data/references/ReferencesTest.class +0 -0
- data/test/data/references/ReferencesTest.java +12 -0
- data/test/data/references/make.bat +5 -0
- data/test/setup.rb +6 -5
- data/test/test_access_flags.rb +59 -44
- data/test/test_base.rb +20 -15
- data/test/test_class_entry.rb +198 -0
- data/test/test_class_version.rb +48 -46
- data/test/test_composite_classpath.rb +68 -0
- data/test/test_constant_pool.rb +49 -41
- data/test/test_folder_classpath.rb +45 -0
- data/test/test_jar_classpath.rb +57 -0
- data/test/test_jar_searcher.rb +93 -0
- data/test/test_java_class_header.rb +34 -22
- data/test/test_java_home_classpath.rb +50 -0
- data/test/test_java_name.rb +110 -0
- data/test/test_javaclass.rb +22 -0
- data/test/test_list.rb +123 -0
- data/test/test_package_entry.rb +91 -0
- data/test/test_references.rb +38 -20
- data/test/test_string_ux.rb +99 -2
- data/test/ts_all_tests.rb +42 -21
- metadata +171 -50
- data/lib/javaclass/access_flags.rb +0 -44
- data/lib/javaclass/class_magic.rb +0 -27
- data/lib/javaclass/class_version.rb +0 -65
- data/lib/javaclass/constant_pool.rb +0 -85
- data/lib/javaclass/constants/base.rb +0 -31
- data/lib/javaclass/constants/double_reference.rb +0 -81
- data/lib/javaclass/constants/single_reference.rb +0 -58
- data/lib/javaclass/constants/value.rb +0 -114
- data/lib/javaclass/java_class_header.rb +0 -88
- data/lib/javaclass/references.rb +0 -31
- data/test/data/AccessFlagsTestPublic$InnerClass.class +0 -0
- data/test/data/AccessFlagsTestPublic.class +0 -0
- data/test/data/AccessFlagsTestPublic.java +0 -7
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'javaclass/classpath/composite_classpath'
|
2
|
+
require 'javaclass/classfile/java_class_header'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module ClassList # :nodoc:
|
6
|
+
|
7
|
+
# Search in zip or jar files for Java class files, check for package access or inner classes and
|
8
|
+
# call back a list of all these.
|
9
|
+
# Author:: Peter Kofler
|
10
|
+
class JarSearcher
|
11
|
+
|
12
|
+
attr_accessor :skip_inner_classes
|
13
|
+
attr_accessor :skip_package_classes
|
14
|
+
|
15
|
+
# Create a new searcher.
|
16
|
+
def initialize
|
17
|
+
@skip_inner_classes = true
|
18
|
+
@skip_package_classes = false
|
19
|
+
@package_filters = []
|
20
|
+
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>.
|
24
|
+
def filters=(filters)
|
25
|
+
@package_filters = filters.collect{ |f| /^#{f}/ }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return the list of classnames of this list of _classes_ .
|
29
|
+
# Skips inner classes if +skip_inner_classes+ is true.
|
30
|
+
# Skips classes that are in the filtered packages.
|
31
|
+
def filter_classes(classes)
|
32
|
+
classes.find_all do |name|
|
33
|
+
!(@skip_inner_classes && name =~ /\$/) && (@package_filters.find { |filter| name =~ filter } == nil)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return true if the _classfile_ in the given _classpath_ is public. This is expensive because
|
38
|
+
# the jarfile is opened and the _classfile_ is extracted and read.
|
39
|
+
def public?(classpath, classfile)
|
40
|
+
begin
|
41
|
+
header = ClassFile::JavaClassHeader.new(classpath.load_binary(classfile))
|
42
|
+
rescue
|
43
|
+
puts "error #{$1} for class #{classfile} on #{classpath.to_s}"
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
raise "invalid java class #{classfile}" unless header.magic.valid?
|
47
|
+
header.access_flags.accessible?
|
48
|
+
end
|
49
|
+
|
50
|
+
# Compile the class list for the given _version_ of Java. This searches the _path_ for zips and jars
|
51
|
+
# and adds them to the given _list_ of found classes. _version_ is a number >= 0, e.g. 2 for JDK 1.2.
|
52
|
+
# _list_ must provide a <code>add_class(entry, is_public, version)</code> method.
|
53
|
+
def compile_list(version, path, list)
|
54
|
+
cpe = JavaClass::Classpath::CompositeClasspath.new
|
55
|
+
cpe.find_jars(path)
|
56
|
+
filter_classes(cpe.names).each do |entry|
|
57
|
+
is_public = public?(cpe, entry)
|
58
|
+
next if @skip_package_classes && !is_public
|
59
|
+
list.add_class(entry, is_public, version) if list
|
60
|
+
yield(entry, is_public, version) if block_given?
|
61
|
+
end
|
62
|
+
|
63
|
+
list
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'javaclass/java_name'
|
2
|
+
require 'javaclass/classlist/package_entry'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module ClassList # :nodoc:
|
6
|
+
|
7
|
+
# Classes to form a list of JDK classes to find classes which have been added in new releases.
|
8
|
+
# The list of classes. It list contains packages.
|
9
|
+
# Author:: Peter Kofler
|
10
|
+
class List
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@packages = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Add a _fileentry_ to the list. The _fileentry_ is the file name of the class in the jar file. _version_
|
17
|
+
# is the version of the JDK scanned and is used if the class is new.
|
18
|
+
def add_class(fileentry, is_public, version)
|
19
|
+
class_name = fileentry.to_javaname.to_classname
|
20
|
+
package_name = class_name.package
|
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)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parse a _line_ from a <code>fullClassList</code> and fill the list again. _maxversion_ is the maximum
|
26
|
+
# max version from the list, i.e. the highest possible value, so we can continue to use it.
|
27
|
+
def parse_line(line, maxversion)
|
28
|
+
class_name, versions = line.scan(/^([^\s]+)\s(?:\[(.*)\]\s)?-\s*$/)[0]
|
29
|
+
|
30
|
+
# no [], so we have it from always and it is public
|
31
|
+
first_vers = 0
|
32
|
+
last_vers = maxversion
|
33
|
+
is_public = true
|
34
|
+
if versions
|
35
|
+
# extract package access and drop it
|
36
|
+
is_public = (versions !~ /p/)
|
37
|
+
versions = versions.gsub(/p/, '')
|
38
|
+
|
39
|
+
# \d, \d-\d, only \d, -\d, oder leer
|
40
|
+
if versions =~ /^(\d)$/
|
41
|
+
first_vers = $1.to_i
|
42
|
+
elsif versions =~ /^(\d)-(\d)$/
|
43
|
+
first_vers = $1.to_i
|
44
|
+
last_vers = $2.to_i
|
45
|
+
elsif versions =~ /^(?:bis\s|-)(\d)$/
|
46
|
+
last_vers = $1.to_i
|
47
|
+
elsif versions =~ /^only (\d)$/
|
48
|
+
first_vers = $1.to_i
|
49
|
+
last_vers = $1.to_i
|
50
|
+
else
|
51
|
+
raise "can't match version number #{versions} in line #{line.chomp}" unless versions == ''
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
first_vers.upto(last_vers) do |v|
|
56
|
+
add_class(class_name, is_public, v)
|
57
|
+
end
|
58
|
+
rescue
|
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
|
+
end
|
61
|
+
|
62
|
+
def packages
|
63
|
+
@packages.values.sort
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return the version list of all packages.
|
67
|
+
def version
|
68
|
+
packages.collect { |p| p.version }.flatten.uniq.sort
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the first and last version of this list.
|
72
|
+
def first_last_versions
|
73
|
+
v = version
|
74
|
+
[v.first, v.last]
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
packages.collect { |p| p.to_s }.join("\n")
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return the number of classes in this list.
|
82
|
+
def size
|
83
|
+
@packages.values.inject(0) {|sum, p| sum + p.size }
|
84
|
+
end
|
85
|
+
|
86
|
+
# The access list is the raw list of all package access classes for one version. It was used to differ
|
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 +skip_package_classes+ set to false (default).
|
89
|
+
# If there are more versions loaded, then only the last version is printed. So we get consecutive lists
|
90
|
+
# of new package access classes with every JDK version.
|
91
|
+
def old_access_list
|
92
|
+
v = first_last_versions
|
93
|
+
packages.collect { |pkg|
|
94
|
+
pkg.classes.find_all { |c| !c.public? && c.version == [v[1]]}.collect { |c| c.to_full_qualified_s(v[0], v[1]) }
|
95
|
+
}.flatten.sort{|a,b| a.casecmp b }
|
96
|
+
end
|
97
|
+
|
98
|
+
# The class list is the raw list of all classes for one version without version or package access
|
99
|
+
# descriptors. It was used to find differences and was saved in <code>doc/ClassLists/*_classes.txt</code>.
|
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.
|
102
|
+
def plain_class_list
|
103
|
+
packages.collect { |pkg|
|
104
|
+
cls = pkg.classes
|
105
|
+
if block_given?
|
106
|
+
cls = cls.find_all { |c| yield(c) }
|
107
|
+
end
|
108
|
+
cls.collect { |c| c.full_name + "\n" }
|
109
|
+
}.flatten.sort{|a,b| a.casecmp b }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Create a full class list with version numbers and different versions to compare.
|
113
|
+
# This was the base for classlists and was saved in <code>doc/fullClassList1x.txt</code>.
|
114
|
+
# This usually was done with JarSearcher set +skip_package_classes+ to false and
|
115
|
+
# contained different classlists merged together.
|
116
|
+
def full_class_list
|
117
|
+
v = first_last_versions
|
118
|
+
packages.collect { |pkg|
|
119
|
+
pkg.classes.collect { |c| c.to_full_qualified_s(v[0], v[1]) }
|
120
|
+
}.flatten.sort{|a,b| a.casecmp b }
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'javaclass/classlist/class_entry'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module ClassList # :nodoc:
|
5
|
+
|
6
|
+
# A package in the List.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class PackageEntry # ZenTest FULL to find method <=>
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
# Return the list of versions this package exists. This is the sum of all versions of all classes in the package.
|
12
|
+
attr_reader :version
|
13
|
+
|
14
|
+
# Create a new package with name _name_ and first version _vers_ which is the version of the first class in the package.
|
15
|
+
def initialize(name, vers=0)
|
16
|
+
@name = name
|
17
|
+
@version = [vers]
|
18
|
+
@classes = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_class(class_name, is_public, version)
|
22
|
+
@version << version unless @version.include? version
|
23
|
+
@version = @version.sort
|
24
|
+
|
25
|
+
unless @classes.has_key?(class_name)
|
26
|
+
@classes[class_name] = ClassEntry.new(self, class_name, is_public, version)
|
27
|
+
else
|
28
|
+
@classes[class_name].update(version, is_public)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sorting in packages is: <code>java.lang</code>, other <code>java.*</code>, <code>javax.*</code> and then others.
|
33
|
+
def <=>(other)
|
34
|
+
if @name =~ /^java\.lang$/ and other.name !~ /^java\.lang$/
|
35
|
+
-1
|
36
|
+
elsif @name !~ /^java\.lang$/ and other.name =~ /^java\.lang$/
|
37
|
+
1
|
38
|
+
elsif @name =~ /^java\./ and other.name !~ /^java\./
|
39
|
+
-1
|
40
|
+
elsif @name !~ /^java\./ and other.name =~ /^java\./
|
41
|
+
1
|
42
|
+
elsif @name =~ /^javax\./ and other.name !~ /^javax\./
|
43
|
+
-1
|
44
|
+
elsif @name !~ /^javax\./ and other.name =~ /^javax\./
|
45
|
+
1
|
46
|
+
else
|
47
|
+
@name <=> other.name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the classes in this package.
|
52
|
+
def classes
|
53
|
+
@classes.values.sort
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return the number of classes in this package.
|
57
|
+
def size
|
58
|
+
@classes.size
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
@name
|
63
|
+
end
|
64
|
+
|
65
|
+
# Special version of +to_s+ for package shortcut. A package needs _minversion_ and _maxversion_ to
|
66
|
+
# determine if the whole package was dropped.
|
67
|
+
def to_package_shortcut_s(minversion, maxversion)
|
68
|
+
"#{@name}#{format_version(minversion, maxversion)} - \n" +
|
69
|
+
classes.collect { |c| c.to_package_shortcut_s }.join
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def format_version(minversion, maxversion)
|
75
|
+
is_newer = @version.first > minversion
|
76
|
+
is_outdated = @version.last < maxversion
|
77
|
+
line =
|
78
|
+
" [#{ is_newer ? @version.first.to_s : ''}" +
|
79
|
+
"#{is_outdated ? '-' + @version.last.to_s : ''}" +
|
80
|
+
"]"
|
81
|
+
line.sub(/(\d)-\1/, "only \\1").sub(/ \[\]/, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'javaclass/classpath/jar_classpath'
|
2
|
+
require 'javaclass/classpath/folder_classpath'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module Classpath
|
6
|
+
# List of class path elements.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class CompositeClasspath
|
9
|
+
# Return the list of classnames found in this path.
|
10
|
+
def initialize
|
11
|
+
@elements = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Return the classpath elements of this path.
|
15
|
+
def elements
|
16
|
+
@elements.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
# Search the given _path_ recursievely for zips or jars. Add all found jars to this classpath.
|
20
|
+
def find_jars(path)
|
21
|
+
current = Dir.getwd
|
22
|
+
begin
|
23
|
+
Dir.chdir File.expand_path(path)
|
24
|
+
|
25
|
+
Dir['*'].collect do |name|
|
26
|
+
if FileTest.directory?(name)
|
27
|
+
find_jars(name)
|
28
|
+
elsif name =~ /\.jar$|\.zip$/
|
29
|
+
add_file_name File.expand_path(name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ensure
|
34
|
+
Dir.chdir current
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add the _name_ class path file/folder name to the list.
|
39
|
+
def add_file_name(name)
|
40
|
+
if FileTest.directory? name
|
41
|
+
add_element(FolderClasspath.new(name))
|
42
|
+
else
|
43
|
+
add_element(JarClasspath.new(name))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add the _elem_ classpath element to the list.
|
48
|
+
def add_element(elem)
|
49
|
+
@elements << elem unless @elements.find { |cpe| cpe == elem }
|
50
|
+
elem.additional_classpath.each do |acpe|
|
51
|
+
# referred classpath elements may be missing
|
52
|
+
if FileTest.exist? acpe
|
53
|
+
add_element(JarClasspath.new(acpe))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return false.
|
59
|
+
def jar?
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return an empty array.
|
64
|
+
def additional_classpath
|
65
|
+
[]
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return the list of class names found in this classpath.
|
69
|
+
def names
|
70
|
+
@elements.collect { |e| e.names }.flatten.uniq
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return if _classname_ is included in this classpath.
|
74
|
+
def includes?(classname)
|
75
|
+
@elements.find { |e| e.includes?(classname) } != nil
|
76
|
+
end
|
77
|
+
|
78
|
+
# Load the binary data of the file name or class name _classname_ from this classpath.
|
79
|
+
def load_binary(classname)
|
80
|
+
found = @elements.find { |e| e.includes?(classname) }
|
81
|
+
if (found)
|
82
|
+
return found.load_binary(classname)
|
83
|
+
end
|
84
|
+
raise "class #{classname} not found in classpath #{to_s}"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return the number of classes in this jar.
|
88
|
+
def count
|
89
|
+
@elements.inject(0) { |s,e| s + e.count }
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
@elements.collect { |e| e.to_s }.join(',')
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'javaclass/java_name'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Classpath # :nodoc:
|
5
|
+
# Abstraction of a folder on the CLASSPATH.
|
6
|
+
# Author:: Peter Kofler
|
7
|
+
class FolderClasspath
|
8
|
+
# Return the list of classnames found in this _folder_ .
|
9
|
+
def initialize(folder)
|
10
|
+
@folder = folder
|
11
|
+
raise IOError, "folder #{@folder} not found" if !FileTest.exist? @folder
|
12
|
+
raise "#{@folder} is no folder" if !FileTest.directory? @folder
|
13
|
+
@classes = list_classes.collect { |cl| cl.to_javaname }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return false.
|
17
|
+
def jar?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return an empty array.
|
22
|
+
def additional_classpath
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the list of class names found in this folder.
|
27
|
+
def names
|
28
|
+
@classes.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return if _classname_ is included in this folder.
|
32
|
+
def includes?(classname)
|
33
|
+
@classes.include?(normalize(classname))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Load the binary data of the file name or class name _classname_ from this jar.
|
37
|
+
def load_binary(classname)
|
38
|
+
raise "class #{classname} not found in #{@folder}" unless includes?(classname)
|
39
|
+
File.open(File.join(@folder, normalize(classname)), 'rb') {|io| io.read }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return the number of classes in this folder.
|
43
|
+
def count
|
44
|
+
@classes.size
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
@folder
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
other.class == FolderClasspath && other.to_s == self.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Return the list of classnames (in fact file names) found in this folder.
|
58
|
+
def list_classes
|
59
|
+
current = Dir.getwd
|
60
|
+
begin
|
61
|
+
Dir.chdir @folder
|
62
|
+
|
63
|
+
list = Dir['**/*.class']
|
64
|
+
|
65
|
+
ensure
|
66
|
+
Dir.chdir current
|
67
|
+
end
|
68
|
+
list.sort
|
69
|
+
end
|
70
|
+
|
71
|
+
# Normalize the file name or class name _classname_ to be a file name in the jar.
|
72
|
+
def normalize(classname)
|
73
|
+
if classname !~ /\.class$/
|
74
|
+
classname.gsub(/\./,'/') + '.class'
|
75
|
+
else
|
76
|
+
classname
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'zip/zipfilesystem'
|
2
|
+
require 'javaclass/java_name'
|
3
|
+
|
4
|
+
module JavaClass
|
5
|
+
module Classpath
|
6
|
+
|
7
|
+
# Abstraction of a ZIP or JAR on the CLASSPATH.
|
8
|
+
# Author:: Peter Kofler
|
9
|
+
class JarClasspath
|
10
|
+
|
11
|
+
# Return the list of classnames found in this _jarfile_ .
|
12
|
+
def initialize(jarfile)
|
13
|
+
@jarfile = jarfile
|
14
|
+
raise IOError, "jarfile #{@jarfile} not found" if !FileTest.exist? @jarfile
|
15
|
+
raise "#{@jarfile} is no file" if !FileTest.file? @jarfile
|
16
|
+
@classes = list_classes.collect { |cl| cl.to_javaname }
|
17
|
+
@manifest =
|
18
|
+
begin
|
19
|
+
Zip::ZipFile.open(@jarfile) { |zipfile| zipfile.file.read("META-INF/MANIFEST.MF") }
|
20
|
+
rescue
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return if the given classpath element is a jar.
|
26
|
+
def jar?
|
27
|
+
@manifest != nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return list of additional classpath elements defined in the manifest of this jarfile.
|
31
|
+
def additional_classpath
|
32
|
+
if @manifest
|
33
|
+
cp = @manifest.gsub(/\s{4,}/, ' ').scan(/^(.*): (.*)\s*$/).find { |p| p[0] == 'Class-Path' }
|
34
|
+
if cp
|
35
|
+
cp[1].strip.split.collect { |jar| File.join(File.dirname(@jarfile), jar) }
|
36
|
+
else
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
else
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return the list of class names found in this jar.
|
45
|
+
def names
|
46
|
+
@classes.dup
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return if _classname_ is included in this jar.
|
50
|
+
def includes?(classname)
|
51
|
+
@classes.include?(normalize(classname))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Load the binary data of the file name or class name _classname_ from this jar.
|
55
|
+
def load_binary(classname)
|
56
|
+
raise "class #{classname} not found in #{@jarfile}" unless includes?(classname)
|
57
|
+
Zip::ZipFile.open(@jarfile) do |zipfile|
|
58
|
+
zipfile.file.read(normalize(classname))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return the number of classes in this jar.
|
63
|
+
def count
|
64
|
+
@classes.size
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
@jarfile
|
69
|
+
end
|
70
|
+
|
71
|
+
def ==(other)
|
72
|
+
other.class == JarClasspath && other.to_s == self.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# Return the list of classnames (in fact file names) found in this jarfile.
|
78
|
+
def list_classes
|
79
|
+
list = []
|
80
|
+
Zip::ZipFile.foreach(@jarfile) do |entry|
|
81
|
+
name = entry.name
|
82
|
+
next unless entry.file? and name =~ /\.class$/ # class file
|
83
|
+
list << name
|
84
|
+
end
|
85
|
+
list.sort
|
86
|
+
end
|
87
|
+
|
88
|
+
# Normalize the file name or class name _classname_ to be a file name in the jar.
|
89
|
+
def normalize(classname)
|
90
|
+
if classname !~ /\.class$/
|
91
|
+
classname.gsub(/\./,'/') + '.class'
|
92
|
+
else
|
93
|
+
classname
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'javaclass/classpath/jar_classpath'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Classpath
|
5
|
+
|
6
|
+
# Abstraction of the Java boot CLASSPATH. May return additional classpath elements for endorsed libs.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class JavaHomeClasspath < JarClasspath
|
9
|
+
|
10
|
+
# Return the list of classnames found in this _javahome_ .
|
11
|
+
def initialize(javahome)
|
12
|
+
if FileTest.exist? rtjar=File.join(javahome, 'lib', 'rt.jar')
|
13
|
+
super(rtjar)
|
14
|
+
elsif FileTest.exist? rtjar=File.join(javahome, 'jre', 'lib', 'rt.jar')
|
15
|
+
super(rtjar)
|
16
|
+
else
|
17
|
+
raise IOError, "rt.jar not found in java home #{javahome}"
|
18
|
+
end
|
19
|
+
@lib = File.dirname(rtjar)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return list of additional classpath elements, e.g. endorsed libs found in this Java Home.
|
23
|
+
def additional_classpath
|
24
|
+
list = super
|
25
|
+
|
26
|
+
if FileTest.exist? ext=File.join(@lib, 'ext')
|
27
|
+
current = Dir.getwd
|
28
|
+
Dir.chdir ext
|
29
|
+
|
30
|
+
list += Dir['*.jar'].collect { |jar| File.join(ext, jar) }
|
31
|
+
|
32
|
+
Dir.chdir current
|
33
|
+
end
|
34
|
+
list
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|