Consequences of running a Java Class file on different JREs? - java

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.

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.

When Does The JDK Compile Version Matter?

I have two Java artifacts being built. One needs to be built in 1.6, because PowerMock isn't compatible w/ 1.7 and we are using it in a lot of unit tests. Refactoring PowerMock out right now isn't an option as it will take too much time.
However, I want to use this artifact in a Java application built in 1.7 and run the whole thing in 1.7. I think that it should be Ok since it is just building some class files, which I doubt changed much if any probably as far back as 1.2 or earlier. Anyway, I obviously have a fuzzy understanding of this and I am interested to get a Java experts deep dive explanation as to when this would matter, when it wouldn't, and why.
Thanks!
Java is usually backwards compatible between versions so anything compiled on an old version should run fine on a newer JVM. In fact a lot of common libraries are compiled in as old a version as possible (usually Java 5 now a days) unless they need a newer feature to allow more people who are still stuck on old JVMs.
Having said that, there are a few gotchas you need to worry about. One problem I had on some Java 6 to 7 conversion was TreeMap with an initial value of null http://hariharanselvarajan-java.blogspot.com/2013/02/treemap-in-java-6-and-java-7.html
EDIT
Here is a link to Oracle discussing what isn't compatible between 6 and 7 although I would imagine this only affects things that are recompiled: http://www.oracle.com/technetwork/java/javase/compatibility-417013.html
The compiled code should be backwards compatible, so if you run it all on java7 it shouldn't matter than some was compiled using java6.
When you try the other way you get an invalid major/minor version number error.
I would assume that you can mix & match java 6 and 7 code too, just as you can (with caution) mix and match pre & post generics java.

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

How many people still use JRE 1.5 or older?

Is there some statistic on how widely people use various JRE's? I'm asking, because I created a program (using JDK 1.6), and found that it would not work on JRE 1.5 and older. So, do I need to bother making it compatible, or maybe the percent of JRE 1.5 out there is too small?
Here is some stats:
http://www.statowl.com/java.php
Don't really know how it's calculated... I think come from users browser, but don't know which websites.
You need to have your JDK emit bytecode for older JVMs with the -target SDK_VERSION argument to javac. Bytecode from one version of the JVM is not compatible with an older release of the JVM.
Thanks to comment
The above only works if you are not using functionality that older JVMs don't have, for example, if you took advantage of the Java Desktop API, which was introduced in 1.6, you wouldn't be able to target an older JVM anyway.
I won't throw statistics your way, I don't really know what your application is/does/who it's intended for, but there are companies and people who still use older JDKs - perhaps due to heavy investment in some specific release of the JVM and it would require significant time and testing to ensure that moving to a newer version does not break their existing software/code, or perhaps some software strictly mandates it. I worked with software from a company (which shall remain unnamed) that ONLY wanted a specific patch revision of an older JVM - their software refused to work on anything newer.
Um yes plenty of enterprises use earlier versions of Java. You simply need to decide what your lowest level target JVM is. Don't forget you can use the -source & -target parameters to specify the type of source code and byte code compatibility with earlier versions.
I don't know of any statistics, but for what is worth I am certain people use Java 1.5. If your app is geared toward general public, I don't think you need to bother, but in specialized environments it might be.
If your application will be for consumers, you will probably be fine relying on 1.6.
Most places that are still running 1.5 are for business applications that have not been updated.
If you're not using any Java 1.6 specific features, you can pass a command line argument to javac to target the 1.5 framework. The argument to add is -target 1.5. Obviously this wouldn't work if you're using any new features shipped with 1.6.

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

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.

Categories