diff -Nru japitools-0.9.7/bin/japizejdks japitools-0.9.7+git20150619/bin/japizejdks --- japitools-0.9.7/bin/japizejdks 2005-09-11 22:35:44.000000000 +0000 +++ japitools-0.9.7+git20150619/bin/japizejdks 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -#!/bin/bash -# This is very obviously tuned to run on my system, but I'm including it in -# the japitools tarball because it's useful for showing exactly how to generate -# japi files for each JDK version. Feel free to modify it to take the paths etc -# as arguments so people other than me can run it directly... - -cd /home/sballard/public_html/japi/htmlout - -JAPIDIR=/home/sballard/japi - -JDK15DIR=/usr/lib/j2sdk1.5-sun -JDK14DIR=/usr/local/j2sdk1.4.1 -JDK13DIR=/usr/lib/j2se/1.3 -JDK12DIR=/usr/local/jdk1.2.2 -JDK11DIR=/usr/lib/jdk/1.1 -JDK10DIR=/usr/local/jdk1.0 - -JDK15ARGS="+java +javax +org -java.awt.dnd.peer -java.awt.peer -org.apache -org.w3c.dom.css -org.w3c.dom.events -org.w3c.dom.html -org.w3c.dom.stylesheets -org.w3c.dom.traversal -org.w3c.dom.views -java.text.resources -org.omg.stub.javax -org.omg.dom.ranges" -JDK14ARGS="+java +javax +org -java.awt.dnd.peer -java.awt.peer -org.apache -org.w3c.dom.css -org.w3c.dom.events -org.w3c.dom.html -org.w3c.dom.stylesheets -org.w3c.dom.traversal -org.w3c.dom.views -java.text.resources" -JDK13ARGS="$JDK14ARGS" -JDK12ARGS="$JDK13ARGS" -JDK11ARGS="+java -java.awt.peer -java.text.resources" -JDK10ARGS="+java -java.lang,UNIXProcess" - -japize=$JAPIDIR/bin/japize - -for n in jdk10 jdk11 jdk12 jdk13 jdk14 jdk15; do mv $n.japi.gz $n.bak.japi.gz; done - -echo -n "Japizing jdk15" -$japize as jdk15 packages $JDK15DIR/jre/lib/{rt,jce,jsse}.jar $JDK15ARGS -echo -n "Japizing jdk14" -$japize as jdk14 packages $JDK14DIR/jre/lib/{rt,jce,jsse}.jar $JDK14ARGS -echo -n "Japizing jdk13" -$japize as jdk13 packages $JDK13DIR/jre/lib/rt.jar $JDK13ARGS -echo -n "Japizing jdk12" -$japize as jdk12 packages $JDK12DIR/jre/lib/rt.jar $JDK12ARGS -echo -n "Japizing jdk11" -$japize as jdk11 packages $JDK11DIR/lib/classes.zip $JDK11ARGS -echo -n "Japizing jdk10" -$japize as jdk10 packages $JDK10DIR/lib/classes.zip $JDK10ARGS -echo "Finished japizing." - -tar cvf ../jdkjapis.tar jdk1?.japi.gz diff -Nru japitools-0.9.7/ChangeLog japitools-0.9.7+git20150619/ChangeLog --- japitools-0.9.7/ChangeLog 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/ChangeLog 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,27 @@ +2015-06-09 Andrew John Hughes + + * src/net/wuffies/japi/ClassFile.java: + (CONSTANT_MethodHandle): Added. + (CONSTANT_MethodType): Likewise. + (CONSTANT_InvokeDynamic): Likewise. + (MethodHandleConstantPoolItem): Added inner + class for new constant pool item in Java 8. + (MethodHandleConstantPoolItem.MethodHandleConstantPoolItem(int,int)): + Likewise. + (MethodTypeConstantPoolItem): Likewise. + (MethodTypeConstantPoolItem.MethodTypeConstantPoolItem(int)): Likewise. + (InvokeDynamicConstantPoolItem): Likewise. + (InvokeDynamicConstantPoolItem.InvokeDynamicConstantPoolItem(int,int)): + Likewise. + (ClassFile(buf[])): Handle cases for CONSTANT_MethodHandle, + CONSTANT_MethodType and CONSTANT_InvokeDynamic so Java 8 + class files can be parsed. + (ClassPathEntry.load(String)): Declare as throwing + IOException. + (JarClassPathEntry.load(String)): Throw IOException rather + than suppressing it. + (JarClassPathEntry.toString()): Implemented to return the + name of the zip file. + (DirClassPathEntry.forName(String)): Handle IOException + and attach it as the cause of the RuntimeException. + Throw an IllegalStateException if the class is not found. diff -Nru japitools-0.9.7/.cvsignore japitools-0.9.7+git20150619/.cvsignore --- japitools-0.9.7/.cvsignore 2006-03-31 16:42:30.000000000 +0000 +++ japitools-0.9.7+git20150619/.cvsignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -*.jar -*.class -net -build -share diff -Nru japitools-0.9.7/debian/changelog japitools-0.9.7+git20150619/debian/changelog --- japitools-0.9.7/debian/changelog 2021-01-06 18:43:17.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/changelog 2021-01-18 11:43:03.000000000 +0000 @@ -1,9 +1,15 @@ -japitools (0.9.7-1.1) unstable; urgency=medium +japitools (0.9.7+git20150619-1) unstable; urgency=medium - * Non maintainer upload by the Reproducible Builds team. - * No source change upload to rebuild on buildd with .buildinfo files. + * New upstream release + * Removed Michael Koch from the uploaders (Closes: #654027, #884611) + * Switched the source to the Andrew John Hughes' fork + * Build with the DH sequencer instead of CDBS + * Moved the package to Git + * Standards-Version updated to 4.5.1 + * Switch to debhelper level 13 + * Converted debian/copyright to the Copyright Format 1.0 - -- Holger Levsen Wed, 06 Jan 2021 19:43:17 +0100 + -- Emmanuel Bourg Mon, 18 Jan 2021 12:43:03 +0100 japitools (0.9.7-1) unstable; urgency=low diff -Nru japitools-0.9.7/debian/compat japitools-0.9.7+git20150619/debian/compat --- japitools-0.9.7/debian/compat 2010-08-03 10:28:53.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -7 diff -Nru japitools-0.9.7/debian/control japitools-0.9.7+git20150619/debian/control --- japitools-0.9.7/debian/control 2010-08-03 10:32:12.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/control 2021-01-18 11:40:34.000000000 +0000 @@ -2,13 +2,15 @@ Section: devel Priority: optional Maintainer: Debian Java Maintainers -Uploaders: Michael Koch -Build-Depends: debhelper (>= 7), cdbs, ant, default-jdk -Standards-Version: 3.9.1 -Vcs-Svn: svn://svn.debian.org/svn/pkg-java/trunk/japitools -Vcs-Browser: http://svn.debian.org/wsvn/pkg-java/trunk/japitools -Homepage: http://savannah.nongnu.org/projects/japitools/ - +Uploaders: Emmanuel Bourg +Build-Depends: + ant, + debhelper-compat (= 13), + default-jdk +Standards-Version: 4.5.1 +Vcs-Git: https://salsa.debian.org/java-team/japitools.git +Vcs-Browser: https://salsa.debian.org/java-team/japitools +Homepage: https://github.com/gnu-andrew/japitools Package: japitools Architecture: all @@ -19,7 +21,7 @@ of Java itself for compatibility with Sun's JDK, but they can also be used for testing backward compatibility between versions of any API. . - The tools are japize and japicompat. Japize is a Java program which emits + The tools are japize and japicompat. Japize is a Java program which emits a listing of an API in a machine-readable format. Japicompat then takes two such listings and compares them for binary compatibility, as defined by Sun in the Java Language Specification. diff -Nru japitools-0.9.7/debian/copyright japitools-0.9.7+git20150619/debian/copyright --- japitools-0.9.7/debian/copyright 2010-08-03 10:28:53.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/copyright 2021-01-18 11:40:34.000000000 +0000 @@ -1,25 +1,20 @@ -This package was debianized by Wolfgang Baer on -Thu, 6 Oct 2005 15:52:05 +0200. - -It was downloaded from - -Copyright: (c) 2004-2009 Stuart Ballard - Jeroen Frijters - -License: - - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 dated June, 1991. - - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this package; if not, write to the Free Software Foundation, - Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - -On Debian systems, the complete text of the GNU General -Public License can be found in `/usr/share/common-licenses/GPL-2'. +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: japitools +Source: https://github.com/gnu-andrew/japitools + +Files: * +Copyright: 1989-1991, Free Software Foundation, Inc + 2006, Jaroslav Tulach + 2004, Jeroen Frijters + 2000-2006, Stuart Ballard +License: GPL-2+ + +Files: debian/* +Copyright: 2005-2006, Wolfgang Baer + 2009, Michael Koch + 2010-2011, Niels Thykier +License: GPL-2+ + +License: GPL-2+ + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-2'. diff -Nru japitools-0.9.7/debian/dirs japitools-0.9.7+git20150619/debian/dirs --- japitools-0.9.7/debian/dirs 2010-08-03 10:28:53.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/dirs 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -usr/bin -usr/share/java diff -Nru japitools-0.9.7/debian/docs japitools-0.9.7+git20150619/debian/docs --- japitools-0.9.7/debian/docs 2011-02-06 16:16:12.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/docs 2021-01-18 11:40:34.000000000 +0000 @@ -1,4 +1,4 @@ +debian/index.html design/genericnotes.txt design/japi-spec-0.9.7.txt design/japi.css -debian/index.html diff -Nru japitools-0.9.7/debian/japitools.install japitools-0.9.7+git20150619/debian/japitools.install --- japitools-0.9.7/debian/japitools.install 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/japitools.install 2021-01-18 11:40:34.000000000 +0000 @@ -0,0 +1,6 @@ +share/java/japitools.jar /usr/share/java/ +bin/japicompat /usr/bin/ +bin/japilist /usr/bin/ +bin/japiohtml /usr/bin/ +bin/japiotext /usr/bin/ +bin/japize /usr/bin/ diff -Nru japitools-0.9.7/debian/manpages japitools-0.9.7+git20150619/debian/manpages --- japitools-0.9.7/debian/manpages 2010-08-03 10:28:53.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/manpages 2021-01-18 11:40:34.000000000 +0000 @@ -1,5 +1,5 @@ debian/japicompat.1 -debian/japize.1 -debian/japiotext.1 -debian/japiohtml.1 debian/japilist.1 +debian/japiohtml.1 +debian/japiotext.1 +debian/japize.1 diff -Nru japitools-0.9.7/debian/rules japitools-0.9.7+git20150619/debian/rules --- japitools-0.9.7/debian/rules 2010-09-02 07:31:38.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/rules 2021-01-18 11:40:34.000000000 +0000 @@ -1,21 +1,4 @@ #!/usr/bin/make -f -# debian/rules file for japitools (uses cdbs) -include /usr/share/cdbs/1/rules/debhelper.mk -include /usr/share/cdbs/1/class/ant.mk - -export UPSTREAM_VERSION = $(shell head -1 debian/changelog | cut -f2 -d\( | cut -f1 -d\) | cut -f1 -d\-) - -JAVA_HOME := /usr/lib/jvm/default-java - -DEB_JARS := $(ANT_HOME)/lib/ant-launcher.jar - -DEB_ANT_BUILD_TARGET := main - -install/japitools:: - install -m 644 share/java/japitools.jar debian/japitools/usr/share/java/japitools.jar - install -m755 bin/japicompat debian/japitools/usr/bin/japicompat - install -m755 bin/japilist debian/japitools/usr/bin/japilist - install -m755 bin/japiohtml debian/japitools/usr/bin/japiohtml - install -m755 bin/japiotext debian/japitools/usr/bin/japiotext - install -m755 bin/japize debian/japitools/usr/bin/japize +%: + dh $@ --buildsystem=ant diff -Nru japitools-0.9.7/debian/watch japitools-0.9.7+git20150619/debian/watch --- japitools-0.9.7/debian/watch 2010-08-03 10:28:53.000000000 +0000 +++ japitools-0.9.7+git20150619/debian/watch 2021-01-18 11:40:34.000000000 +0000 @@ -1,2 +1,3 @@ -version=3 -http://sab39.netreach.com/Software/Japitools/Download/43/ .*/japitools-([\d.]+)\.tar\.gz +version=4 +opts="mode=git,repack,compression=xz,pretty=0.9.7+git%cd" \ +https://github.com/gnu-andrew/japitools HEAD diff -Nru japitools-0.9.7/example-scripts/japinightly japitools-0.9.7+git20150619/example-scripts/japinightly --- japitools-0.9.7/example-scripts/japinightly 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/example-scripts/japinightly 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,153 @@ +#!/bin/bash + +# Modify these lines to provide a list of VMs to test, a technique to obtain a +# japi file for each VM, and a list of JDK versions to test against. The last +# listed JDK will be tested bidirectionally. +TESTEES="classpath classpath-generics harmony" +JDKS="jdk10 jdk11 jdk12 jdk13 jdk14 jdk15" +BETAJDKS="jdk6 jdk7" +WORKDIR=/home/sballard/japiout/cvs +JAPIDIR=/home/sballard/japicvs/japitools +JAPIZEJDKS=true +JAPIZEBETAS=true +GENIGNORE=true +MAILDIFFS=true + +# Q should be either nothing or "-q". Currently we just assume that the user +# knows about the use of -q to make the script quiet, and doesn't specify +# anything else (if they do, things will go wrong). +Q=$1 +#set -e +export CVS_RSH=ssh + +cd $JAPIDIR +cvs update -dP +chmod +x $JAPIDIR/bin/japicompat +chmod +x $JAPIDIR/bin/japize +chmod +x $JAPIDIR/bin/japiotext +chmod +x $JAPIDIR/bin/japiohtml +ant -Dbuild.compiler=jikes +cd $WORKDIR + +function uploadem() { + if [ "$FILESTOCOPY" != "" ]; then + if [ "$Q" = "" ]; then + echo "Uploading files: $FILESTOCOPY" + fi + scp $Q $FILESTOCOPY stuart@kaffe.org:public_html/japi/htmlout + FILESTOCOPY= + fi +} +FILESTOCOPY= + +function docompare() { + orig="$1" + new="$2" + diffsto="$3" + extra="$4" + + $JAPIDIR/bin/japicompat $Q -jvo j-$orig-$new.japio $extra $orig.japi.gz $new.japi.gz + if [ -f t-$orig-$new.txt ]; then mv t-$orig-$new.txt t-$orig-$new-last.txt; fi + $JAPIDIR/bin/japiotext t-$orig-$new.txt + $JAPIDIR/bin/japiohtml h-$orig-$new.html + if [ -f t-$orig-$new-last.txt ]; then + diff -u t-$orig-$new{-last,}.txt | grep '^[+-]' | grep -v '^+++' | grep -v '^---' > diff-$orig-$new.txt + if [ `grep -v 'Comparison run at' diff-$orig-$new.txt | + grep -v 'API scanned at' | + wc -l` == 0 ]; then + rm diff-$orig-$new.txt + else + (echo -e "Japi diff $orig vs $new:\nFull results:\nhttp://www.kaffe.org/~stuart/japi/htmlout/h-$orig-$new.html\n\nChanges since last run:\n"; + cat diff-$orig-$new.txt; + echo -e "\n") >> $diffsto.diffs.txt + fi + fi + + FILESTOCOPY="$FILESTOCOPY h-$orig-$new.html" +} + +# Regenerate the JDK japis in case there are file format changes in CVS +if $JAPIZEJDKS; then + /home/sballard/bin/japizejdkscvs + FILESTOCOPY="$FILESTOCOPY jdkjapis.tar" +fi +if $JAPIZEBETAS; then + /home/sballard/bin/grabjdk6 + /home/sballard/bin/grabjdk6 7 + FILESTOCOPY="$FILESTOCOPY jdk6.japi.gz jdk7.japi.gz jdk6.crapi.txt jdk7.crapi.txt" +fi + +# Simple trick for getting the last out of a list: set a variable to each one +# in turn, and at the end of the loop it's set to the last one. +for n in $JDKS; do + LASTJDK=$n +done + +# Generate ignore files +if $GENIGNORE; then + prev="" + for n in $JDKS $BETAJDKS; do + for m in $JDKS $BETAJDKS; do + if [ $n '<' $m ]; then + $JAPIDIR/bin/japicompat $Q -jvo j-$n-$m.japio $n.japi.gz $m.japi.gz + $JAPIDIR/bin/japiohtml h-$n-$m.html + FILESTOCOPY="$FILESTOCOPY h-$n-$m.html" + fi + done + if [ -n "$prev" ]; then + $JAPIDIR/bin/japicompat $Q -hvo h-$n-$prev.html $n.japi.gz $prev.japi.gz + FILESTOCOPY="$FILESTOCOPY h-$n-$prev.html" + fi + prev=$n + done +fi + +uploadem + +# Loop over the VMs being tested. +for m in $TESTEES; do + if [ -f $m.diffs.txt ]; then rm $m.diffs.txt; fi + if [ -f $m.japi.gz ]; then mv $m.japi.gz $m.japi.gz.last; fi + ~/bin/japize$m "$Q" + FILESTOCOPY="$FILESTOCOPY $m.japi.gz" + + # Compare against each JDK. + for n in $JDKS; do + if [ $n != $LASTJDK ]; then + IGNFILE="-i " + for o in $JDKS; do + if [ $n '<' $o ]; then + IGNFILE="${IGNFILE}j-$n-$o.japio," + fi + done + IGNFILE="${IGNFILE:0:${#IGNFILE}-1}" + else + IGNFILE="" + fi + + docompare $n $m $m "$IGNFILE" + done + + # Compare in reverse against the LASTJDK. + docompare $m $LASTJDK $m "-p" + + # Compare against beta JDKs + for n in $BETAJDKS; do + docompare $n $m $m + docompare $m $n $m "-p" + done + + # Mail the report + if $MAILDIFFS; then + if [ "$m" = "harmony" ]; then + ADDR=commits@harmony.apache.org + else + ADDR=classpath-testresults@gnu.org + fi + if [ -f $m.diffs.txt ]; then + ssh stuart@kaffe.org mail -s "\"Japi diffs for $m\"" stuart.a.ballard@gmail.com japitools-results@nongnu.org $ADDR < $m.diffs.txt + fi + fi + uploadem +done + diff -Nru japitools-0.9.7/example-scripts/japizejdkbeta japitools-0.9.7+git20150619/example-scripts/japizejdkbeta --- japitools-0.9.7/example-scripts/japizejdkbeta 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/example-scripts/japizejdkbeta 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,27 @@ +#!/bin/bash + +N=$1 +if [ -z "$1" ]; then N=6; fi + +JDK=jdk$N +JDKV=jdk1.$N.0 +GRAB=true + +if $GRAB; then + if [ -d "$HOME/defunct/$JDK" ]; then rm -rf "$HOME/defunct/$JDK"; fi + mkdir "$HOME/defunct/$JDK" + cd "$HOME/defunct/$JDK" + wget -O $JDK.zip `wget -O- -q http://download.java.net/$JDK/binaries/ | perl -ne 'print "$1\n" if / $JDK.pkgs +$HOME/japicvs/japitools/bin/japize as $JDK lint $JDK.crapi.txt packages *.jar @$JDK.pkgs -javax.swing:serial +mv $JDK.crapi.txt $JDK.japi.gz $JDK.pkgs "$HOME/japiout/cvs" +cd $HOME +rm -rf "$HOME/defunct/$JDK" diff -Nru japitools-0.9.7/example-scripts/japizejdks japitools-0.9.7+git20150619/example-scripts/japizejdks --- japitools-0.9.7/example-scripts/japizejdks 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/example-scripts/japizejdks 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,24 @@ +#!/bin/bash + +cd /home/sballard/japiout/cvs + +JAPIDIR=/home/sballard/japicvs/japitools +JDKJARSDIR=/home/sballard/jdkjars + +japize=$JAPIDIR/bin/japize + +for n in jdk10 jdk11; do + if [ -f $n.japi.gz ]; then mv $n.japi.gz $n.bak.japi.gz; fi + + echo -n "Japizing $n" + $japize as $n lint $n.crapi.txt packages $JDKJARSDIR/$n/classes.zip @$n.pkgs +done +for n in jdk12 jdk13 jdk14 jdk15; do + if [ -f $n.japi.gz ]; then mv $n.japi.gz $n.bak.japi.gz; fi + + echo -n "Japizing $n" + $japize as $n lint $n.crapi.txt packages $JDKJARSDIR/$n/*.jar @$n.pkgs -javax.swing:serial +done +echo "Finished japizing." + +tar cvf jdkjapis.tar jdk1?.japi.gz diff -Nru japitools-0.9.7/.gitignore japitools-0.9.7+git20150619/.gitignore --- japitools-0.9.7/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/.gitignore 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,5 @@ +*.jar +*.class +net +build +share diff -Nru japitools-0.9.7/src/net/wuffies/japi/ClassFile.java japitools-0.9.7+git20150619/src/net/wuffies/japi/ClassFile.java --- japitools-0.9.7/src/net/wuffies/japi/ClassFile.java 2006-11-13 16:48:54.000000000 +0000 +++ japitools-0.9.7+git20150619/src/net/wuffies/japi/ClassFile.java 2015-06-19 14:59:39.000000000 +0000 @@ -1,6 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // Japize - Output a machine-readable description of a Java API. // Copyright (C) 2004 Jeroen Frijters +// Copyright (C) 2015 Andrew John Hughes // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -44,6 +45,9 @@ private static final int CONSTANT_Double = 6; private static final int CONSTANT_NameAndType = 12; private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_MethodHandle = 15; + private static final int CONSTANT_MethodType = 16; + private static final int CONSTANT_InvokeDynamic = 18; private DataInputStream todo; private ConstantPoolItem[] constant_pool; @@ -61,6 +65,7 @@ private ClassType superclassType; private ClassType[] interfaceTypes; private GenericWrapper containingWrapper; + private ClassFile declaringClass; private class ConstantPoolItem { @@ -189,6 +194,41 @@ } } + private class MethodHandleConstantPoolItem extends ConstantPoolItem + { + int reference_kind; + int reference_index; + + MethodHandleConstantPoolItem(int reference_kind, int reference_index) + { + this.reference_kind = reference_kind; + this.reference_index = reference_index; + } + } + + private class MethodTypeConstantPoolItem extends ConstantPoolItem + { + int descriptor_index; + + MethodTypeConstantPoolItem(int descriptor_index) + { + this.descriptor_index = descriptor_index; + } + } + + private class InvokeDynamicConstantPoolItem extends ConstantPoolItem + { + int bootstrap_method_attr_index; + int name_and_type_index; + + InvokeDynamicConstantPoolItem(int boostrap_method_attr_index, + int name_and_type_index) + { + this.bootstrap_method_attr_index = bootstrap_method_attr_index; + this.name_and_type_index = name_and_type_index; + } + } + private abstract class FMInfoItem implements Wrapper { int access_flags; @@ -369,6 +409,32 @@ i = sig.indexOf(';', i); l.add(Type.fromNonGenericSig(sig.substring(start, i + 1))); } + // The first parameter of a nonstatic inner class constructor is the enclosing + // instance, rather than a real parameter. Identify this case and skip it. + // Note: this doesn't handle anonymous classes which are scoped to a method since + // getContainingWrapper() isn't a ClassWrapper in that case; these are handled + // wrong but they are never public, so they never show up in japi files, so + // having an incorrect view of their constructor parameters is irrelevant. + if ("".equals(getName()) && + !Modifier.isStatic(ClassFile.this.getModifiers()) && + ClassFile.this.getContainingWrapper() != null && + ClassFile.this.getContainingWrapper() instanceof ClassWrapper) + { + // As far as I can tell all the things I check here are required by the JLS so + // I just throw if they're violated. + if (l.size() == 0) + throw new RuntimeException("Nonstatic inner class " + ClassFile.this.getName() + " constructor has no parameters!"); + + if (!(l.get(0) instanceof ClassType)) + throw new RuntimeException("First parameter of nonstatic inner class " + ClassFile.this.getName() + " constructor is not a class type"); + + ClassType t = (ClassType) l.get(0); + ClassWrapper cw = (ClassWrapper) ClassFile.this.getContainingWrapper(); + if (!t.getName().equals(cw.getName())) + throw new RuntimeException("First parameter of nonstatic inner class " + ClassFile.this.getName() + " constructor is " + t.getName() + ", not " + cw.getName()); + + l.remove(0); + } parameterTypes = new Type[l.size()]; l.toArray(parameterTypes); } @@ -413,35 +479,6 @@ public Type[] getParameterTypes() { - // The first parameter of a nonstatic inner class constructor is the enclosing - // instance, rather than a real parameter. Identify this case and skip it. - // Note: this doesn't handle anonymous classes which are scoped to a method since - // getContainingWrapper() isn't a ClassWrapper in that case; these are handled - // wrong but they are never public, so they never show up in japi files, so - // having an incorrect view of their constructor parameters is irrelevant. - if ("".equals(getName()) && - !Modifier.isStatic(ClassFile.this.getModifiers()) && - ClassFile.this.getContainingWrapper() != null && - ClassFile.this.getContainingWrapper() instanceof ClassWrapper) - { - // As far as I can tell all the things I check here are required by the JLS so - // I just throw if they're violated. - if (parameterTypes.length == 0) - throw new RuntimeException("Nonstatic inner class " + ClassFile.this.getName() + " constructor has no parameters!"); - - if (!(parameterTypes[0] instanceof ClassType)) - throw new RuntimeException("First parameter of nonstatic inner class " + ClassFile.this.getName() + " constructor is not a class type"); - - ClassType t = (ClassType) parameterTypes[0]; - ClassWrapper cw = (ClassWrapper) ClassFile.this.getContainingWrapper(); - if (!t.getName().equals(cw.getName())) - throw new RuntimeException("First parameter of nonstatic inner class " + ClassFile.this.getName() + " constructor is " + t.getName() + ", not " + cw.getName()); - - List paramList = Arrays.asList(parameterTypes); - List realParamList = paramList.subList(1, parameterTypes.length); - return (Type[]) realParamList.toArray(new Type[parameterTypes.length - 1]); - } - return parameterTypes; } @@ -603,6 +640,15 @@ case CONSTANT_Utf8: constant_pool[i] = new Utf8ConstantPoolItem(in.readUTF()); break; + case CONSTANT_MethodHandle: + constant_pool[i] = new MethodHandleConstantPoolItem(in.readUnsignedByte(), in.readUnsignedShort()); + break; + case CONSTANT_MethodType: + constant_pool[i] = new MethodTypeConstantPoolItem(in.readUnsignedShort()); + break; + case CONSTANT_InvokeDynamic: + constant_pool[i] = new InvokeDynamicConstantPoolItem(in.readUnsignedShort(), in.readUnsignedShort()); + break; default: throw new IOException("unrecognized constant pool item"); } @@ -672,9 +718,13 @@ int mask = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | Modifier.STATIC; this.access_flags &= ~mask; this.access_flags |= access_flags & mask; - if(outer_class != 0 && !Modifier.isStatic(access_flags)) + if(outer_class != 0) { - containingWrapper = ClassFile.forName(getClassConstantName(outer_class)); + declaringClass = ClassFile.forName(getClassConstantName(outer_class)); + if(!Modifier.isStatic(access_flags)) + { + containingWrapper = declaringClass; + } } } } @@ -1145,9 +1195,15 @@ return ((Utf8ConstantPoolItem)constant_pool[idx]).string; } + public boolean isPublicOrProtected() + { + return (raw_access_flags & Modifier.PUBLIC) != 0; + } + public int getModifiers() { - return access_flags; + ensureParsed(); + return access_flags; } public boolean isDeprecated() @@ -1209,11 +1265,32 @@ return false; } + private static boolean gotEnum = false; + private static ClassFile enumClass = null; + + private boolean isEnumOrSubClass() + { + if (!gotEnum) + { + gotEnum = true; + try + { + enumClass = forName("java.lang.Enum"); + } + catch (RuntimeException e) { } + } + return enumClass != null && isSubTypeOf(enumClass); + } + // This code is partially based on GNU Classpath's implementation which is // (c) FSF and licensed under the GNU Library General Public License. public Long getSerialVersionUID() { ensureParsed(); + if(isEnumOrSubClass()) + { + return Long.valueOf(0L); + } for(int i = 0; i < fields.length; i++) { if(fields[i].getName().equals("serialVersionUID") && @@ -1274,6 +1351,7 @@ data_out.writeUTF(interfaces[i]); } + FieldInfoItem[] fields = (FieldInfoItem[])this.fields.clone(); Arrays.sort(fields, new Comparator() { public int compare(Object o1, Object o2) @@ -1296,7 +1374,8 @@ for (int i = 0; i < fields.length; i++) { FieldInfoItem field = fields[i]; - modifiers = field.getModifiers(); + modifiers = field.getModifiers() + & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | Modifier.TRANSIENT); if (Modifier.isPrivate (modifiers) && (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers))) @@ -1309,6 +1388,7 @@ data_out.writeUTF(field.getType().getNonGenericTypeSig()); } + MethodInfoItem[] methods = (MethodInfoItem[])this.methods.clone(); Arrays.sort(methods, new Comparator() { public int compare(Object o1, Object o2) @@ -1331,7 +1411,8 @@ for (int i = 0; i < methods.length; i++) { MethodInfoItem method = methods[i]; - modifiers = method.getModifiers(); + modifiers = method.getModifiers() + & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT); if (Modifier.isPrivate(modifiers)) { continue; @@ -1425,14 +1506,17 @@ public boolean isInterface() { - return Modifier.isInterface(access_flags); + ensureParsed(); + return Modifier.isInterface(access_flags); } public boolean isAnnotation() { - return (access_flags & 0x2000) != 0; + ensureParsed(); + return (access_flags & 0x2000) != 0; } public boolean isEnum() { + ensureParsed(); return (access_flags & 0x4000) != 0; } public GenericWrapper getContainingWrapper() @@ -1441,6 +1525,12 @@ return containingWrapper; } + public ClassWrapper getDeclaringClass() + { + ensureParsed(); + return declaringClass; + } + public ClassType[] getInterfaces() { ensureParsed(); @@ -1497,7 +1587,7 @@ private static abstract class ClassPathEntry { - abstract ClassFile load(String name); + abstract ClassFile load(String name) throws IOException; } private static class JarClassPathEntry extends ClassPathEntry @@ -1509,30 +1599,29 @@ this.zf = new ZipFile(f); } - ClassFile load(String name) + ClassFile load(String name) throws IOException { - try + ZipEntry entry = zf.getEntry(name.replace('.', '/') + ".class"); + if(entry != null) { - ZipEntry entry = zf.getEntry(name.replace('.', '/') + ".class"); - if(entry != null) + DataInputStream dis = new DataInputStream(zf.getInputStream(entry)); + try { - DataInputStream dis = new DataInputStream(zf.getInputStream(entry)); - try - { - byte[] buf = new byte[(int)entry.getSize()]; - dis.readFully(buf); - return new ClassFile(buf); - } - finally - { - dis.close(); - } + byte[] buf = new byte[(int)entry.getSize()]; + dis.readFully(buf); + return new ClassFile(buf); + } + finally + { + dis.close(); } } - catch(IOException x) - { - } - return null; + return null; + } + + public String toString() + { + return zf.getName(); } } @@ -1574,16 +1663,23 @@ ClassFile cf = (ClassFile)cache.get(name); if(cf != null) return cf; - for(int i = 0; i < classpath.length; i++) - { - cf = classpath[i].load(name); - if(cf != null) + try { - cache.put(name, cf); - return cf; + for(int i = 0; i < classpath.length; i++) + { + cf = classpath[i].load(name); + if (cf != null) + { + cache.put(name, cf); + return cf; + } + } } - } - throw new RuntimeException("NoClassDefFoundError: " + name); + catch (IOException iox) + { + throw new RuntimeException("NoClassDefFoundError: " + name, iox); + } + throw new IllegalStateException("forName(" + name + ") failed to load class"); } public static void setClasspath(String classpath) throws IOException diff -Nru japitools-0.9.7/src/net/wuffies/japi/ClassWrapper.java japitools-0.9.7+git20150619/src/net/wuffies/japi/ClassWrapper.java --- japitools-0.9.7/src/net/wuffies/japi/ClassWrapper.java 2005-11-09 01:36:01.000000000 +0000 +++ japitools-0.9.7+git20150619/src/net/wuffies/japi/ClassWrapper.java 2015-06-19 14:59:39.000000000 +0000 @@ -24,6 +24,7 @@ ClassType getSuperclass(); ClassType[] getInterfaces(); boolean isSerializable(); + ClassWrapper getDeclaringClass(); /** * Return the class's serialVersionUID, or null if a blank final @@ -45,5 +46,9 @@ * True if this class is actually an enum. */ boolean isEnum(); + /** + * True if this class is visible. + */ + boolean isPublicOrProtected(); } diff -Nru japitools-0.9.7/src/net/wuffies/japi/Japize.java japitools-0.9.7+git20150619/src/net/wuffies/japi/Japize.java --- japitools-0.9.7/src/net/wuffies/japi/Japize.java 2006-11-14 03:02:18.000000000 +0000 +++ japitools-0.9.7+git20150619/src/net/wuffies/japi/Japize.java 2015-06-19 14:59:39.000000000 +0000 @@ -748,8 +748,7 @@ ClassWrapper c = getClassWrapper(n); // Load the class and check its accessibility. - int mods = c.getModifiers(); - if (!Modifier.isPublic(mods) && !Modifier.isProtected(mods)) { + if (!isEntirelyVisible(c)) { progress('-'); return false; } @@ -769,12 +768,19 @@ } type += getTypeParamStr(c); - + + int mods = c.getModifiers(); if (c.isInterface()) { mods |= Modifier.ABSTRACT; // Interfaces are abstract by definition, } else { + // Enums are considered non-abstract and final + if (c.isEnum()) { + mods |= Modifier.FINAL; + mods &= ~Modifier.ABSTRACT; + } + // Classes that happen to be Serializable get their SerialVersionUID // output as well. The separation by the '#' character from the rest // of the type string has mnemonic value for Brits, as the SVUID is a @@ -807,9 +813,6 @@ } type += mkIfaceString(c, ""); - // Skip things that aren't entirely visible as defined below. - if (!isEntirelyVisible(c)) return false; - // Print out the japi entry for the class itself. printEntry(entry, type, mods, c.isDeprecated(), false, false); @@ -1017,6 +1020,12 @@ mmods |= Modifier.FINAL; } + // Methods of enums are by definition final and non-abstract + if (c.isEnum()) { + mmods |= Modifier.FINAL; + mmods &= ~Modifier.ABSTRACT; + } + // Constructors are never final. The verifier should enforce this // so this should always be a no-op, except for when the line above // set it. @@ -1191,14 +1200,22 @@ /** * Determine whether a class is entirely visible. If it's not then it should be skipped. - * A class is entirely visible if it's public or protected, its containing - * class, if any, is entirely visible, and all the bounds of its + * A class is entirely visible if it's public or protected, its declaring + * / containing class, if any, is entirely visible, and all the bounds of its * type parameters are entirely visible. */ static boolean isEntirelyVisible(ClassWrapper cls) { - if (!Modifier.isPublic(cls.getModifiers()) && !Modifier.isProtected(cls.getModifiers())) { + if (!cls.isPublicOrProtected()) { return false; } + + // Declaring and containing class should be the same but a redundant + // check doesn't harm anything. The difference is subtle and I'm not + // 100% sure. + + ClassWrapper declaring = cls.getDeclaringClass(); + if (declaring != null && !isEntirelyVisible(declaring)) return false; + ClassWrapper containing = (ClassWrapper) cls.getContainingWrapper(); if (containing != null && !isEntirelyVisible(containing)) return false; diff -Nru japitools-0.9.7/web/index.html japitools-0.9.7+git20150619/web/index.html --- japitools-0.9.7/web/index.html 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/web/index.html 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,631 @@ +japitools: Java API compatibility testing + +

japitools: Java API compatibility testing tools

+

japitools consists of two simple tools designed to test for compatibility +between Java APIs. They were originally designed for testing free +implementations of Java itself for compatibility with Sun's JDK, but they can +also be used for testing backward compatibility between versions of any API.

+

The tools are japize +and japicompat. Japize is a Java program which +emits a listing of an API in a machine-readable +format. Japicompat then takes two such listings and compares them for binary +compatibility, as defined by Sun in the +Java Language Specification +(and as amended +here).

+

Authors

+

japitools was written primarily by +Stuart Ballard (sab39). +Contributions have been made by various people including Brian Jones, +Tom Tromey, Michael Koch and Jeroen Frijters. It incorporates part of Jode by +Jochen Hoenicke. If I forgot anyone, +let me know.

+

Results

+

(in alphabetical order to avoid arguments... ;) )

+ +

The JDK 1.5 results include comparisons of most of the aspects of the API +that use language features, but not quite all: Japitools still does not yet +understand annotations applied to classes and members.

+

A tarball of the JDK japi files used to generate this output can be +downloaded from here. These japi files were +created by running japize over the rt.jar (or equivalent) files from each +JDK release.

+

News

+
    +
  • 11 November 2004: Released japitools-0.9.5. This release has several + significant changes and fixes: +
      +
    • A much-requested feature: the ability to ignore differences when + reporting compatibility with an early API release, if those + differences are required for compatibility with a later release. See + the description of the -i flag below for more information. This new + code has been running nightly for a while producing the results + linked above, without any known problems. It reveals that the free + implementations are much closer to full coverage of 1.0 and 1.1 than + was previously apparent - in fact already perfect for 1.0 and in + Classpath's case only one method away from 1.1.
      + Thanks to Michael Koch for the key insight that enabled this feature + to finally be written, four years after I first said it was needed. +
    • +
    • A new bytecode reading implementation from Jeroen Frijters to + replace Jode. This vastly reduces the amount of code because it + only reads and understands the bits of metadata we actually need, + where Jode was part of a larger system that needed more information. + This code also fixes a "Miranda Methods" bug in the Jode + implementation.
    • +
    • Also from Jeroen: methods in final classes are now treated as + final even if they weren't explicitly marked as such.
    • +
    • Correct access modifiers on inner classes. Jeroen caught this one + and the fix was a joint effort.
    • +
    • japicompat will warn if using a japi file from an older release that + contains known bugs. That covers all versions except for this one, + in fact. Use the -w flag to disable this warning
    • +
    • Better support for launching japiotext and japiohtml on Windows + systems (some issues may remain, however).
    • +
    • The serialize and serialcompat tools have been removed (they are + now a module in the + Mauve project).
    • +
    +
  • +
  • 30 September 2004: Released japitools-0.9.4. This is a bugfix release + that addresses two issues: +
      +
    • Constant field values were frequently missed.
    • +
    • Exceptions were sometimes misreported (found and fixed by Tom + Tromey).
    • +
    + Needless to say, the world has changed a bit since I suggested that + 0.9.3 was a release candidate for 1.0. Now that Java 5 has been released, + it would be unacceptable to make a 1.0 release without support for + generics and the other new language features. Still, 0.9.4 is definitely + more stable than any previous "stable" release - this is the version + you should be using. +
  • +
  • 19 February 2003: Released japitools-0.9.3. This is a 'release candidate' + for 1.0. There are a few minor fixes over 0.9.2 including: +
      +
    • Workaround a bug that caused Japize to abort when run against + Classpath.
    • +
    • Implement toString-independent comparisons of floats and doubles, + as described below.
    • +
    • Fix a problem that caused deprecation errors to be reported only on + classes and interfaces, not members.
    • +
    • Fix an erroneous '}' that appeared in comparisons of constant + fields. Also fix some other potential problems if particular + characters appeared in constant fields.
    • +
  • +
  • 4 December 2002: Released an EXPERIMENTAL, BETA QUALITY japitools-0.9.2. + This release is more complete than 0.9.1 and includes some fixes over + version 0.9 that make it worth using even if you're not interested in + the flashy output. On the other hand, it's still less tested than 0.9 + was, so be warned. Improvements over 0.9.1 include: +
      +
    • Fix for a problem that caused inner classes to be incorrectly + treated as non-static.
    • +
    • Deprecation support (undeprecating an API is flagged as a + (minor) error).
    • +
    • Preparation for toString-independent comparisons of floats and + doubles. Since toString on these types seems to be all but + impossible to code to the spec (even Sun don't achieve it), this + allows japi files to be somewhat independent of the VM producing + them. Note that this is not yet implemented in japicompat, but + the necessary information is in the japi file so the nightly results + will be able to take advantage immediately.
    • +
    • The date of japi file creation is now included in the japi file and + presented in the output
    • +
    • Numerous fixes to the HTML output including better organization of + errors, browser compatibility fixes, and a color-legend.
    • +
    • Parallel enhancements to the text output.
    • +
    • Use -h to get HTML output, no more piping to japiohtml manually. + You can still get raw output by specifying -j. Use -o to specify + an output filename if you don't want to use shell redirection.
    • +
    • Other miscellaneous fixes.
    • +
  • +
  • 21 November 2002: Released an EXPERIMENTAL, ALPHA QUALITY japitools-0.9.1. + Japitools-0.9 is still the recommended version if you plan to do anything + important with the results. This release includes some nice new features + but also has some significant issues: +
      +
    • The documentation below has not been updated to cover this release. + Since 0.9 is still the stable version, I need to split out the + webpage with separate docs for each version. I haven't done that + yet. The only information about the differences in usage is this + list.
    • +
    • japicompat no longer gives you anything terribly comprehensible if + you save its stdout directly. Instead, you must pipe the output to + one of the new tools japiotext or japiohtml. In a future version + this will be made optional, with a pipe through japiotext as the + default, but currently it's compulsory. You can save the results + as a ".japio" file if you want to run both japiotext and japiohtml + over the same output.
    • +
    • Speaking of which, the japiohtml tool gives nice HTML output. This + is what's been generating the nightly classpath comparisons. The + output will be further cleaned up in future versions.
    • +
    • Using japiotext to get text output still doesn't provide everything + the old text output did. Neither does the HTML output.
    • +
    • The bits of Jode source code that I'm using are included directly + and get compiled into japitools.jar, so jode-1.1.1.jar is no longer + bundled. I stripped out some of the "magic" of the Jode build system + to use just .java files instead of .java.in. I also applied a + theoretical fix to Jode's problem with JDK1.4, but this is entirely + untested. If you test it, and produce a jdk14.japi.gz, please + send it to me.
    • +
  • +
  • 13 November 2002: Started a nightly script comparing classpath to various + JDK versions using new experimental (and unreleased because it's still + very crufty) HTML output. The results can be seen here: + vs JDK1.1, + vs JDK1.2, and + vs JDK1.3.
  • +
  • 5 November 2002: Released japitools-0.9, and dared to announce it on a few + mailing lists that I thought might be interested. This release only has + minor changes and cleanups over 0.8.7: +
      +
    • Japifix was missing a case in the exception-pruning algorithm + (thanks to Brian Jones for catching this).
    • +
    • Fixes to serialize from Brian Jones, including addition of the + line that actually runs it, which I somehow missed last time.
    • +
    • Print a warning from japize about the importance of using the right + filename, if "as" isn't used (thanks to Dalibor Topic for pointing + out that this isn't obvious). Updated the docs, too.
    • +
    • Cleaner separation of japicompat output between stdout and stderr, + to make it easier to redirect what you actually want. Recommended + usage is now to redirect stdout only, and use the "-q" option if + running non-interactively.
    • +
    + This release is currently considered stable and suitable for widespread + use. Barring the discovery of major problems, the next few releases will + be potentially unstable new-feature releases leading up to an eventual + 1.0.
  • +
  • 24 September 2002: Released japitools-0.8.7, which is a "release + candidate" for a hopefully stable and widely-announced 0.9. Quite a bit + new in this release: +
      +
    • Japize (and japifix) will now ignore any subclasses of Error and + RuntimeException thrown, because they're redundant. Exceptions will + also be skipped if they are subclasses of another exception thrown + by the same method, eg FileNotFoundException won't be included if + the method also throws IOException.
    • +
    • Added Ant build system (optional) provided by Brian Jones.
    • +
    • Added new tools serialize and serialcompat for testing serialization + compatibility, again thanks to Brian Jones.
    • +
    • japipkgs has evolved into japilist, which can list classes and + members, and filter results by package and class, as well as just + listing packages. Thanks again to Brian for the "japiclasses" script + that inspired this tool.
    • +
    • japifix can now detect mis-sorted files without the explicit -s + flag, by re-starting as soon as a mis-sort is detected. To make this + possible, the ability to operate on stdin has been dropped.
    • +
    • Fixed a corner-case mis-sorting bug in japize that appeared if + java.lang.something was included but java.lang itself was not.
    • +
    • japicompat flushes stdout when it's done, making the output appear + in a nice order if stdout and stderr are redirected to the same + place.
    • +
    • Added windows batch file for running japize on windows systems, + thanks (yet again :) ) to Brian Jones.
    • +
    • Added the japi file format specification + for the benefit of anyone writing code to interoperate with + japitools.
    • +
  • +
  • 18 September 2002: Released japitools-0.8.6, fixing an ordering problem + related to inner classes (serve me right for having a machine that can + only handle japizing JDK1.1, which has no inner classes). This release + also includes some cruft-removal, including the unreliable "reflect" + option and japicompat-old, and makes zipped output the default. I added + Jode to the tarball itself and restructured a bit so that japize can find + its own libraries, so you no longer need to set CLASSPATH (or download + Jode separately).
  • +
  • 10 September 2002: Released japitools-0.8.5. This fixes numerous problems + in the files produced by japize, bringing it finally back to parity with + release 0.8 or so. Japicompat will now abort on mis-ordered files, so that + errors like this will be caught quicker next time. Japi2new got a facelift + and is now called japifix. Much more testing, leading me to conclude that + japicompat is now more trustworthy than japicompat-old.
  • +
  • 31 July 2002: Released a brown-paper-bag japitools-0.8.4 with a fix for + a hang-at-end-of-file bug that showed up whenever the 'orig' file contains + packages or classes at the end of the file that aren't in the 'new' file. + Oooops!
  • +
  • 31 July 2002: Released japitools-0.8.3 with a rewritten japicompat that + uses a much faster and more scalable algorithm. Of course, being a total + rewrite, there's a risk of regressions, so the old japicompat is still + available as japicompat-old (and, in fact, includes a fix or two over the + 0.8.2 version). The other casualty of the rewrite is that although some + summary information is better, some is also worse. I hope to resurrect the + bits of what was lost that make sense. Also updated the docs below so that + they match the state of reality since 0.8.1.
  • +
  • 9 July 2002: Released japitools-0.8.2 with a fix for a NullPointer. + There's more work in progress on my laptop that isn't included in this + release because it's not ready yet, but hopefully soon there'll be a first + pass at the optimized algorithm for japicompat.
  • +
  • 28 June 2002: Released japitools-0.8.1. Noted that this obsoletes some + of the documentation on the website. Removed a bunch of old results + files that aren't correct any more. The docs will have to be updated + later - no time now.
  • +
  • 19 March 2002: Updated the website so that the documentation matches the + actual current code. Since it's been almost 2 years since I wrote this, + I can't be 100% sure that this documentation is all correct, but it's + certainly better than it was before!
  • +
  • 28 June 2000: Finally bundled japitools up into a jarball which I'm + calling version 0.8 (which is a good indicator of how close to "complete" + I feel it is). It now requires the jode.bytecode package if you want to + get good results, although you can still use the old buggy reflection + version. See below for details.
  • +
  • 18 June 2000: At the suggestion of Edouard G. Parmelan, added support + for checking SerialVersionUIDs. Since this will generally produce lots + of errors and make it harder to identify more important API compatibility + errors, it needs to be explicitly turned on in japicompat by passing the + -v flag.
  • +
  • 16 June 2000: Godmar fixed the remaining Kaffe bug, so I've removed the + hackaround. I still need to leave part of it in due to a subtlety in the + way superinterfaces are defined by the JLS. japicompat now removes + duplicates, cutting the number of Kaffe errors to 142, and checks + everything in the JLS plus my four additions. Reflection is incapable of + telling me if a field is a primitive constant, buggrit, so I have to + move to using something like gnu.bytecode.
  • +
  • 15 June 2000: Japize is now, finally, well commented. Godmar Back kindly + fixed one of the Kaffe bugs which will mean that some hackarounds can be + removed Real Soon (once another related bug gets fixed). I've been hacking + japicompat to allow duplicates to be removed; you can find the code + here [long-dead link]. It doesn't actually do the + removal yet, but the architecture is in. This will replace japicompat once + I'm convinced it's as robust; early signs look good. It's also commented! + Certify me on Advogato + - or don't, but it really is me! I need to figure how I'm going to version + japitools - right now, all the links here are to my working copies...
  • +
+ +

Installation

+

You can download japitools-0.9.5.tar.gz +here. This tarball contains a bin/ directory containing all the japi tools, a +share/ directory containing the java runtime libraries, and a src/ directory +containing all the sources in case you want to do development. It should be +unnecessary to set your CLASSPATH, since japitools can figure out the path to +its runtime libraries by relative directory structures.

+

The tarball contains code extracted from +Jode +(a jarball of which is mirrored here). +japitools is completely self-sufficient (except for perl, Java, and optionally +gzip). The tools in the bin directory assume that perl is /usr/bin/perl and that +your prefered Java runtime is "java" in your PATH. If you're working with +zipped japi files, you must also have "gzip" in your path.

+ +

Usage

+

Using japitools is a two-step process:

+
  • Use japize to generate a .japi file for each of the versions you want +to compare.
  • +
  • Use japicompat to compare one for backwards compatibility with the +other
+

japize

+

The general usage of japize is as follows:

+
$ japize [unzip] [as <name>] apis <zipfile> | <dir> ... +|-<pkgpath> ...
+

At least one +<pkgpath> is required. <name> will have +".japi" and/or ".gz" appended as appropriate.

+

The word "apis" can be replaced by "explicitly", "byname", "packages" or +"classes". These options indicate whether something of the form "a.b.C" should +be treated as a class or a package. You may specify this unambiguously by using +one of the forms "a.b.cpackage," or "a.b,CClass".

+

That's the one-paragraph overview, pretty much equivalent to what you get if +you type "japize" with no arguments. In detail, the options available are as +follows:

+

[unzip]

+

Specifying the "unzip" option indicates that japize should not gzip its +output. Zipping the output is highly +recommended since it saves huge amounts of space (japi files are +large but extremely compressable because they contain large numbers of duplicate +strings. Factor-of-ten compression seems to be typical). The only situations +where you might not want to use gzip compression are when memory and CPU usage +are extremely tight (zipping and unzipping both require more memory the larger +the file gets, and require more CPU usage - on todays computers this is rarely +an issue, though) or if your JVM does not implement GZIPOutputStream correctly +(in which case you might still want to gzip the resulting file manually).

+

as <name>

+

Specifying this option tells japize to write its output to a file with the +specified name. When writing to a file with the "as" option, japize insists on +writing to a file name ending in .japi.gz for compressed files, or .japi for +uncompressed files. If the filename you specify doesn't have the right +extension, japize will add parts to it to ensure that it does.

+

If the "as" option is omitted, japize will write to standard output. In this +case japize has no control over the filename you use, but it is strongly +recommended to use a filename with the correct extension (".japi.gz" unless the +"unzip" option was specified). If you use any other extension, japicompat and +other tools may be unable to recognize the format.

+

apis | explicitly | byname | packages | classes

+

This option has a dual role: it indicates the boundary between japize options +(unzip, as) and other arguments (files and packages), but also tells +japize how to deal with ambiguously specified arguments. See +"+|-<pkgpath>" below for details on the behavior of each option. If you +are unsure which to specify, "apis" is a safe choice.

+

<zipfile> | <dir>

+

Any arguments after "apis" that do not start with "+" or "-" are taken to be +zipfiles or directories. These should be specified exactly as you would put +them in your CLASSPATH (except separated by spaces rather than colons). Anything +that's a file will be assumed to be a zip (or jar) file, so you can't specify +a .class file directly - if you need to do that you should specify the folder +containing it and then name the class for processing.

+

+|-<pkgpath>

+

To specify which classes are included, use +pkgpath to add pkgpaths to be +scanned and -pkgpath to exclude sub-pkgpaths of these. You MUST specify at least +one +pkgpath option to specify which pkgpath to include, otherwise Japize could +happily scan through all the zipfiles and directories but not actually process +any of the classes. Since that would be a useless thing to do, japize gives an +error instead.

+

A "pkgpath" refers to either a package (which includes, by implication, all +sub-packages of it) or a single class. A pkgpath for a package looks like +"com.foo.pkg.sub," and a pkgpath for a class looks like "com.foo.pkg,Cls". The +existence and placement of the comma indicates unambiguously which type of path +is intended.

+

Most of the time, though, it's a pain to have to put in commas in names that +are familiar with dots instead, and get the comma placement exactly right. For +this reason, japize accepts pkgpaths containing only dots, and lets you tell it +what to make of those names. The interpretation of "a.b.c" as a pkgpath depends +on whether you specified apis, explicitly, byname, packages, or classes.

+
+
apis
+
a.b.c is tried both as a package and a class. This will always do + what you want (which is why apis is described as the safe default) but at + the expense of possibly doing extra unnecessary processing trying to find + the wrong thing.
+
explicitly
+
pkgpaths of the form a.b.c are illegal - you must use the explicit + form.
+
byname
+
a.b.c will be processed as a package if "c" starts with a lowercase + letter, or as a class if it starts with an uppercase one. This usually + does what you want but fails on things like org.omg.CORBA. +
packages
+
a.b.c will be processed as a package. If processing for a class is needed, + it must be specified explicitly.
+
classes
+
a.b.c will be processed as a class. If processing for a package is needed, + it must be specified explicitly.
+
+

Example

+

As an example, Sun's +JDK 1.1 includes classes in java.awt.peer and in java.text.resources that are +not part of the public API, even though they are public classes; however, every +other class in the java.* package hierarchy is part of the public API. The +syntax to construct a useful jdk11.japi.gz would therefore be:

+
$ japize as jdk11 apis classes.zip +java -java.awt.peer -java.text.resources
+

Note that since all pkgpath arguments here are packages, you could save a +small amount of processing by doing this instead:

+
$ japize as jdk11 packages classes.zip +java -java.awt.peer -java.text.resources
+

or even this:

+
$ japize as jdk11 explicitly classes.zip +java, -java.awt.peer, -java.text.resources,
+

Another example, this time doing the same thing for kaffe:

+
$ japize as kaffe packages $KAFFEHOME/share/kaffe/Klasses.jar $KAFFEHOME/share/kaffe/rmi.jar +java -java.awt.peer -java.text.resources
+

japicompat

+

Next, you can perform the test for compatibility between these two files:

+
+$ japicompat jdk11.japi.gz kaffe.japi.gz
+
+

The full list of flags supported by japicompat is as follows:

+
japicompat [-svqhtjw] [-o <outfile>] [-i <ignorefile>] <original api> <api to check>
+

The meanings of these options are as follows:

+

-s

+

By default, japicompat tests for binary compatibility as defined by the JLS, +plus a couple of additions (see below for details). You can turn off these +additions by passing the -s flag to japicompat, for example:

+
+$ japicompat -s jdk11.japi.gz kaffe.japi.gz
+
+

The s stands for "sun", "standard", "specification", or if you like more +colorful language, "single-buttocked" (one buttock=half an...). See "What exactly +does japicompat test?" below for exactly what tests get turned off by this +flag.

+ +

-v

+

By default, japicompat only checks for errors that break binary compatibility. +However, japicompat can also check for some "minor" compatibility problems. To +activate these additional checks, use the "-v" flag. The v stands for "verbose".

+
+$ japicompat -v jdk11.japi.gz kaffe.japi.gz
+
+

Specifically, the -v flag enables the following additional checks:

+
    +
  • SerialVersionUID checking: japicompat reports a minor error if a Serializable + class has a different SerialVersionUID between the two releases.
  • +
  • Deprecation checking: japicompat reports a minor error if a class or member + was deprecated in the original API but is not deprecated in the API being + checked.
  • +
+ +

-q

+

By default, japicompat provides progress reports as it runs. In unix +terminology, these are sent to stderr (the actual results are sent to +stdout unless the -o flag is used). The -q flag turns off these +progress reports - only real errors will be sent to stderr.

+ +

-h

+

Generate output in HTML format. The HTML files produced depend on the +japi.css file in the design directory to get attractive presentation. + +

-t

+

Generate output in text format. This is the default.

+ +

-j

+

Generate output in raw machine readable form. The format produced is called +"japio" format, and by convention should be saved with a ".japio" file extension. +The standalone japiotext and japiohtml utilities can be used to convert this +format into html or text (actually, japicompat calls japiotext or japiohtml +internally if the -h or -t flags are used). Japio files can also be used with +the -i flag to support ignoring errors caused by incompatibilities between +JDK versions.

+ +

-w

+

By default japicompat will produce warnings if run against japi files +originally generated by older versions of japitools that had known bugs that +japifix cannot eliminate. Use the -w flag to turn off these warnings, or better +yet, generate your japi files with the latest version ;)

+ +

-o <outfile>

+

Send the output to <outfile> instead of stdout. The format of this file +depends on the -h, -t and -j flags.

+ +

-i <ignorefile>

+

Suppose you are attempting to implement the Java API. You have (pretty much) +completed coverage of the early JDK versions (1.0 and 1.1) but still have some distance +to achieve full coverage of 1.4 (this is an accurate description of all Free +Software Java implementations at the time of writing). Using japicompat to compare +your implementation with JDK 1.4 gives accurate results, but you might also want to +show your coverage of the earlier versions.

+

Unfortunately Sun has not followed their own binary compatibility rules between +JDK releases, let alone the expanded rules that japicompat tests for. So when you +run a comparison between JDK 1.1 and your implementation, you will get spurious +error reports when you're compatible with 1.4 but not 1.1.

+

Obviously what you really want is to ignore errors like this, and japicompat +provides a way to do so. First, run a comparison between 1.1 and 1.4 using the +-j switch. Then run the comparison between 1.1 and your implementation, passing +the "-i" option with the output of the previous run. For example:

+
+$ japicompat -jvo ignore-11-14.japio jdk11.japi.gz jdk14.japi.gz
+$ japicompat -hvo jdk11-myimpl.html -i ignore-11-14.japio jdk11.japi.gz myimpl.japi.gz
+
+

(In this example I also passed the -v flag but didn't pass -s. You should use +the same combination of these two flags for both runs of japicompat to avoid getting +bad results)

+

You can also get the same effect by running:

+
+$ japicompat -hvo jdk11-myimpl.html -i jdk14.japi.gz jdk11.japi.gz myimpl.japi.gz
+
+

This is obviously simpler and quicker to type, but requires the comparison +between jdk11 and jdk14 to be run every single time. Making the japio file +manually allows for it to be saved and used again the next time, which lets +japicompat run about twice as fast.

+

<original api> <api to check>

+

The japi files corresponding to the APIs to be compared.

+

japicompat specifically tests that the second argument is +backwardly-compatible with the first. Therefore, a perfect implementation of +JDK 1.1 would produce no errors regardless of the order of the arguments, but a +perfect implementation of JDK1.1 plus parts of JDK1.2 should be tested as +follows:

+
$ japicompat jdk11.japi.gz myimpl.japi.gz
+$ japicompat myimpl.japi.gz jdk12.japi.gz
+

It is probably impossible to make an implementation that passes both these +tests, since Sun's own JDK1.2 produces numerous errors when tested against +JDK1.1. See the discussion of the -i option above for a way to cope with this +situation.

+

Either compressed (.japi.gz) or uncompressed (.japi) files can be passed to +japicompat: The file extension is used to determine whether or not to pipe input +through gzip or not.

+ +

What exactly does japicompat test?

+

As mentioned above, japicompat tests for binary compatibility as defined +by Sun in the JLS. A full summary of what does and does not break binary +compatibility according to Sun is here.

+

However, japicompat also performs some checks that are not specified by the +JLS, for the simple reason that I believe the JLS is wrong to omit them. You can +omit these four extra checks by passing the "-s" flag to japicompat, although +I'm not sure why you would want to...

+

The specific checks that I believe the JLS should include are:

+
    +
  • Adding an exception to the throws clause of a method or constructor + violates binary compatibility, because a class calling that method may + not catch or specify the newly thrown exception. The JLS claims that the + VM does not perform any checks on thrown exceptions; I hope this has + changed because it makes it trivially easy to write a method that throws + any exception you like without specifying it.
  • +
  • Removing an exception from the throws clause of a method or constructor + violates binary compatibility, because a subclass may be overriding + the method and throwing the exception. This only applies to non-final + methods, but it is worth enforcing this rule for all methods and + constructors because otherwise it is possible to break source code + compatibility by rendering code in a catch block unreachable.
  • +
  • Adding a method to an interface violates binary compatibility, + because a class that implemented the original version of the interface + may not implement the newly added method.
  • +
  • Adding an abstract method to an abstract class violates binary + compatibility, because a concrete class derived from the original + version may not provide a concrete implementation of the new method. +
+ + +

File format

+

The file format of .japi files is described in full in +the japi file format specification. This document +should provide enough information to write a japi file fully compatible with +those produced by japize. This spec can also be found in the tarball as +design/japi-spec.txt.

+ +

License

+

These programs are made available under the +GNU General Public License, +version 2 or later.

+ +

To do

+

Here is an incomplete list of what still needs to be done:

+
    +
  • Handle the new constructs in JDK 1.5 (or 5.0 or whatever it's called), + particularly generics.
  • +
  • Fix any bugs that anyone finds...
  • +
  • Handle APIs containing international characters in class/member names, and + also international characters in final constant Strings.
  • +
  • Make a "1.0" release.
  • +
+ diff -Nru japitools-0.9.7/web/jcompat.txt japitools-0.9.7+git20150619/web/jcompat.txt --- japitools-0.9.7/web/jcompat.txt 1970-01-01 00:00:00.000000000 +0000 +++ japitools-0.9.7+git20150619/web/jcompat.txt 2015-06-19 14:59:39.000000000 +0000 @@ -0,0 +1,63 @@ +Classes: +- ILLEGAL: more access->less access (eg public->protected) +- LEGAL: less access->more access (eg protected->public) +- ILLEGAL: nonabstract->abstract +- LEGAL: abstract->nonabstract +- ILLEGAL: nonfinal->final +- LEGAL: final->nonfinal +- ILLEGAL: removing a class from the set of superclasses or an interface from the set of superinterfaces +- LEGAL: Adding interfaces or superclasses; reordering superclasses + - BUT: Note that going from A extends B extends C to A extends C extends B + breaks binary compatibility for B, even though it doesn't for A. + +Fields: +- ILLEGAL: more access->less access (eg public->protected) +- LEGAL: less access->more access (eg protected->public) +- ILLEGAL: deleting public/protected fields +- LEGAL: Adding fields +- ILLEGAL: nonfinal->final +- LEGAL: final->nonfinal +- ILLEGAL: primitive constant (static/final/compile time constant) -> non-primitive constant or different value. +- LEGAL: non-primitive constant to primitive constant. +- ILLEGAL: static->nonstatic +- ILLEGAL: nonstatic->static +- LEGAL: transient->nontransient (japitools does not address Serialization compatibility) +- LEGAL: nontransient->transient (japitools does not address Serialization compatibility) + +Methods: +- ILLEGAL: more access->less access (eg public->protected) +- LEGAL: less access->more access (eg protected->public) +- ILLEGAL: deleting public/protected methods +- LEGAL: Adding methods +- Changing the types of parameters or the result type is equivalent to deleting one method and adding another. +- LEGAL: abstract->nonabstract +- ILLEGAL: nonabstract->abstract +- ILLEGAL: adding an abstract method (the JLS does NOT specify this, but it's clearly true) + - BUT: If the class in question has no public or protected constructors it cannot be inherited from, + so it's okay to add to it. +- ILLEGAL: nonfinal->final +- LEGAL: final->nonfinal +- LEGAL: nonfinal->final on a static method +- ILLEGAL: static->nonstatic +- ILLEGAL: nonstatic->static +- ILLEGAL: changing the throws clause (the JLS does NOT specify this; see my rationale on the japitools homepage for why it should) +- LEGAL: adding new overloads to methods. +- LEGAL: adding new overrides to methods. + +Constructors: +- ILLEGAL: more access->less access (eg public->protected) +- LEGAL: less access->more access (eg protected->public) +- ILLEGAL: deleting public/protected constructors +- LEGAL: Adding constructors +- Changing the types of parameters is equivalent to deleting one constructor and adding another. +- ILLEGAL: Adding constructors such that the default constructor disappears, without replacing it. +- ILLEGAL: changing the throws clause (the JLS does NOT specify this; see my rationale on the japitools homepage for why it should) +- LEGAL: adding new overloads to constructors. + +Interfaces: +- ILLEGAL: more access->less access (eg public->protected) +- LEGAL: less access->more access (eg protected->public) +- ILLEGAL: removing any interface from being a superinterface of a class or interface. +- LEGAL: any change to the hierarchy that does not cause the above. +- LEGAL: adding a field to an interface +- ILLEGAL: Adding a method to an interface (the JLS does NOT specify this, but it's clearly true)