Are there any specific examples of backward incompatibilities between Java versions? - java

Have there been incompatibilities between Java releases where Java source code/Java class files targeting Java version X won't compile/run under version Y (where Y > X) ?
By "Java release" I mean versions such as:
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)
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.

Compatibility notes for various versions:
Java 1.4
Java 5
Java 6
Java 7
Java 8
The first major hiccup I remember was the introduction of assert in Java 1.4. It affected a lot of JUnit code.

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.

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.

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.

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.

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.

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.

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";
}
}

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?
(The list is from Wikipedia.)

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.

See report on API changes for the JRE class library here: http://abi-laboratory.pro/java/tracker/timeline/jre/
The report includes backward binary- and source-compatibility analysis of Java classes.
The report is generated by the japi-compliance-checker tool.
...
Another interesting analysis for JDK 1.0-1.6 you can find at Japitools JDK-Results page.

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).

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;
}

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.

Related

Can program developed with Java 8 be run on Java 7?

I am a little confused.
Oracle says Java 8 is highly compatible with Java 7 (backward). But, what possibilities exist that Java 8 program can be run on Java 7 successfully (SE/EE)?
If point one was true, Java 8 applications will be deployed and executed on a Java 7 server support? for example, Tomcat 8 or WildFly?
In general, no.
The backwards compatibility means that you can run Java 7 program on Java 8 runtime, not the other way around.
There are several reasons for that:
Bytecode is versioned and JVM checks if it supports the version it finds in .class files.
Some language constructs cannot be expressed in previous versions of bytecode.
There are new classes and methods in newer JRE's which won't work with older ones.
If you really, really want (tip: you don't), you can force the compiler to treat the source as one version of Java and emit bytecode for another, using something like this:
javac -source 1.8 -target 1.7 MyClass.java
(the same for Maven), and compile against JDK7, but in practice it will more often not work than work. I recommend you don't.
EDIT: JDK 8 apparently doesn't support this exact combination, so this won't work. Some other combinations of versions do work.
There are also programs to convert newer Java programs to work on older JVM's. For converting Java 8 to 5-7, you can try https://github.com/orfjackal/retrolambda To get lower than 5, you can pick one of these: http://en.wikipedia.org/wiki/Java_backporting_tools
None of these hacks will give you new Java 8 classes and methods, including functional programming support for collections, streams, time API, unsigned API, and so on. So I'd say it's not worth it.
Or, since you want to run your Java 8 JEE applications on an application server, just run your entire server on Java 8, it may work.
Backward compatibility means
You can Run Lower configuration on Higher Configuration not Vice-Versa .
Well, there is the -target compiler option, which lets you target the class file format of previous java versions. However, this doesn't fix or detect things such as using classes or methods introduced in JDK APIs after the target version.
No backward compatibility means that Java7 programs will run under Java8 but the reverse is not always true
You may also check Oracle Limit Backward Compatibility
In general, new versions have to give backwards compatibility, so people dont have to throw their work and can upgrade easily. The other way round (newer version running in older version) is not necesarily true because if you use some new implemented feature, that feature obviously does not exist in the previous version and won't work.
Regards
I generated stubs from WSDL, compiled in java 8 and was able to deploy them on server having java 1.6 jvm on it.

what is the general java API compatibility rule

in detail:
if we use public API for example, write java program for example , in JDK 1.4, if should run correctly in all version above it. in all update version in 1.4, in 1.5, 1.6 and 1.7?
Also , what is the combability rule between different updater versions , for example 1.6.22 and 1.6.23 what can not be changed, what can be changed?
of course, public API definition can not be changed, how about others? javadoc? internal API definition, implementation?
It will be great if someone can point a concrete official document on this topic. thanks,
there is one example in java document bug, that they intended not to change between updater version. see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6475885
this should be one of its big picture, but we better to have a complete description on this.
need to know the complete story so that we feel safe to upgrade to bigger version.
The general rule is that any code that is written and compiled against the APIs of Java X should run on Java Y where Y >= X.
There are occasional exceptions to this; e.g. where the application's behaviour depends on some undocumented behaviour (typically a bug) in Java X that was corrected in a later version.
AFAIK, there is no single document that lists these incompatibilities. The release notes for all of the Java major releases include a list of changes that could result in breakage of older code.
Having said that, the prudent approach is make sure that you thoroughly test / retest your software when you upgrade to a more recent Java release. And if your software is shipped to customers / clients, let them know if / when it is safe for them to upgrade, and (if necessary) provide them with fixes for any problems that your testing has uncovered.
need to know the complete story so that we feel safe to upgrade to bigger version.
Feeling safe is beside the point. Thoroughly test your application on the later version. That is the only practical solution. And that would be the case even if each and every incompatibility was exhaustively documented.
Think about it. How can you know for sure that your application won't somehow be affected by change XYZ? Or that some 3rd-party library that you use won't be affected? Answer: you can't.
No manner of complaining here that you think that Oracle should handle this issue differently is going to make any difference. Not that I think that they could handle this better without changing their business model. How much would you be prepared to pay for a Java platform that guaranteed there were no version compatibility issues?
This is not a full answer but I will add that will-it-run and will-it-compile are two different things. Keywords introduced in 1.5 will prevent some 1.4 code from compiling but the byte code will run just fine.
Almost anything can be changed between versions there are no set rules for such things. Use the release notes to publish changes or review them between versions such as:
http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html
Usually only bug fixes are the cause of minor versions (like you detail 1.6.22 - 1.6.23), or simple enhancements which are only ever good things. When the major version numbers change then you can expect more major changes but you still "hope" for reverse compatibility.
I don't think JDK ever changes an API that breaks backward comparability (except unintentionally).
They introduced #deprecated tag in the very beginning, probably thinking that they may need to do some API cleanup in future. But that never happens. No #deprecated API has ever been removed, or behavior changed.
if we use public API for example, write java program for example , in JDK 1.4, if should run correctly in all version above it. in all update version in 1.4, in 1.5, 1.6 and 1.7?
See this table, that shows breaking changes in public jdk APIs
See these official documents about versions compatibility:
Java SE 7 and JDK 7 Compatibility
Java SE 6 compatibility with J2SE 5.0
Incompatibilities in J2SE 5.0 (since 1.4.2)
Java SE 1.4.2 Compatibility with Previous Releases

what is difference between JDK 1.4 and JDK1.6

I have created the project using the JDK 1.4. Now I want to use JDK 1.6 version in my project.
for this what steps are required.Means I want to know the what changes is require in code to get a JDK 1.6 feature.Basically I am talking about the features that is added in JDK 1.6. If any one list out that changes it is very helpful.
Thanks in advance..............................
Better to see differences between 1.4 and 1.5 and then between 1.5 and 1.6.
You can check new features in each version on official web site, but below is a little chronology ...
JDK 1.0 (january 23, 1996) oak
Initial release
JDK 1.1 (february 19, 1997)
Retooling of the AWT event model
Inner classes added to the language
JavaBeans
JDBC
RMI
J2SE 1.2 (December 8, 1998) playground
This and subsequent releases through J2SE 5.0 were rebranded retrospectively Java 2 & version name "J2SE"
(Java 2 platform, Standard edition) replaced JDK to distinguish the base platform from
J2EE (java 2 platform, enterprise edition) and J2ME (java 2 platform, micro edition).
Strictfp keyword
Reflection
Swing api integration into the core classes
JVM equipped with a jit compiler
Java plug-in
Java IDL
An IDL implementation for corba interoperability
Collections Framework
J2SE 1.3 (may 8, 2000) kestrel
Hotspot jvm included
JavaSound
JNDI included in core libraries
Java platform debugger architecture (jpda)
RMI was modified to support optional compatibility with corba
J2SE 1.4 (february 6, 2002) merlin
assert keyword
Regular expressions
Exception chaining (allows an exception to encapsulate original lower-level exception)
Internet protocol version 6 (IPV6) support
Non-blocking nio (new input/output)
Logging API
Image i/o api for reading and writing images in formats like jpeg and png
Integrated XML parser and XSLT processor (JAXP)
Integrated security and cryptography extensions (JCE, JSSE, JAAS)
Java web start
J2SE 5.0 (september 30, 2004) tiger [originally numbered 1.5]
Generics: provides compile-time
(static) type safety for collections
and eliminates the need for most
typecasts (type conversion).
Metadata: also called annotations; allows language constructs such as classes and methods to be tagged with additional data, which can then be processed by metadata-aware utilities.
Autoboxing/unboxing: automatic conversions between primitive types (such as int) and primitive wrapper classes (such as integer).
Enumerations: the enum keyword creates a typesafe, ordered list of values (such as day.monday, day.tuesday, etc.). Previously this could only be achieved by non-typesafe constant integers or manually constructed classes (typesafe enum pattern).
Swing: new skinnable look and feel, called synth.
Var args: the last parameter of a method can now be declared using a type name followed by three dots (e.g. Void drawtext(string... Lines)). In the calling code any number of parameters of that type can be used and they are then placed in an array to be passed to the method, or alternatively the calling code can pass an array of that type.
Enhanced for each loop: the for loop syntax is extended with special syntax for iterating over each member of either an array or any iterable, such as the standard collection classesfix the previously broken semantics of the java memory model, which defines how threads interact through memory.
Automatic stub generation for rmi objects.
Static imports concurrency utilities in package java.util.concurrent.
Scanner class for parsing data from various input streams and buffers.
Assertions
StringBuilder class (in java.lang package)
Annotations
Java SE 6 (december 11, 2006) mustang
sun replaced the name "J2SE" with java se and dropped the ".0" from the version number.
Beta versions were released in february and june 2006, leading up to a final release that occurred on december 11, 2006.
The current revision is update 20.
Support for older win9x versions dropped.
Scripting lang support: Generic API for integration with scripting languages, & built-in mozilla javascript rhino integration
Dramatic performance improvements for the core platform, and swing.
Improved web service support through JAX-WS JDBC 4.0 support
Java compiler API: an API allowing a java program to select and invoke a java compiler programmatically.
Upgrade of JAXB to version 2.0: including integration of a stax parser.
Support for pluggable annotations
Many GUI improvements, such as integration of swingworker in the API, table sorting and filtering, and true swing double-buffering (eliminating the gray-area effect).
Java se 6 update 10
A major enhancement in terms of end-user usability.
Java Deployment Toolkit, a set of
javascript functions to ease the
deployment of applets and java web
start applications.
Java Kernel, a small installer including only the most commonly used jre classes. Enhanced updater.
Enhanced versioning and pack200 support: server-side support is no longer required.
Java quick starter, to improve cold start-up time.
Improved performance of java2D graphics primitives on windows, using direct3D and hardware acceleration.
A new Swing look and feel called NIMBUS and based on synth.
Next-generation java plug-in: applets now run in a separate process and support many features of web start applications.
Java se 6 update 12
This release includes the highly anticipated 64-bit java plug-in (for 64-bit browsers only), windows server 2008 support,
and performance improvements of java and JAVAFX applications.
...........
You can check in wikipedia till latest update.
To my opinion, the four most prominent enhancements since Java 1.4.2 are
Generics
enums
enhanced for-loop and
Annotations
There are a lot of additional classes and API enhancements, but if you want to 'upgrade' your code, I'd suggest to start your refactoring with using generics and replacing standard for loops by enhanced for loops. Both can be done without major code changes, clean up the code (you can delete a lot of lines of code) and improve readability. And using generics might reveal some hidden bugs ;)
I have created the project using the JDK 1.4. Now I want to use JDK 1.6 version in my project. For this what steps are required.
Actually, there is (almost) nothing that you need to start to make a JDK 1.4 application run using JDK 1.6. In nearly all cases, you simply need to recompile the code with the JDK 1.6 compiler and run it in a JDK 1.6 JVM. The only problems you are likely to encounter are:
If your code uses "enum" as an identifier, you will need to change it to something else. enum is a keyword starting in Java 1.5.
If your code directly depends on Sun proprietary / internal classes, you may need to deal with unannounced API changes.
You might find the certain official API classes or methods have been marked as deprecated.
There are a small number of changes in API implementations / behaviors with each release that may impact your application. These are typically highlighted in the document on upgrading.
Once you have got your application working on Java 1.6, you can then think about whether and when to start using the Java 1.5 language extensions, and the new / enhanced APIs in the class libraries.
Means I want to know the what changes is require in code to get a JDK 1.6 feature.
Almost no changes are required. But obviously, if you want or need to use a new feature you will need to change your code to do that.
Wikipedia has an summary of the most significant changes made across various Java releases.
UPDATE
As of May 2014, Java 6 has been "end-of-lifed", and Java 8 has been released for a month or so (with no significant early release number dramas). You should now be thinking about moving to at least Java 7, and probably Java 8.
The same principles apply. Recompile and run your regression tests, and you will most likely to be good to go. Then start learning all about the Java 8 language extensions.
What's new in JDK 6?
There are so many changes added in 6.0.
However all your 1.4 code will run smoothly.
For further reference about the version please see the following link
http://en.wikipedia.org/wiki/Java_version_history#Java_SE_6_.28December_11.2C_2006.29
Hope it helps.
The important details on 1.5 extensions are covered in these slides which provides also code examples.
There is a big difference in behaviour for volatile keyword in 1.5 - more along the lines of C# away from C++ behaviour. But it only makes the code safer. So no code changes.

Is there a Java program snippet which can compile with a Java 5 compiler on JRE 6 but not Java 6 compiler?

I want to have a source file which can compile with javac / ecj set to Java 5 but not Java 6 (even if the underlying Java runtime is Java 6).
This is to be certain that the compiler level is set correctly in Eclipse 3.5 running with Java 6 installed, but where the result needs to run on a Java 5 installation.
For java 1.4 I could use "enum" as a variable name (which fails under Java 5 and later) but I cannot locate a similar approach for Java 5 versus 6 (and later).
Suggestions?
There's nothing in the Java language that was removed between JDK5 and 6. The only thing which was added, as has been said, was the #Override annotation being allowable on interface methods - no keywords. Hence you are left with library diferences as the only cause of breaking changes, I'm afraid.
These do exist, even in the core API; in an unusual fit of backwards-compatibility-breaking revelry they changed the signature of some methods on the ExecutorService interface. This was because the generic signatures of the methods were overly restrictive. This was a pure library change (although, being part of java.util, a pretty core library); nothing to do with any language-level modification.
For example, from JDK5 :
<T> T invokeAny(Collection<Callable<T>> tasks)
to JDK6:
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
This means that any program which contained code implementing this interface in JDK5, would not have compiled against JDK6. A snippet is easy to create; just let your IDE create an empty implementation of the JDK5 interface and then build against JDK6.
Note: that the wildcard was added because the previous version would not have accepted a parameter like List<MyCallable<String>> (i.e. the collection being typed by some subclass of callable) whereas the later version does.
Since JVMDI was removed and JVMPI was disabled in Java SE 6 (according to J2SE 6.0 release note), you could add a code using that API: it will not compile with J2SE 6.0, only 5.0. (as illustrated by this thread)
Not an answer to your question but an alternative to your approach: wouldn't it be possible to use a second builder, based on ant or maven, that you use on demand to create the final application or library? This build would use a real external Java 5 SDK and thus guarantee that the application/library runs in a Java5 environment.

Consequences of running a Java Class file on different JREs?

What are the consequences of running a Java class file compiled in JDK 1.4.2 on JRE 1.6 or 1.5?
The Java SE 6 Compatibility page lists the compatibility of Jave SE 6 to Java SE 5.0. Furthermore, there is a link to Incompatibilities in J2SE 5.0 (since 1.4.2) as well. By looking at the two documents, it should be possible to find out whether there are any incomapatibilities of programs written under JDK 1.4.2 and Java SE 6.
In terms of the binary compatibility of the Java class files, the Java SE 6 Compatibility page has the following to say:
Java SE 6 is upwards binary-compatible
with J2SE 5.0 except for the
incompatibilities listed below. Except
for the noted incompatibilities, class
files built with version 5.0 compilers
will run correctly in JDK 6.
So, in general, as workmad3 noted, Java class files compiled on a older JDK will still be compatible with the newest version. Furthermore, as noted by Desty, any changes to the API are generally deprecated rather than removed.
From the Source Compatibilities section:
Deprecated APIs are interfaces that
are supported only for backwards
compatibility. The javac compiler
generates a warning message whenever
one of these is used, unless the
-nowarn command-line option is used. It is recommended that programs be
modified to eliminate the use of
deprecated APIs, although there are no
current plans to remove such APIs
entirely from the system with the
exception of JVMDI and JVMPI.
There is a long listing of performance improvements in the Java SE 6 Performance White Paper.
Java classes are forward compatible , e.g. classes generated using 1.5 compiler will be loaded and executed successfully without any problems on JRE 1.6. Generally your classes genereated by today java compilers will be compatible with future JREs (for example Java7)
The inverse does not hold : you can not run classes generated by 1.6 on older JREs (1.3, 1.4, etc).
Java compilers specify source and target compliance levels. This way, you can compile for any JRE from any other higher-versioned JRE. You need to make sure to use these compliance levels because there are API differences between JREs. For example, JRE 1.5 introduced StringBuilder at the compiler level. This means any time you do:
String s = "string1" + "string2";
The compiler changes it to:
String s = new StringBuilder("string1").append("string2").toString();
Obviously, this will break with a NoClassDefFoundError when you attempt to construct the StringBuilder.
Theoretically, nothing. The JVM is supposedly backwards compatible. Myself, I've never had a problem in that direction.
Depends entirely on what parts of the java library you are using. It could be anything from 'absolutely fine, no difference whatsoever' to 'OMG!! WHY HAS IT JUST FORMATTED MY HARD DRIVE??' (Well, perhaps not this second one, but it serves to support the point of it going from nothing to possibly bad :)).
Your class could also pick up on bug fixes in the library as well, which would mean niggling bugs disappear (or could be introduced depending on if you were relying on buggy behaviour or not).
AFAIK though, the java bytecode is backwards compatible so you shouldn't get any issues with it just not doing anything.
One positive consequence is that the 1.4 classes will still take advantage of speed improvements made to the JVM (although not necesarily improvements made to library classes).
just ran into a problem like this myself. I was writing code that should work with 1.6 but the college had 1.3 installed. Lots of methods just don't work i.e
input = ""+ JOptionPane.showInputDialog(null,"Enter a four digit number to " + (b?"encrypt":"decrypt")+".",(b?"4086":"5317"));
wouldn't work but
input = ""+ JOptionPane.showInputDialog(null,"Enter a four digit number to " + (b?"encrypt":"decrypt")+".");
would. the inputdialog method that accepts three agruments doesn't seam to exist in 1.3.
this is just a long winded way of saying working with 1.6 api on 1.3 results in head slamming incidents.
It should work. I don't remember encountering any problems with it, except when parts of the Java API are deprecated, in which case it'll explain what they are anyway and you can hopefully write a workaround.
Of course, running a class file compiled with JDK 1.6 in JRE 1.5 would cause a problem - even a JRE only minor build revisions older will throw an error.

Categories