views:

1393

answers:

13

It has been thirteen years between the initial public release of Java 1.0 (1996) and the current stable release 1.6.0_16 (2009).

During those thirteen years the following notable releases have been made:

  • JDK 1.0 (January, 1996)
  • JDK 1.1 (February, 1997)
  • J2SE 1.2 (December, 1998)
  • J2SE 1.3 (May, 2000)
  • J2SE 1.4 (February, 2002)
  • J2SE 5.0 (September, 2004)
  • Java SE 6 (December, 2006)

I'm looking for specific examples of backwards incompatibilities during the history of the Java platform.

Question:

  • In the thirteen year history of the Java platform, is there any examples of Java backwards incompatibility where Java source code/Java class files targeting Java version X won't compile/run under version Y (where Y > X)?

House rules:

  • Please include references and code examples where possible.
  • Please try to be very specific/concrete in your answer.
  • A class that is being marked as @Deprecated does not count as a backwards incompatibility.
+7  A: 

The semantics of the memory model changed from 1.4 to 1.5. It was changed to allow besides other things double checked locking again. (I think volatile semantics were fixed.) It was broken.

Thomas Jung
"semantics" not "sematics"
Jason S
Thanks, fiksed te speling.
Thomas Jung
@Jason: There is an edit button, you know.
Stefan Kendall
That is a change, but how would code in 1.4 break going to 1.5? Seems backwards compatible to me.
Yishai
+15  A: 

The interface java.sql.Connection was extended from java 1.5 to java 1.6 making compilation of all classes that implemented this interface fail.

tangens
I think all JDBC versions do that extensively. It should not be a surprise!
Tom Hawtin - tackline
+17  A: 

First of all, Sun actually considers all of the releases you mentioned (other than 1.0 of course) to be minor releases, not major ones.

I am unaware of any examples of binary incompatibility in that time. However, there have been some examples of source incompatibility:

  • In Java 5, "enum" became a reserved word; it wasn't before. Therefore, there were source files that used enum as an identifier that would compile in java 1.4 that wouldn't compile in java 5.0. However, you could compile with -source 1.4 to get around this.

  • Adding methods to an interface can break source compatibility as well. If you implement an interface, and then try to compile that implementation with a JDK that adds new methods to the interface, the source file will no longer compile successfully, because it doesn't implement all of the interface's members. This has frequently happened with java.sql.Statement and the other jdbc interfaces. The compiled forms of these "invalid" implementations will still work unless you actually call one of the methods that doesn't exist; if you do that, a MissingMethodException will be thrown.

These are a few examples I can recall off of the top of my head, there may be others.

Sean Reilly
The worst part was some of the methods added in the JDBC interfaces relied on new types that didn't exist in earlier versions. This meant it was impossible to make implementations that could compile in multiple versions of the JDK.
Laurence Gonsalves
I actually ran into this again myself just last week at work. We ended up resorted to writing a dynamic proxy to get an implementation that would compile in both Java 5 and 6.
Sean Reilly
+2  A: 

As Sean Reilly said, a new method can break your code. Besides the simple case that you have to implement a new method (this will produce a compiler warning) there is a worst case: a new method in the interface has the same signature as a method you do already have in your class. The only hint from the compiler is a warning that the @Override annotation is missing (Java 5 for classes, the annotation is supported for interfaces in Java 6 but optional).

Thomas Jung
Workaround: never make a method public unless it implements or overrides an interface method (not as hard as it might sound - I have been sticking to this rule for a few years now.)
finnw
+20  A: 

The first major hiccup I remember was the introduction of assert in Java 1.4. It affected a lot of JUnit code.

McDowell
Introducing new, reserved keywords should be severely punished! And they did it again with enum.
Thorbjørn Ravn Andersen
And yet they have never removed goto as a reserved word!
Duncan McGregor
It's interesting that there's no comment about incompatibilities of the JDBC package inside the official notes. Or did I miss it?
tangens
@tangens - probably not noted because JDBC client code would not be required to change to work against the new API; Java applications would generally not implement these interfaces; the database vendors would. You can find specific information in the @since tags in the javadoc and there's probably more detail in the JDBC spec: http://java.sun.com/products/jdbc/download.html
McDowell
+4  A: 

The following will compile under Java 1.4 but not Java 1.5 or later.

(Java 5 introduced 'enum' as a keyword. Note: it will compile in Java 5 if the "-source 1.4" option is provided.)

public class Example {
    public static void main(String[] args) {
        String enum = "hello";
    }
}
Michael Easter
+8  A: 

Between 1.3 and 1.4 the interpretation of Long.parseLong(String) handled the empty string differently. 1.3 returns a 0 value, whereas 1.4 throws a NumberFormatException.

Recompiles aren't needed, but working code stopped working if it relied on the 1.3 behaviour.

rsp
+2  A: 

I have not tried it but in theory this would work in Java 1.1 and break in Java 1.2. (More info here)

public class Test {
    float strictfp = 3.1415f;
}
Michael Easter
+10  A: 

The main one that I can think of is the introduction of new reserved words:

Java 1.3: strictfp
Java 1.4: assert
Java 5.0: enum

Any code that previously used these values as identifiers would not compile under a later version.

One other issue that I remember causing problems on a project that I worked on was that there was a change in the default visibility of JInternalFrames between 1.2 and 1.3. They were visible by default, but when we upgraded to 1.3 they all seemed to have disappeared.

Dan Dyer
+4  A: 

Yet another example of java.sql breaking compatibility:

In 1.5 a compareTo(Date) method was added to java.sql.Timestamp. This method would throw a ClassCastException if the supplied Date was not an instance of java.sql.Timestamp. Of course, java.sql.Timestamp extends Date, and Date already had a compareTo(Date) method that worked with all Dates, so this meant that code that compared a Timestamp to a (non-Timestamp) Date would break at runtime in 1.5.

It's interesting to note that it appears that 1.6 seems to have fixed this problem. While the documentation for java.sql.Timestamp.compareTo(Date) still says "If the argument is not a Timestamp object, this method throws a ClassCastException object", the actual implementation says otherwise. My guess is that this is a documentation bug.

Laurence Gonsalves
+4  A: 

obviously the naming convention of release names is not backwards-compatible.

  • JDK 1.0 (January 23, 1996)
  • JDK 1.1 (February 19, 1997)
  • J2SE 1.2 (December 8, 1998)
  • J2SE 1.3 (May 8, 2000)
  • J2SE 1.4 (February 6, 2002)
  • J2SE 5.0 (September 30, 2004)
  • Java SE 6 (December 11, 2006)
  • Java SE 6 Update 10, Update 12, Update 14, Update 16
  • Java SE 7 ??? JDK7?

(list from wikipedia)

Andreas Petersson
+11  A: 

Every release of Swing broke something for us, from 1.3 through 1.6.

The JDBC issue has already been mentioned, but existing code worked.

From 1.5 to 1.6 there was a change in the behavior of Socket which broke the Cisco client.

Of course new reserved keywords were introduced.

The big one which I think was truely unforgivable on Sun's part was System.getenv(). It worked in 1.0, and then was deprecated and changed to throw an error on all platforms under the rather dubious justification that the Mac didn't have system environment variables. Then the Mac got system environment variables, so in 1.5 it was undeprecated and works. There is no reasonable justification for doing that. Return an empty set on a Mac (Swing has much bigger cross-platform issues if you want to care about that level of cross platform consistency) or even on all platforms.

I never agreed with them turning off the feature, but to change it to throw an error was just a pure breaking change that if they were going to do, they should have just removed the method entirely.

But, really from 1.0 to 1.1 they were less concerned about backwards compatability. For example, they dropped "private protected" as a modifier.

So the upshot is that every version changes enough to require close evaluation, that is why you still see many 1.4 questions here on SO.

Yishai
+1  A: 

From personal experience, we had some AWT/Swing text fields embedded in a SWT_AWT frame in 1.5, that ceased to be editable after upgrading to 1.6.

Chris