The Artima Developer Community
Sponsored Link

Java Buzz Forum
Java incompatability, a maddening NoClassDefError

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Norman Richards

Posts: 396
Nickname: orb
Registered: Jun, 2003

Norman Richards is co-author of XDoclet in Action
Java incompatability, a maddening NoClassDefError Posted: Aug 28, 2003 6:33 PM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Norman Richards.
Original Post: Java incompatability, a maddening NoClassDefError
Feed Title: Orb [norman richards]
Feed URL: http://members.capmac.org/~orb/blog.cgi/tech/java?flav=rss
Feed Description: Monkey number 312,978,199
Latest Java Buzz Posts
Latest Java Buzz Posts by Norman Richards
Latest Posts From Orb [norman richards]

Advertisement

Suppose that you have a Bar class with a method boing:

public class Bar
{
    public void boing() {
        // ...
    }
}

Suppose one day you refactor your classes to create a superclass and this method gets pushed up to the superclass.

public class Bar
    extends Foo
{
}


public class Foo
{
    public void boing() {
    }
}

This shouldn't be a problem. If you write code that only uses Bar, it shouldn't matter which version of Java you compile/run with or which version of your library you compile against/run against. As long as you don't reference the incompatable change, then you should ne ok. But you aren't. Here's a simple user of the class.

public class Client
{
    static Bar b = new Bar();
    public static void main(String[] args) {
        b.boing();
    }
}

In Java 1.4, no matter which version of the library you compile Client against, you get the same compilation result:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field b:LBar;
   3:   invokevirtual   #3; //Method Bar.boing:()V
   6:   return

Unfortunately, with Java 1.3, you get a very different result. Compiling against the refactored version yields:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field b:LBar;
   3:   invokevirtual   #3; //Method Foo.boing:()V
   6:   return

What is happening here is that the 1.3 compiler finds the boing() method on the Foo superclass and uses the Foo.boing() method signature in the invocation. The JVM doesn't really care whether you talk about the boing() method on Foo or on Bar. Even if both Foo and Bar implemented the method and your bytecode invoked the boing() method on Foo, you'd still get version on Bar. That's how virtual dispatch works. No matter how high up in the inheritence chain you are, you still get the right method.

So, then what is the problem? The problem is that if you run the code compiled against the refactored library with the original library then the code will fail. You'll get a NoClassDefFoundError, telling you there's no such class as Foo. The Client doesn't reference Foo anywhere, but the 1.3 compiler creates a hidden dependency.

So, just compile on 1.4 and everything will be fine. You can still run the 1.4 compiled code in 1.3 without a problem, right? For the most part yet, but you can still get bit by subtle class incompatabilities. I'm not talking about real incompatabilities like using methods that would cause the code to not compile under 1.3 at all. I'm talking about something like this:

public class SB
{
    public static void main(String[] args) {
        StringBuffer x = new StringBuffer("x");
        StringBuffer y = new StringBuffer("y");

        y.append(x);
        x.append(y);
        
        System.out.println(x);
    }
}

Try compiling this class in 1.3 and 1.4 and then running in both 1.3 and 1.4. This code is valid in 1.3 and 1.4, but if you compile using 1.4 and run using 1.3, you'll get a NoSuchMethodError. (if you don't see why, look at the APIs and the then use javap to dissasseble the class file)

Right now, using the 1.4 compiler with the 1.3 classes seems to solve all of our compatability issues. But, it's hard to be 100% sure that we don't have some hidden problems waiting to jump out at us. If you are curious where the Foo/Bar example comes from, it hit us with Struts. In 1.0 ActionForward had no super class, but in 1.1 it is under ForwardConfig. (see my prior entry about using Shell Scripts to track down the NoClassDefError) The best solution for us is to split our code base and compile against the version of Struts that we will be deploying against. (and the same Java version) But, we really shouldn't have to. As long as we aren't using incompatable features, it really should just work. Oh well...

Read: Java incompatability, a maddening NoClassDefError

Topic: PHP vs. Java - which is better? Previous Topic   Next Topic Topic: Get LinkedIn, NOW!

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use