 |
Java APIs comparison
Posted by cos on March 28, 2006 at 09:57 PM | Comments (9)
Hello folks
We recently thought about an interesting approach of finding a
difference between APIs (public methods) of two versions of a Java
software. I was doing it for JDK1.5
(Tiger) and JDK1.6 (Mustang b76).
Sometime you might want to take a quick look and find out what exactly
has been changed in your (or somebody's else code) between two
versions. Why? Well, if you want to focus your test development on the
new API only it might be a very sound idea. I'd spoke about
some of other methods to help you to achieve
better software quality
Well, there are some methods to do so. E.g. you can use "Since" tags
from a Javadoc Well, good if you have any...
Or you can store your product API's snapshot like RefactorIt does. Boy, what if you didn't create this snapshot in a first
place and now you badly need one? "Sorry partner - no can do for ya..."
Anyways, the idea was on the surface as usual:
In one way or another
build a list of all public (protected/private/static/etc.) methods in
your software. You can use grep or javap
along with grep for these purposes. Don't forget to do this for both
versions of your application - it's about the difference, right? :-)
Now, you have these API lists, you just need to compare them. And again
it's up to you: you can use Unix diff command, Emacs ediff, or
vimdiff. I'd wrote that self-explanatory Perl script (feel free to
modify it, criticize it, or merely throw it away). Fix &open_file()'s loop if your API lists weren't created in the form of "filename:method signature" per line...
#!/usr/bin/perl
if ($#ARGV != 1) {
print "Please supply two lists of APIs you want to compare\n";
exit 1;
}
my %diff = ();
my $left = &open_file ($ARGV[0]); #Presumably, the earlier version
my $right = &open_file ($ARGV[1]); #Presumably, the latest version
foreach $file (keys %$right) {
if (!exists $left->{$file}) {
$diff{$file} = \@{ $right->{$file} } ;
} else {
@l_stuff = @{ $left->{$file} };
@r_stuff = @{ $right->{$file} };
foreach $r ( @r_stuff ) {
if (&is_there($r, @l_stuff) != 1) {
push @{ $diff{$file}}, $r;
}
}
}
}
foreach $d (keys %diff) {
@extract = @{ $diff{$d} };
print "$d\n @extract\n";
}
#=========== Some subs
sub is_there () {
my ($search, @list) = @_;
for (@list) {
return 1 if $_ eq $search;
}
return 0;
}
sub open_file () {
local ($name) = @_;
open FILE, $name or
die "Can't open specified file!$name\n";
my %ret = ();
while () {
($key, $value) = split(':', $_);
push @{ $ret{$key} }, $value;
}
return \%ret;
}
Of course, there's always an expert opinion. Or you can ask an author of an application, or eye-roll it yourself. But isn't that much simpler to load your computer with the stuff it can do better then a human being?
So, I'll let you to carry on from here...
CU,
Cos
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
cos, this is so inefficient. :-)
Sun's very own FAQ on JavaDoc has link to JDiff doclet that can compare two API's and produce nice diff report. Here is diff between JRE 1.4 and 1.5 API.
Posted by: euxx on March 28, 2006 at 10:32 PM
-
"Self-explanatory" and "Perl script"... Only 10 kinds of people in the world, those that use them in the same sentence and those that don't :)
Posted by: kirillcool on March 28, 2006 at 11:46 PM
-
Konstantin, at Kaffe & GNU Classpath we use Stuart Ballards excellent japitools[1] to keep track of APIs and their differences between revisions, and in particular to keep track of how far from complete J2SE 1.5 API coverage we are.[2] It can generate text or html output, etc. I hope it works as well for you as it does for us.
cheers,
dalibor topic
[1] japitools
[2] its output
Posted by: robilad on March 29, 2006 at 03:03 AM
-
Hey Euxx.
Actually, having HTML report is good and convenient, but plain text
has its own advantages. Although, I wasn't aware about jDiff - seems
to be cool thing. Thanks. And BTW, you didn't call me when you were in SF :-(
Posted by: cos on March 29, 2006 at 01:36 PM
-
Kirill,
what kind of people you are belonging too? :-)
Cos
Posted by: cos on March 29, 2006 at 01:36 PM
-
Robilad,
it sounds very interesting. I wish I knew about it before. BTW, how do you guys measure coverage? What tools you're using, etc.? Please feel free to frop me a note either here or to Konstantin.Boudnik@sun.com
Thank,
Cos
Posted by: cos on March 29, 2006 at 01:41 PM
-
Hi Cos. My bad. I was completely swamped at work. Hope to fix it during next visit to SF.
Posted by: euxx on March 31, 2006 at 01:27 PM
-
Heya, I looked around a bit, since I haven't tried to integrate a test coverage tool with our free software test suite[1], Mauve, and while EMMA & Cobertura work fine on Kaffe, it seems to be pretty tricky to get them to work well with "instrumented" core class libraries for coverage, since they rely on the standard class libraries themselves to store/output coverage information. I guess that's something that could be worked around by playing tricks with class-loaders though I have not really investigated it yet. If you have some ideas, shoot me an e-mail at robilad@kaffe.org.
cheers,
dalibor topic
[1] http://sources.redhat.com/mauve/
Posted by: robilad on April 04, 2006 at 10:49 AM
-
Hi. I found this one very useful at times:jarjardiff compares different versions of the same JAR, i.e. the classes inside the JAR's.
It is part of the Dependency Finder project, which includes another tool to render the results in HTML.
Here is how little code to add to your utility buildfile, if you just want to drop earlier versions of JARs into subfolder first and the newer ones into subfolder other to have a go:
<property file="dependencyfindertasks.properties"/>
<property file="log4j.properties"/>
<path id="dependencyfinder">
<pathelement location="${dependencyfinder.home}/classes"/>
<pathelement location="${dependencyfinder.home}/lib/DependencyFinder.jar"/>
<pathelement location="${dependencyfinder.home}/lib/jakarta-oro.jar"/>
<pathelement location="${dependencyfinder.home}/lib/log4j.jar"/>
</path>
<taskdef resource="dependencyfindertasks.properties">
<classpath refid="dependencyfinder"/>
</taskdef>
<target name="diff">
<jarjardiff destfile="result/diff.xml"
name="jardiff"
oldlabel="first"
newlabel="other">
<old>
<fileset dir="first">
<include name="**/*.jar"/>
</fileset>
</old>
<new>
<fileset dir="other">
<include name="**/*.jar"/>
</fileset>
</new>
</jarjardiff>
<xslt style="DiffToHTML.xsl"
in="result/diff.xml"
out="result/diff.html"/>
</target>
Posted by: jbuchberger on April 06, 2006 at 01:32 AM
|