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... ;) )

- GNU Classpath: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated nightly).
- GNU Classpath generics branch: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated nightly).
- GNU libgcj: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated nightly).
- Apache Harmony: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated nightly).
- JNode: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated nightly).
- Kaffe: vs JDK1.0, vs JDK1.1, vs JDK1.2, vs JDK1.3, vs JDK1.4, vs JDK1.5, JDK1.5 vs it (updated manually).

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.