Over a million developers have joined DZone.
Platinum Partner

A Tale of Four JVMs and One App Server

· Java Zone

The Java Zone is brought to you in partnership with ZeroTurnaround. Discover how you can skip the build and redeploy process by using JRebel by ZeroTurnaround.

This article proposes a way to reveal latent bugs in Java applications by running them on different JVMs. It is illustrated with a real world example involving a popular Java application server.

Starting point

A user has recently reported in the JBoss issue tracker that JBoss AS 5.0.0 GA fails to start on the IBM JRE. One may say: So what? Didn't you hear that the IBM JRE "fits better" for another app server?

Independently, our QA team has encountered the same problem when testing JBoss 5.0 on a new version of Excelsior JET JVM. A quick check confirmed that the problem manifests itself on Oracle JRockit as well.

At the same time, on the Sun JRE everything worked like a charm...

Well, I respect the Sun reference implementation but something suggested to me that the other three JVMs, which all support Java 6 and passed the Sun JCK, cannot have exactly the same bug.

Further investigation has shown that the issue was in the Java code that worked on the Sun JRE by a lucky coincidence.

Just follow the specification

The root cause of the problem is that JBoss 5.0 (intentionally or not) relies on the order of elements in the array returned by the method


and under the Sun JRE the order happens to be "right". However, the Java SE API specification says "...The elements in the array returned are not sorted and are not in any particular order."

The full transcript of the root cause analysis of that issue is available in this Excelsior's blog post. We have also posted a comment to the JBoss issue tracker.

Now one may say: I don't care about it. I deployed, deploy, and will deploy my application with the Sun JRE whatever other Java implementations would offer. OK, no problem but...

Kind of magic

Consider this simple program that reflects the declared constructors and prints the result:

import java.lang.reflect.*;

class Test{
Test() {}
Test(Object o) {}
Test(String s) {}

public static void main(String args[]){
for (Constructor c: Test.class.getDeclaredConstructors())

If run on the Sun JRE 6, it prints:


So far so good. It looks like the constructors appear in the order they are declared in the source code. Let’s add a few instance methods to the code to make it a little bit more realistic:

void dont() {}
void rely() {}
void on () {}
void it () {}

and run the program on the same version of Sun JRE. Now it prints:


Surprise! If you want to find the rationale behind this behavior, you may dig into the OpenJDK sources starting from the method sort_methods() in the file hotspot\src\share\vm\runtime\classfileparser.cpp.

The lesson learned: Java applications may not rely on JVM features that are not enforced by the Java specification.

On speculative assumptions

Some observant readers may notice that the order of constructors from the examples above matches either direct or reverse order of their declaration in the source code. I however would not recommend to exploit this observation. Just add one more method:

    void ever() {}

to the code and run it to see yet another (different) order of the reflected constructors!

I must say that I did not get the last example out of my head. The quite popular JNA library used to rely on exactly this assumption regarding the method Class.getDeclaredFields(): the order of reflected fields was deemed either direct or reverse. Fortunately, in JNA 3.0.5, “support for JVMs with unpredictable order of fields” has been added though I would rather call it “improved compliance with the Java specification”.


Neglecting the Java spec, you still have a chance to get a working application. But you also have a chance that it will stop working if you modify the code or upgrade the underlying JVM. As a result, you may have to spend (waste) time on hunting subtle bugs or, even worse, get stuck with an outdated Java version if such bugs lurk in third-party components (yeah, J2SE 1.4.2 still has its “thankful” audience).

What would be a solution for this problem? I cannot imagine a “rule checker” that tests Java applications for compliance with the Java spec. Implementing such a tool is unlikely possible because the semantics of programs is involved.

For now, the only practical option is testing your Java application on different JVMs provided they support the same Java version (with the same level of Java compatibility). If the application does not work on one or more of them, it may be an issue worth investigating.

P.S. By the way, another large cluster of latent bugs that this testing approach can help you reveal is data races (aka random features) in multi-thread Java applications but that is another tale.

The Java Zone is brought to you in partnership with ZeroTurnaround. Discover how you can skip the build and redeploy process by using JRebel by ZeroTurnaround.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}