javaclass 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +188 -194
  3. data/Readme.txt +33 -29
  4. data/examples/generate_class_lists.rb +16 -9
  5. data/history.txt +15 -4
  6. data/javaclass.gemspec +10 -8
  7. data/lib/generated/examples/chart_class_dependencies.txt +35 -0
  8. data/lib/generated/examples/chart_module_dependencies.txt +43 -0
  9. data/lib/generated/examples/check_interface_names.txt +36 -0
  10. data/lib/generated/examples/count_classes_in_modules.txt +31 -0
  11. data/lib/generated/examples/cumulative_dependencies.txt +28 -0
  12. data/lib/generated/examples/find_all_imported_types.txt +38 -0
  13. data/lib/generated/examples/find_incoming_dependency_graph.txt +73 -0
  14. data/lib/generated/examples/find_layers_of_modules.txt +70 -0
  15. data/lib/generated/examples/find_referenced_modules.txt +41 -0
  16. data/lib/generated/examples/find_unreferenced_classes.txt +66 -0
  17. data/lib/generated/examples/generate_class_lists.txt +53 -0
  18. data/lib/generated/examples/show_jar_api.txt +64 -0
  19. data/lib/generated/examples/simple_usage.txt +38 -0
  20. data/lib/javaclass/classfile/access_flag_constants.rb +32 -5
  21. data/lib/javaclass/classfile/access_flags.rb +39 -20
  22. data/lib/javaclass/classfile/attributes/attributes.rb +134 -0
  23. data/lib/javaclass/classfile/class_access_flags.rb +37 -0
  24. data/lib/javaclass/classfile/class_file_attributes.rb +62 -0
  25. data/lib/javaclass/classfile/class_version.rb +0 -1
  26. data/lib/javaclass/classfile/constant_pool.rb +17 -11
  27. data/lib/javaclass/classfile/constants/single_reference.rb +53 -0
  28. data/lib/javaclass/classfile/fields.rb +37 -0
  29. data/lib/javaclass/classfile/java_class_header.rb +22 -13
  30. data/lib/javaclass/classfile/java_class_header_shortcuts.rb +6 -2
  31. data/lib/javaclass/classfile/methods.rb +37 -0
  32. data/lib/javaclass/classlist/jar_searcher.rb +38 -4
  33. data/lib/javaclass/classpath/temporary_unpacker.rb +1 -1
  34. data/lib/javaclass/string_hexdump.rb +1 -1
  35. data/license.txt +7 -7
  36. data/test/data/access_flags/{AccessFlagsTestInner$1.class → AccessFlagsTestAnonym$1.class} +0 -0
  37. data/test/data/access_flags/{AccessFlagsTestInner.class → AccessFlagsTestAnonym.class} +0 -0
  38. data/test/data/access_flags/AccessFlagsTestAnonym.java +9 -0
  39. data/test/data/access_flags/AccessFlagsTestPublic_javap.txt +1 -0
  40. data/test/data/constant_pool/Java8_JavaFX_Animation$1_Tag15.class +0 -0
  41. data/test/data/constant_pool/Java9_Activation_module-info_Tag20.class +0 -0
  42. data/test/data/jar_searcher/JarClassListTest.jar +0 -0
  43. data/test/data/jar_searcher/PublicClass.java +44 -1
  44. data/test/data/jar_searcher/make.bat +1 -2
  45. data/test/{test_access_flags.rb → test_class_access_flags.rb} +91 -93
  46. data/test/test_class_file_attributes.rb +57 -0
  47. data/test/test_constant_pool.rb +31 -0
  48. data/test/test_jar_searcher.rb +40 -7
  49. data/test/test_javaclass_api.rb +2 -2
  50. data/test/test_string_hexdump.rb +4 -1
  51. data/test/ts_all_tests.rb +4 -2
  52. metadata +100 -116
  53. data/test/data/access_flags/AccessFlagsTestInner$2.class +0 -0
  54. data/test/data/access_flags/AccessFlagsTestInner.java +0 -13
@@ -22,8 +22,8 @@ JDK_CONFIG = Struct.new(:version, :label, :paths)
22
22
  # Windows 7 configuration for 32bit Sun/Oracle JVMs
23
23
  PROGRAMS = 'C:\Program Files (x86)\Java'
24
24
  JDKS = [
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']),
25
+ JDK_CONFIG.new(0, '1.0.2', [PROGRAMS + '\jdk1.0.2\lib']),
26
+ JDK_CONFIG.new(1, '1.1.8-09', [PROGRAMS + '\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
27
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
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
29
  JDK_CONFIG.new(4, '1.4.2-03', [PROGRAMS + '\jdk1.4.2_03\jre\lib', PROGRAMS + '\jdk1.4.2_03\lib\dt.jar']),
@@ -31,6 +31,7 @@ JDKS = [
31
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
32
  JDK_CONFIG.new(7, '1.7.0', [PROGRAMS + '\jdk1.7.0\jre\lib', PROGRAMS + '\jdk1.7.0\lib\dt.jar']),
33
33
  JDK_CONFIG.new(8, '1.8.0', [PROGRAMS + '\jdk1.8.0_25\jre\lib', PROGRAMS + '\jdk1.8.0_25\lib\dt.jar']),
34
+ JDK_CONFIG.new(9, '9.0.4', [PROGRAMS + '\open_jdk9.0.4-1\jmods', PROGRAMS + '\open_jdk9.0.4-1\lib\jrt-fs.jar']),
34
35
  ]
35
36
  #++
36
37
  # configuration for some JDKs
@@ -39,16 +40,22 @@ JDKS = [
39
40
  # 1) create a JavaClass::ClassList::JarSearcher
40
41
  JavaClass.unpack_jars!(:unpack)
41
42
  searcher = JavaClass::ClassList::JarSearcher.new
43
+ searcher.skip_inner_classes = false
44
+ searcher.skip_package_classes = true
42
45
 
43
46
  # 2) filter out unwanted classes, e.g. vendor classes
44
- searcher.filters = %w[sun/ sunw/ com/oracle/ com/sun/ netscape/ COM/rsa/
45
- quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
47
+ searcher.filters = %w[sun/ sunw/ com/oracle/ com/sun/ netscape/ com/rsa/
48
+ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/
49
+ oracle/jrockit/ jdk/internal/ jdk/nashorn/internal/
50
+ jdk/dynalink/internal/ jdk/incubator/http.internal/ jdk/javadoc/internal/ jdk/tools/jlink/internal/ ]
46
51
  #--
47
52
  # netscape ... applet js security [2]
48
53
  # COM/rsa/ ... jsafe [4]
49
54
  # quicktime ... quicktime [5]
50
55
  # org/jcp/xml/dsig/internal ... xml dsig [6]
51
56
  # com/oracle/ ... com.oracle.net.Sdp [7]
57
+ # oracle/jrockit/ jdk/internal/ jdk/nashorn/internal/ [8]
58
+ # jdk/dynalink/internal/ jdk/incubator/http.internal/ jdk/javadoc/internal/ jdk/tools/jlink/internal/ [9]
52
59
 
53
60
  Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
54
61
  #++
@@ -73,14 +80,14 @@ JDKS.each do |conf|
73
80
 
74
81
  # 5) save various kind of lists
75
82
  basename = "./ClassLists/jdk#{conf.label.gsub(/\./, '')}"
76
- File.open("#{basename}_new_package_classes.txt", "w") { |f| f.print list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
77
- File.open("#{basename}_all_classes.txt", "w") { |f| f.print list.plain_class_list }
83
+ # File.open("#{basename}_new_package_classes.txt", "w") { |f| f.print list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
84
+ # File.open("#{basename}_all_classes.txt", "w") { |f| f.print list.plain_class_list }
78
85
  File.open("#{basename}_all_packages.txt", "w") { |f| f.print list.to_s }
79
- File.open("#{basename}_all_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? } }
80
- File.open("#{basename}_new_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
86
+ File.open("#{basename}_all_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? }.join() }
87
+ File.open("#{basename}_new_public_classes.txt", "w") { |f| f.print list.plain_class_list { |c| c.public? and c.version.first == conf.version }.join() }
81
88
 
82
89
  baseversion = conf.label.gsub(/\.|-.+$/, '')
83
- File.open("./fullClassList#{baseversion}.txt", "w") { |f| f.print list.full_class_list }
90
+ File.open("./fullClassList#{baseversion}.txt", "w") { |f| f.print list.full_class_list.join() }
84
91
 
85
92
  puts "processed #{conf.label}"
86
93
  end
@@ -1,12 +1,23 @@
1
+ === 0.4.2 16/09/2020
2
+
3
+ * fix license text and name
4
+ * tested with GitHub actions for Ruby 2.1 to 2.7
5
+ * fix some warnings shown by Ruby 2.1
6
+ * moved code to GitHub
7
+ * added outer class name for inner classes
8
+ * added new constant pool tags and access modifier for Java 9
9
+ * added method handle and invoke dynamic constant pool tags for Java 8
10
+ * parse class attributes: source file and inner classes
11
+
1
12
  === 0.4.1 30/05/2015
2
13
 
3
14
  * make compatible with Ruby 2.0
4
15
  * upgrade rubyzip to 1.x (still supports 0.x as well)
5
16
  * moved code to Bitbucket, moved API doc to code-cop.org
6
- * Cloudbees dropped support for Ruby 1.8.6 and 1.8.7 - not testet there anymore
17
+ * Cloudbees dropped support for Ruby 1.8.6 and 1.8.7 - not tested there any more
7
18
  * add plain class Node for dependency graph
8
19
  * add dependency graph and classpath (module/component/plugin) implementation
9
- * add Maven artefact to generate classpath from group/name/version
20
+ * add Maven artifact to generate classpath from group/name/version
10
21
  * change version number from micro to minor which more proper reflects code
11
22
  * fix some warnings shown by Ruby 1.9.1
12
23
 
@@ -14,7 +25,7 @@
14
25
 
15
26
  * convert examples to RDOC using example_task
16
27
  * added transitive dependency trees from references
17
- * patched the rubyzip for invalid flags found in some JARs
28
+ * patched the rubyzip gem for invalid flags found in some JARs
18
29
  * add some examples
19
30
  * fixed generate_class_lists.rb
20
31
  * finish first version of DSL with loading/values
@@ -37,7 +48,7 @@
37
48
  * integrated ClassList from another project as first analyser
38
49
  * added abstraction of Java names to all class names that are returned
39
50
  * fixed links in RDoc, update documentation
40
- * moved classes into submodules for classpath, classfile, etc.
51
+ * moved classes into sub modules for classpath, class file, etc.
41
52
  * migrated to Google Code and Mercurial repository
42
53
  * added access flag $1000
43
54
  * added references to used classes
@@ -1,17 +1,18 @@
1
1
  GEM_NAME = 'javaclass'
2
- HG_PROJECT = "#{GEM_NAME}-rb"
2
+ GIT_PROJECT = "#{GEM_NAME}-rb"
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.version = '0.4.1'
5
+ s.version = '0.4.2'
6
6
  s.name = GEM_NAME
7
- s.rubyforge_project = 'javaclass' # old, just redirects
7
+ s.rubyforge_project = 'javaclass' if s.respond_to? :rubyforge_project=
8
+ # Gem::Specification#rubyforge_project= is deprecated with no replacement in 2.7
8
9
  s.summary = 'Java class files parser and disassembler for Ruby'
9
10
  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 = "https://bitbucket.org/pkofler/#{HG_PROJECT}"
11
+ s.license = 'BSD-2-Clause'
12
+ s.homepage = "https://github.com/codecop/#{GIT_PROJECT}"
12
13
  s.author = 'Peter Kofler'
13
14
  s.email = 'peter dot kofler at code minus cop dot org'
14
- s.date = Time::gm(2015, 5, 30) # set current date for release
15
+ s.date = Time::gm(2020, 9, 16) # set current date for release
15
16
 
16
17
  s.files = Dir.glob('*.txt') + Dir.glob('{lib,test,examples}/**/*') + ['javaclass.gemspec', 'Rakefile'] + Dir.glob('rake_*.rb') + Dir.glob('dev/*_task.rb')
17
18
  s.test_files = Dir.glob('test/**/test_*.rb')
@@ -20,12 +21,13 @@ Gem::Specification.new do |s|
20
21
  s.required_ruby_version = '>= 1.8.6'
21
22
  s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
22
23
  s.platform = Gem::Platform::RUBY
23
- s.add_development_dependency('rake', '>= 0.8.3')
24
+ # s.add_development_dependency('rake', '>= 0.8.3')
24
25
  # s.add_development_dependency('rcov', '>= 0.8.1.2')
25
26
  # s.add_development_dependency('saikuro', '>= 1.2.1')
26
27
  # s.add_development_dependency('ZenTest', '>= 4.4.0')
27
28
 
28
- s.has_rdoc = true
29
+ s.has_rdoc = true if s.respond_to? :has_rdoc=
30
+ # Gem::Specification#has_rdoc= is deprecated with no replacement in 2.6
29
31
  s.extra_rdoc_files = Dir.glob('*.txt')
30
32
  s.rdoc_options << '--title' << "#{s.name}-#{s.version} Documentation" <<
31
33
  '--main' << 'Readme.txt'
@@ -0,0 +1,35 @@
1
+ # Example usage of JavaClass::Dependencies::Graph: Iterate all classes of a
2
+ # classpath and construct the Java dependency graph.
3
+ # Author:: Peter Kofler
4
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
5
+ # License:: {BSD License}[link:/files/license_txt.html]
6
+ #
7
+ # === Steps
8
+ #
9
+ # require 'javaclass/dsl/mixin'
10
+ # require 'javaclass/dependencies/graph'
11
+ # require 'javaclass/dependencies/class_node'
12
+ # require 'javaclass/dependencies/yaml_serializer'
13
+ # require 'javaclass/dependencies/graphml_serializer'
14
+ #
15
+ # 1) create the classpath of a given location
16
+ # cp = classpath(location)
17
+ #
18
+ # dependencies = JavaClass::Dependencies::Graph.new
19
+ #
20
+ # 2) iterate all classes of the classpath
21
+ # cp.values.each do |clazz|
22
+ # next unless clazz.access_flags.public?
23
+ #
24
+ # 3) add a JavaClass::Dependencies::ClassNode for each class to the graph
25
+ # dependencies.add(JavaClass::Dependencies::ClassNode.new(clazz))
26
+ # end
27
+ #
28
+ # 4) resolve all dependencies of all nodes in the graph. Now each class (Node) has a dependency to
29
+ # all imported classes (Nodes).
30
+ # dependencies.resolve_dependencies
31
+ # puts "#{dependencies.to_a.size} classes loaded"
32
+ #
33
+ # 5) save the result in various formats, e.g. GraphML or YAML, skipping outgoing edges information
34
+ # JavaClass::Dependencies::GraphmlSerializer.new(:edges => :no_text).save('class_dependencies', dependencies)
35
+ # JavaClass::Dependencies::YamlSerializer.new(:outgoing => :none).save('class_dependencies', dependencies)
@@ -0,0 +1,43 @@
1
+ # Example usage of JavaClass::Dependencies::Graph: Iterate all folders of a root folder.
2
+ # Load each component separately and construct the dependency graph.
3
+ # Author:: Peter Kofler
4
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
5
+ # License:: {BSD License}[link:/files/license_txt.html]
6
+ #
7
+ # === Steps
8
+ #
9
+ # require 'javaclass/dsl/mixin'
10
+ # require 'javaclass/dependencies/graph'
11
+ # require 'javaclass/dependencies/classpath_node'
12
+ # require 'javaclass/dependencies/yaml_serializer'
13
+ # require 'javaclass/dependencies/graphml_serializer'
14
+ #
15
+ # 1) define the location of the plugins
16
+ # location = 'C:\Eclipse\workspace'
17
+ #
18
+ # plugins = JavaClass::Dependencies::Graph.new
19
+ #
20
+ # 2) iterate all plugins of a workspace location
21
+ # Dir.new(location).each do |folder|
22
+ # path = File.join(location, folder)
23
+ # next unless FileTest.directory? path
24
+ #
25
+ # classes = File.join(path, 'bin')
26
+ # next unless FileTest.exist?(classes)
27
+ #
28
+ # 3) create a classpath for each plugin
29
+ # cp = classpath(classes)
30
+ # next if cp.count == 0
31
+ #
32
+ # 4) add a JavaClass::Dependencies::Node for that plugin to the graph
33
+ # plugins.add(JavaClass::Dependencies::ClasspathNode.new(folder, cp))
34
+ # end
35
+ #
36
+ # 5) resolve all dependencies of all nodes in the graph
37
+ # plugins.resolve_dependencies
38
+ # puts "#{plugins.to_a.size} plugins loaded"
39
+ #
40
+ # 6) save the result in various formats, e.g. GraphML or YAML
41
+ # JavaClass::Dependencies::GraphmlSerializer.new.save('plugin_dependencies', plugins)
42
+ # JavaClass::Dependencies::YamlSerializer.new.save('plugin_dependencies', plugins)
43
+ # JavaClass::Dependencies::YamlSerializer.new(:outgoing => :summary).save('plugin_dependencies_summary', plugins)
@@ -0,0 +1,36 @@
1
+ # Example usage of classpath and class files: Scan all classes of an workspace.
2
+ # Find all interfaces, print their names and find all which are prefixed with 'I'.
3
+ # Author:: Peter Kofler
4
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
5
+ # License:: {BSD License}[link:/files/license_txt.html]
6
+ #
7
+ # === Steps
8
+ #
9
+ # require 'javaclass/dsl/mixin'
10
+ #
11
+ # 1) define the location of the project and a package you are interrested
12
+ # location = 'C:\Eclipse\workspace'
13
+ # package = 'com.biz.app'
14
+ #
15
+ # e.g. add an Eclipse classpath variable to find external dependencies.
16
+ # Eclipse.add_variable('KOR_HOME', location)
17
+ #
18
+ # 2) create the classpath of the given workspace
19
+ # cp = workspace(location)
20
+ # puts "#{cp.elements.size} classpaths found under the workspace #{location}:"
21
+ # puts " #{cp.elements.join("\n ")}"
22
+ # puts "#{cp.count} classes found on classpath"
23
+ #
24
+ # 3) filter the classes to analyse, using JavaClass::JavaQualifiedName methods
25
+ # to_analyse = cp.names { |classname| classname.same_or_subpackage_of?(package) }
26
+ # puts "#{to_analyse.size} classes matched #{package}"
27
+ #
28
+ # 4) load all selected classes, parse into JavaClass::ClassFile, find all interfaces and collect their qualified names
29
+ # names = cp.values(to_analyse).
30
+ # find_all { |clazz| clazz.interface? }.
31
+ # collect { |clazz| clazz.to_classname }
32
+ # puts "#{names.size} interfaces found:\n #{names.sort.join("\n ")}"
33
+ #
34
+ # 5) print all qualified names have a simple namee staring with an I
35
+ # inames = names.find_all { |classname| classname.simple_name =~ /^I[A-Z][a-z]/ }
36
+ # puts "#{inames.size} interfaces start with I:\n #{inames.join("\n ")}"
@@ -0,0 +1,31 @@
1
+ # Example usage of classpath (JavaClass::Classpath): Scan all classpaths (e.g. modules)
2
+ # of an an Eclipse "workspace". A workspace is a folder containing several Eclipse
3
+ # projects, e.g. JavaClass::Classpath::EclipseClasspath. Report the number of found
4
+ # classes per module.
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
+ # require 'javaclass/classpath/factory'
12
+ # include JavaClass::Classpath::Factory
13
+ # The require/include above just imports what is needed, but usually one would require the whole
14
+ # JavaClass::Dsl::Mixin for conveniance, e.g. require 'javaclass/dsl/mixin'.
15
+ #
16
+ # 1) define the location of the project
17
+ # location = 'C:\Eclipse\workspace'
18
+ #
19
+ # 2) create a JavaClass::Classpath::CompositeClasspath of the complete workspace, which will contain many classpath elements.
20
+ # cp = workspace(location)
21
+ # puts "#{cp.elements.size} classpaths found under the workspace #{location}"
22
+ #
23
+ # 3a) find all empty elements by querying the classpath elements
24
+ # empty = cp.elements.find_all { |clp| clp.count == 0 }
25
+ # puts "\n#{empty.size} empty modules found:\n #{empty.join("\n ")}"
26
+ #
27
+ # 3b) or print the list of each element with its class count
28
+ # puts "library (module path): number of contained classes"
29
+ # puts cp.elements.map { |clp| [clp.to_s, clp.count] }.
30
+ # sort { |a,b| a[1] <=> b[1] }.
31
+ # map { |e| " #{e[0]}: #{e[1]}" }
@@ -0,0 +1,28 @@
1
+ # Example usage of the featuress of JavaClass::Analyse::TransitiveDependencies
2
+ # to collect all transitive dependencies of a certain class or a whole package
3
+ # (Cumulative Component Dependencies).
4
+ # Author:: Peter Kofler
5
+ # Copyright:: Copyright (c) 2009, Peter Kofler.
6
+ # License:: {BSD License}[link:/files/license_txt.html]
7
+ # See:: Another example how to {list all imported types}[link:/files/lib/generated/examples/find_all_imported_types_txt.html]
8
+ #
9
+ # === Steps
10
+ #
11
+ # require 'javaclass/dsl/mixin'
12
+ #
13
+ # 1) create the classpath of the given workspace
14
+ # cp = workspace(location)
15
+ # puts "#{cp.count} classes found on classpath"
16
+ #
17
+ # define a filter to limit all operations to the classes we are interested in
18
+ # filter = Proc.new { |classname| classname.same_or_subpackage_of?(package) }
19
+ #
20
+ # 2a) collect all transitive dependencies of a single class into an AdderTree
21
+ # dependencies = cp.transitive_dependency_tree(start_class.to_javaname, &filter)
22
+ # puts "#{dependencies.size} classes in transitive dependency graph of class #{start_class}"
23
+ # dependencies.debug_print
24
+ #
25
+ # 2b) or collect all transitive dependencies of a whole package
26
+ # dependencies = cp.transitive_dependencies_package(start_class.to_javaname.package, &filter)
27
+ # puts "#{dependencies.size} classes in transitive dependency graph of package #{start_class.to_javaname.package}"
28
+ # dependencies.debug_print
@@ -0,0 +1,38 @@
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
+ # require 'javaclass/dsl/mixin'
12
+ #
13
+ # 1) create the classpath of production classes
14
+ # cp = classpath(prod_location)
15
+ #
16
+ # 2) remember all types defined on this classpath from JavaClass::Analyse::Dependencies
17
+ # prod_classnames = cp.types
18
+ #
19
+ # 3) collect all dependencies of all classes defined there
20
+ # imported_types_with_numbers = cp.used_types_map
21
+ # imported_classnames = imported_types_with_numbers.keys
22
+ #
23
+ # 4) also collect all classes referenced from config files, defined in JavaClass::JavaNameScanner
24
+ # hardcoded_classnames = scan_config_for_3rd_party_class_names(conf_location)
25
+ #
26
+ # 5) now we know all classes imported/used by production classes
27
+ # puts '---------- used 3rd party types in production ; 0 = hardcoded'
28
+ # used_classnames = (imported_classnames + hardcoded_classnames).uniq.sort - prod_classnames
29
+ # puts used_classnames
30
+ # used_classnames.each do |name|
31
+ # puts "#{name} ; #{imported_types_with_numbers[name]}"
32
+ # end
33
+ #
34
+ # 6) do the same for test classes, at least org.junit.* should show up here
35
+ # test_cp = classpath(test_location)
36
+ # puts '---------- used 3rd party types only in tests'
37
+ # test_classes = test_cp.external_types - prod_classnames - used_classnames
38
+ # puts test_classes
@@ -0,0 +1,73 @@
1
+ # Example usage of dependency graph: Invert the graph and see incoming dependencies of a module.
2
+ # After getting all classes of a module, use previously generated dependency graph to iterate
3
+ # all incoming edges. Then either report all incoming edges as CSV or find all private/inner
4
+ # classes of the module. Works with an existing dependency graph,
5
+ # e.g. created by {chart module dependencies example}[link:/files/lib/generated/examples/chart_module_dependencies_txt.html].
6
+ # Author:: Peter Kofler
7
+ # Copyright:: Copyright (c) 2012, Peter Kofler.
8
+ # License:: {BSD License}[link:/files/license_txt.html]
9
+ #
10
+ # === Steps
11
+ #
12
+ # require 'javaclass/dsl/mixin'
13
+ # require 'javaclass/classpath/tracking_classpath'
14
+ # require 'javaclass/dependencies/edge'
15
+ # require 'javaclass/dependencies/yaml_serializer'
16
+ #
17
+ # 1) create a classpath of the main model plugin
18
+ # Plugin_name = 'org.codecop.model'
19
+ # cp = classpath(File.join(location, Plugin_name, 'bin'))
20
+ # classes = cp.names
21
+ # puts "#{classes.count} classes found in main plugin"
22
+ # cp.reset_access
23
+ #
24
+ # 2) load a dependency Graph containing the model
25
+ # plugins = JavaClass::Dependencies::YamlSerializer.new.load('plugin_dependencies')
26
+ #
27
+ # used to strip beginning of full qualified names
28
+ # def strip(name)
29
+ # name.sub(/^org\.codecop\./, '*.')
30
+ # end
31
+ #
32
+ # 3) mark all accessed classes in model plugin using the dependency graph
33
+ # plugins.each_node do |plugin|
34
+ # next if plugin.name == Plugin_name
35
+ # plugin.each_edge do |dep, edge|
36
+ # next unless dep.name == Plugin_name
37
+ # cp.mark_accessed(edge.target)
38
+ # end
39
+ # end
40
+ #
41
+ # plugins.each_node do |plugin|
42
+ # plugin.each_dependency_provider do |dep, dependencies|
43
+ # plugin.dependencies[dep] = dependencies.map { |edge|
44
+ # # replace class edges by package edges
45
+ # # JavaClass::Dependencies::Edge.new(edge.source.to_javaname.package, edge.target.to_javaname.package)
46
+ #
47
+ # # replace class edges with source plugin, target package
48
+ # # JavaClass::Dependencies::Edge.new(plugin.name, edge.target.to_javaname.package)
49
+ #
50
+ # # replace source edges with source plugin
51
+ # JavaClass::Dependencies::Edge.new(plugin.name, edge.target)
52
+ # }.uniq.sort
53
+ # end
54
+ # end
55
+ #
56
+ # 4) report all incoming dependencies (edges) for further Excel analysis
57
+ # plugins.each_node do |plugin|
58
+ # next if plugin.name == Plugin_name
59
+ # plugin.each_edge do |dep, edge|
60
+ # next unless dep.name == Plugin_name
61
+ # puts "#{strip(edge.target)};#{strip(plugin.name)};#{strip(edge.source)}"
62
+ # end
63
+ # end
64
+ #
65
+ # 5) report unused classes in model from outside
66
+ # unused_classes = classes.
67
+ # find_all { |clazz| cp.accessed(clazz) == 0 }.
68
+ # reject { |clazz| clazz =~ /\$.*$/ }
69
+ # report = unused_classes.map { |clazz| "#{clazz.to_classname}" }.uniq
70
+ # puts "#{report.size} private classes found:"
71
+ # report.each do |clazz|
72
+ # puts "#{strip(clazz)};(internal);NA"
73
+ # end
@@ -0,0 +1,70 @@
1
+ # Example usage of dependency graph: Organize the nodes into layers
2
+ # depending on their dependencies. Works with an existing dependency graph,
3
+ # e.g. created by {chart module dependencies example}[link:/files/lib/generated/examples/chart_module_dependencies_txt.html].
4
+ # Author:: Peter Kofler
5
+ # Copyright:: Copyright (c) 2012, Peter Kofler.
6
+ # License:: {BSD License}[link:/files/license_txt.html]
7
+ #
8
+ # === Steps
9
+ #
10
+ # require 'javaclass/dependencies/yaml_serializer'
11
+ #
12
+ # 1) load dependency graph
13
+ # plugins = JavaClass::Dependencies::YamlSerializer.new.load('plugin_dependencies')
14
+ # components = plugins.to_a
15
+ #
16
+ # @layerOfComponents = []
17
+ #
18
+ # 2) find modules without any dependencies, these are the first/bottom
19
+ # first_elements = components.find_all { |c| c.dependencies.size == 0 }.sort
20
+ # @layerOfComponents << first_elements
21
+ # components = components - first_elements
22
+ #
23
+ # def has_all_deps_satisfied?(component)
24
+ # already_sorted_dependencies = @layerOfComponents.flatten
25
+ # component.dependencies.keys.find { |dependency|
26
+ # !already_sorted_dependencies.include?(dependency)
27
+ # } == nil
28
+ # end
29
+ #
30
+ # while components.size > 0
31
+ # cycle = true
32
+ #
33
+ # # 3) for each component, check if all dependencies are satisfied combined layers below
34
+ # components.each do |component|
35
+ #
36
+ # if has_all_deps_satisfied?(component)
37
+ # components -= [component]
38
+ #
39
+ # # 4) if yes, walk up the dependencies until highest/lowest possible
40
+ # index = @layerOfComponents.size - 1
41
+ # while (component.dependencies.keys.find { |dependency| @layerOfComponents[index].include?(dependency) } == nil)
42
+ # index = index -1
43
+ # end
44
+ # index = index + 1 # take next
45
+ #
46
+ # # and add to the layers
47
+ # if index == @layerOfComponents.size
48
+ # @layerOfComponents[index] = []
49
+ # end
50
+ # @layerOfComponents[index] << component
51
+ #
52
+ # puts "added #{component}"
53
+ # cycle = false
54
+ # break
55
+ # end
56
+ #
57
+ # end
58
+ #
59
+ # if cycle
60
+ # warn "cycle in #{components.join(', ')}, can't continue with layering"
61
+ # break
62
+ # end
63
+ # end
64
+ #
65
+ # 5) output the found layering
66
+ # (1..@layerOfComponents.size).each do |i|
67
+ # layer = @layerOfComponents[i-1].sort
68
+ # puts "#{i} " + layer.join(', ')
69
+ # end
70
+ #