If you’re a Java developer and are using a Linux system, probably you’ve had to deal with the alternatives program. I’m going to be honest, I hate ‘alternatives‘ (with a passion). I use the command-line all the time, but I just think the interface of this command is counterintuitive. I will try in this post to explain how the ‘alternatives‘ program works, specifically for configuring Java,  and how I think its interface could be improved.

When there are several programs that response to the same command in a system, the ‘alternatives‘ command let us set which will be the real program that will be executed when that command is called. This is very clear to see in the case of Java. There are several JDK implementations: OpenJDK, GNU, JDK from Oracle, etc. All these JDKs come with a ‘java‘ executable. Supposing we got several JDKs from different vendors installed, which will be the one executed in our system when the ‘java‘ program runs?

Firstly, I’ll check what are the Java alternatives configured in my system:

$ alternatives --config java

+  1        /usr/lib/jvm/jre-1.6.0-openjdk/bin/java
*  2        /etc/alternatives/java_sdk/bin/java
3           /usr/lib/jvm/jre-1.5.0-gcj/bin/java
4           /usr/java/latest/bin/java
5           /usr/java/jdk1.7.0/bin/java

It seems I got several :) If you just installed Fedora and run the command above, probably you’ll see nothing, as you haven’t added an alternative yet. So, how to add a new alternative? I run the help first:

$ alternatives --help

Says that: *‘alternatives –install *‘, adds a new alternative. Now, the million-dollar question. What the hell means each parameter? This is pretty obscure if you don’t really understand what’s the purpose of the ‘*alternatives*‘ program.

  • **** is the name under which the alternative will be grouped. If we set ** as *‘java’*, then when later we do: ‘*alternatives –config java*‘, the alternatives for ‘*java*‘ will be listed.
  • is the full path to the command that will be executed. If we set as ‘/usr/bin/java’, this means that when the ‘/usr/bin/java‘ command is executed in our system, the default alternative for ‘java‘ will be run.
  • **** is the full path to the command of the alternative. The program which will be actually run.
  • **** a priority number. The highest the number, the higher the priority. That means that the alternative with the highest number will be executed by default, unless we manually set which is the default.

So, imagine I’m doing a fresh installation, downloaded the latest version of Oracle JDK 1.6 and would like to add it as an alternative. We should run the following command:

$ sudo alternatives --install /usr/bin/java java  /usr/java/jdk1.6.0_25/bin/java 1000

Now if we list the alternatives for ‘java‘.

$ sudo alternatives --config java

Selection    Command
-----------------------------------------------
*+ 1           /usr/java/jdk1.6.0_25/bin/java

When you run this command the prompt asks you which alternative will be the default.

Enter to keep the current selection[+], or type selection number:

The ‘+‘ symbol indicates the manual default, the ‘***‘ indicates the automatic default (the one with the highest number). In this case as there is only one alternative both signs point to the same alternative.

Let’s execute the ‘java‘ command and see what happens:

$ java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) Server VM (build 20.0-b11, mixed mode)

You may think this is a pretty stupid example as there is only one alternative. Let’s add OpenJDK as an alternative (imagine I just downloaded and have successfully installed in my system). I should run the following:

$ sudo alternatives --install /usr/bin/java java /usr/lib/jvm/jre-1.6.0-openjdk/bin/java 2000

As we have set OpenJDK with a priority of 2000, higher that Oracle JDK (which was 1000), that means that now OpenJDK is the default alternative for ‘java‘.

$ alternatives --config java
There are 2 programs which provide 'java'.

Selection    Command
-----------------------------------------------
1           /usr/java/jdk1.6.0_25/bin/java
*+ 2        /usr/lib/jvm/jre-1.6.0-openjdk/bin/java

Let’s see what happens if we run ‘java‘ now.

$ java -version
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.3) (fedora-59.1.10.3.fc15-i386)
OpenJDK Server VM (build 20.0-b11, mixed mode)

As the OpenJDK is now the default alternative, OpenJDK is executed.

What if we would like to remove an alternative. The help says:

alternatives --remove <name> <path>

Remember that ** is actually ** as it’s listed in the list of alternatives. So, if we would like to remove OpenJDK we should type the following:

$ sudo alternatives --remove java /usr/lib/jvm/jre-1.6.0-openjdk/bin/java

Now  Oracle JDK should be the only alternative available:

$ alternatives --config java

There is 1 program that provides 'java'.

Selection    Command
-----------------------------------------------
*+ 1           /usr/java/jdk1.6.0_25/bin/java

Another interesting parameter is the* ‘–display’* option, which show information about the available alternatives.

$ sudo alternatives --display java
java - status is auto.
link currently points to /usr/java/jdk1.6.0_25/bin/java
/usr/java/jdk1.6.0_25/bin/java - priority 1000
Current `best' version is /usr/java/jdk1.6.0_25/bin/java.

And that’s basically all you need to know about alternatives with regard to Java configuration.

Now, why I think the interface of alternatives is somehow counterintuitive?

Well, the first thing is that when you list the alternatives there are two headers: ** and **. The help, however tells you that for installing or removing and alternative you need to provide a ** and a **. What is called ** is in fact **, so if they mean the **same thing**, they should have the **same name**. Another thing is that unless you really got a good grasp of what the ‘*alternatives*‘ program does, it’s difficult to understand at first sight what’s the meaning of **. Perhaps an example in the man pages could help (an EXAMPLE section should be mandatory in every man page IMHO, but that’s another story). Lastly, I wonder what’s the purpose of providing ** for removing an alternative? If the way the user knows about alternatives is by listing them and there’s an identifier for each alternative (the ** column), wouldn’t be much easier to remove an alternative in this way *‘alternatives –remove java 1*‘ (meaning “*remove the first alternative for java*“), which definitively is much easier and intuitive than typing *‘alternatives –remove java /usr/java/jdk1.6.0_25/bin/java’*. Just my two cents.