Java Developer Guide

Background
Before going into details of how Java is handled on Gentoo, it is worthwhile to take a few moments to discuss current trends in the Java programming world.

Java Build Systems
There are a few build systems commonly used for Java projects. Apache's ant (Another Neat Tool) is by far the most common. It is a task oriented system. This means that you give Ant instructions on what tasks to perform and how to perform them to build your project. For example, compile these source files using this class path, create a jar of these classes, and so on. It is fairly easy to get up and running with Ant. Unfortunately, it leaves a lot of room for variation, so Ant scripts are terribly inconsistent from one project to the next.

Maven is another Apache project which has been gaining popularity. In contrast to ant, it is a project based system. This means that you give maven information about your project, and once that's established, you can do many things without any further configuration. For example, you tell maven your project's name and where your source is, and you can then tell maven: "Hey maven, make me a jar and some javadocs too!". Another feature of maven is its ability take care of making a project's dependencies available by downloading them from mirrors.

Another tool which is also gaining widespread popularity in the Java world, partly due to Google adopting it as the main tool for building Android projects, is Gradle. What is Gradle? Basically, gradle is a project automation tool that builds upon the concepts of Apache Ant and Apache Maven and introduces a Groovy-based domain-specific language. Gradle isn't part of Portage (yet) nor it is in our plans to introduce it to our build process (for the foreseeable future). We are keeping an eye on it though. Experimental ebuids are available in the Gentoo Java overlay.

You can also find a number of packages using the classic combination of autoconf and automake. They will mostly be found on projects that interact with existing C and C++ libraries. Unfortunately, automake and autoconf are used mostly dealing with the non-Java bits, leaving the Java bits wedged where it can fit.

Lastly, you may find custom scripts which will attempt to run javac, jar, and javadoc itself, or it may just be a wrapper for ant to properly prepare the build environment.

Bundled Dependencies
One of the features of Java has always been "compile once, run everywhere." A consequence of this is that Java developers traditionally bundle all library dependencies with their project's distribution. While this might be convenient for the end-user, it rapidly becomes problematic from a packager's point of view.

For example, project A depends on C, and project B depends on C, and you have project A and B installed, then you'd have two copies of C installed to support it. And if there's new release of C with a bug or security fix, you would want both A and B to take advantage of it.

Java on Gentoo
This section will give you more insight into how Gentoo handles Java. You should be familiar with the Java User Guide before proceeding.

Virtual Machines (VMs)
As discussed in the User Guide, there are several VMs available from portage.

Testing all packages to ensure they build and run with every VM is a huge undertaking, and there simply are not enough resources to guarantee every package will build and run with every VM.

We now maintain a list of "supported virtual machines" for each architecture. These are the VMs we will test the packages against before committing changes to portage. When you emerge a package, it will by default try to use the best "supported virtual machine."

Of course, Gentoo and Linux in general are about choice, so if you prefer a different VM over the "supported virtual machines", you can easily use that VM instead. However, you should also know that bugs reported with one of the non-"supported virtual machine" will get a low priority if it isn't present using a "supported virtual machine".

Configuring which VM to Use
You can choose which VM to use on a per-user basis, and which VM to use for the system (ie when running things as root). Both of these are configured using java-config.

A user's current VM is represented by a symlink located at ~/.gentoo/java-config-2/current-user-vm. This symlink points to the JAVA_HOME of the chosen VM. Similarly, the system VM is represented by a symlink at /etc/java-config-2/current-system-vm.

The current VM can also be changed on the fly. This can be accomplished setting the environment GENTOO_VM to contain the name of a VM that java-config knows about.

Java Tools
The traditional Java tools, ie, java, javac, javadoc, etc, are all located in /usr/bin. They are actually all symlinks to the run-java-tool script. This script will call the appropriate tool, depending on how the script is invoked, from the current VM. GENTOO_VM is first checked, then the user VM, and lastly the system VM.

Build-time VM Switching
As outlined in the User Guide, and mentioned briefly earlier, the VM will switch at build time to accommodate the needs of the package. The VM to use is first determined by JAVA_PKG_FORCE_VM, then /etc/java-config-2/build/jdk.conf, and lastly the system VM.

Bytecode Compatibility
The default behavior of javac is to compile bytecode that will compatible with the current VM version and higher (ie forward compatible). It is possible to specify which VM to compile for to provide the best compatibility.

At build time, the DEPEND and RDEPEND will determine what VM to compile for based on virtual/jdk and virtual/jre. Additionally, this can be controlled by the environment variables JAVA_PKG_WANT_SOURCE and JAVA_PKG_WANT_TARGET.

There is a wrapper for javac, ejavac, which will use the appropriate VM's javac, and then specify the appropriate -target and -source. For projects that use ant, the build.xml can be translated to specify the appropriate -target and -source.

Gentoo Java Packaging Policy
In addition to other Gentoo policies, there are a few unique to Java packages, or that need special attention.

Why build from source?
We should strive to only accept ebuilds that build from source code. For reasons why, please refer to Why Build From Source.

Filesystem Layout
In general, the directory policies are handled for you by the helper functions in the java-utils-2 eclass.

These functions adhere to the following path name conventions:


 * /usr/share/${PN}-${SLOT}/package.env contains information about the package
 * .jar files created from source code are installed to /usr/share/${PN}-${SLOT}/lib/
 * .jar pre-built files not compiled by the ebuild are installed to /opt/${PN}-${SLOT}/lib
 * Javadoc documentation is installed to /usr/share/doc/${PF}/html/api/
 * Source archives are installed to /usr/share/${PN}-${SLOT}/source/
 * User-executable scripts are installed to /usr/bin
 * System-wide environment files are in installed to /usr/env.d/java
 * User-specific environment files can be put into ${HOME}/.gentoo/env.d/

Slotting
Libraries should be slotted according to the API they provide. If two version have the same API, or if a new version is fully compatible with the previous version, then they should be in the same SLOT.

Java libraries have a tendency to sometimes break API and ABI between minor revisions, ie from 2.1.1 to 2.1.2. As a result, it is necessary to slot early, and slot often.

For applications, it is mostly sufficient to keep only the latest version. If the application comes in series, such as Eclipse, we want to keep the latest revision in each series. Very old series may eventually be dropped completely.

Dependencies
Packages should not use bundled jars. Instead, they should make use of jars from already installed packages.

When depending on a package, take care that you depend on a sufficiently recent version, and explicitly ensure at building time that the providing package gives you the correct interface, i.e. the correct SLOT.

General Guidelines
In addition to standard Gentoo ebuild guidelines, there are a number specific for Java packages:


 * In RDEPEND, use ">=virtual/jre-[minimal-version]". If you need a JDK for normal operation, like www-servers/tomcat used to, then you should use ">=virtual/jdk-[minimal-version]". The jre atom MUST have a version.
 * In DEPEND, use ">=virtual/jdk-[minimal-version]", unless the ebuild is not compiling source. The jdk atom MUST have a version.
 * For packages that use Ant to build, try to DEPEND on just dev-java/ant-core when possible instead of dev-java/ant. dev-java/ant-core is automatically added to DEPEND if you inherit java-ant-2. If the package makes use of 'optional' ant tasks, you'll need to DEPEND on dev-java/ant or add WANT_ANT_TASKS="ant-task" before inherit. The latter is of course preferred. see the Ant Guide for details.
 * For packages that are distributed as zip, you need to DEPEND on app-arch/unzip to unpack
 * Since Portage does not support depending on a particular slot at this time, your DEPEND and RDEPEND should look like =dev-java/some-library-1.2* to signify that any 1.2.x library is supported. Presumably, they will all be SLOT compatible.
 * Avoid using bundled .jar files at all costs for source-based packages. Instead, they should use system installed versions with the help of our eclass functions.
 * If you only need the path to installed libraries, you can use java-pkg_getjar(s). Don't call java-config directly, because it will not be recorded as a dependency in the package env.
 * Always provide an easily understandable reason after 'die', so that end-users will provide the maintainers with sensible feedback if the build should fail.
 * Avoid cluttering up the environment by adding environment files to /etc/env.d/. Instead, store your env file in /etc/env.d/java/, and then have user scripts source its environment file when it launches. Otherwise, developers, who regularly override CLASSPATH, CATALINA_HOME and other env vars, will have problems running regular apps. If you use the launcher it will also automatically source the appropriate env file.
 * Make sure you always compile with correct a source/target. This is important to ensure future and backwards compatibility. If the packages use ant, this can be done for you automatically. See java-ant-2.eclass. If not you will have to patch it to pass $(java-pkg_javac-args) to javac.
 * Do no install jars which contain versions in their filename, ie castor-0.9.7.jar. Use java-pkg_newjar to rename and install versioned jars to not contain the version in their filename.

USE flags
If a manual or other extensive documentation is available, it should be installed using the doc USE flag. If the build system can, you should build javadocs also using the doc USE flag. If it does not, you should consider patching it to do so, and provide the patch upstream. HTML documentation should be installed using dohtml and javadocs using java-pkg_dojavadoc.

If the program provides examples, in the form of source code or some other format, and you think they may be worthwhile for some users to have, install them optionally with the examples use flag using the java-pkg_doexamples function.

If you want to go all the way, add the source USE flag that installs the complete source code as a .zip file. Use java-pkg_dosrc for this purpose. This allows IDEs such as Eclipse and NetBeans to do complete source-level debugging. You will need to also DEPEND="source? ( app-arch/zip )" or add JAVA_PKG_IUSE="source" before inherit. Using JAVA_PKG_IUSE means that we can remove the app-arch/zip requirement in the future and use for example jar provided by virtual/jdk.

If your package comes with unit tests, you can enable these using the test FEATURE, in src_test. If you need extra dependencies for the testing you can pull these in with the test useflag (for example dev-java/junit). We will no longer use the junit use flag for this.

Typical Examples
Without further ado, here are a few examples: