I had the need to get an overview of the differences between 2 jar files, so I created a simple Ruby script that simply wraps the output of jar, javap, and diff (I’m using Cygwin diff on WinXP).
Here’s jardiff.rb:
#! /usr/bin/ruby
if ARGV.size !=2
puts “USAGE: ruby jardiff.rb “
puts “\nNOTE: ‘diff’ command must be on the path and JAVA_HOME environment variable must point to a valid JDK install”
exit
end
# —————————————————————————–
# check arguments
jar1=ARGV[0].tr(“\\”,“/”)
if (!File.exists? jar1)
print “#{jar1} can’t be found”
exit
end
jar2=ARGV[1].tr(“\\”,“/”)
if (!File.exists? jar2)
print “#{jar2} can’t be found”
exit
end
# —————————————————————————–
# constants, exec commands : customize, if you wish
WIDTH=100
JAVA_HOME=ENV["JAVA_HOME"].tr(“\\”,“/”)
JAR_CMD=“#{JAVA_HOME}/bin/jar tf”
JAVAP_CMD=“#{JAVA_HOME}/bin/javap -public”
# diff currently assumed to be on the path
DIFF_CMD=“diff -wBW #{WIDTH}”
HR=“=”*WIDTH
# —————————————————————————–
require “Tempfile”
# Utility functions
# wrapper around diff
def filediff(f1, f2)
#print “filediff #{f1} #{f2}\n”
`#{DIFF_CMD} #{f1} #{f2}`
end
# wrapper around jar tf
def get_jar_classes (jar_file)
`#{JAR_CMD} #{jar_file}`.reject { |v| !v.match(/\.class$/) }.collect { |v| v.strip.tr(“/”,“.”).sub(“.class”, “”) }.sort
end
# wrapper around javap
def javap(jar_file,class_name)
`#{JAVAP_CMD} -classpath #{jar_file} #{class_name}`
end
# wrapper around Tempfile : returns tempfile or block value
# ? don’t know why Tempfile.open doesn’t return the block value
def tmpfile()
result = tf = Tempfile.new(“jardiff”)
if block_given?
begin
result = yield tf
ensure
tf.close unless tf.nil?
end
end
result
end
# —————————————————————————–
print “Comparing classes in #{jar1} with those in #{jar2}\n”
# examine the jar files, pull out a list of class names from each
classes1 = get_jar_classes jar1
classes2 = get_jar_classes jar2
f1 = tmpfile() { |f| f.puts(classes1.join(“\n”)); f.path }
f2 = tmpfile() { |f| f.puts(classes2.join(“\n”)); f.path }
diff = filediff(f1, f2)
if (diff.strip.length > 0)
print “#{HR}\n#{”*** Differences ***“.center(WIDTH)}\n#{diff}#{HR}\n”
end
# —————————————————————————–
same_list = (classes1&classes2).sort
print “Comparing method signatures for #{same_list.size} classes\n”
# diff each class that occurs in both jars
same_list.each do |cn|
f1 = tmpfile() { |f| f.puts javap(jar1, cn); f.path }
f2 = tmpfile() { |f| f.puts javap(jar2, cn); f.path }
diff = filediff(f1, f2)
if (diff.strip.length > 0)
print “#{HR}\n#{”*** Differences in #{cn} ***”.center(WIDTH)}\n#{diff}#{HR}\n”
end
end
# —————————————————————————–