If I compile an application using Java 5 code into bytecode, are the resulting .class files going to be able to run under Java 1.4?
If the latter can work and I'm trying to use a Java 5 framework in my Java 1.4 application, is there anything I should watch out for?
Nope! .class files are forward compatible only. Java 5 introduced new classfile attributes and format changes, to handle Varargs, enums, and generics. Java 4 would just fail when processing these.
However, there is the unsupported -target jsr14 option on javac that generates JDK 1.4-compatible bytecode for some Java 5 language features.
Also, there are projects (e.g. Retroweaver, Retrotranslator) that convert Java 5 classfiles into Java 4 files.
EDIT: I found this good resource: Using Java 5 language features in earlier JDKs
No. You can only move upwards - Java 1.4 bytecode will work on Java 5 runtimes. However, if you aren't using any functionality not found in Java 1.4, you can compile using the -target and -source options of javac.
If you want to use Java 5 to write an application that can be run on Java 4, you can't use any features that weren't present before Java 5.
No they are not. .class files are forward compatible only.
Java5 framework implies that your library is probably using generics or annotations that are incompatible with your 1.4 environment. You have to evaluate how much risk there is for you to run your 1.4 application under a 1.5 JVM to enable use of the frameworks you require.
In general I've found moving to 1.5 to be mostly painless, but diligent testing is called-for.
Related
The target system, on which my application is supposed to run, uses Java 6. On my development machine, I have Java 7. Can I do the development, without downloading Java 6?
I found on http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html one example for cross compilation:
javac -source 1.6 -target 1.6 -bootclasspath C:\jdk1.6.0\lib\rt.jar -extdirs "" OldCode.java
However, this too requires the existence of a rt.jar, which belongs to Java 6. Is there a simpler way?
New Java versions generally change both the Java Language (source and class file format) and the Java API.
The Java compiler can emit class files in the old format, even if the source is in a new format (these versions are specified by -target and -source, respectively). Therefore, you don't need the old compiler to target an old JVM.
However, the changes to the Java API are somewhat harder to account for. The easiest is to compile using the API of the Java version you target (-bootclasspath). Of course, you may feel confident that you are not using newer APIs, and skip this step, but the only way to make sure is actually compiling against, and testing on, the old runtime library.
In short, while cross compilation is helpful in that the same source can be used with different Java versions, you should compile and test against the actual Java version you intend to use, which does require the old JRE (or JDK).
BTW, all of these settings are also available in Java IDEs. For instance, in eclipse, one would set the compliance level in the project's compiler settings, and add the appropriate "JRE System Library" to the project's "Build Path":
The below command should suffice to meet your requirement.
'javac -source 1.6 -target 1.6 OldCode.java'
With this command you are telling that the compiler should generate class file that is compatible with java 6. Any java 7 specific will result in compilation error. Regarding rt.jar, you don't need to have java6 specific version. As mentioned the above command automatically ensures output is java6 compatible.
UPDATE/CORRECTION:
After going through the following link http://www.javaworld.com/article/2077388/core-java/what-version-is-your-java-code.html it is clear why it is recommended and is important to use -bootstrap flag along with -source and/or -target flags.
I try to write my code compatible with older versions of java, so it will work everywhere.
on the other hand there is very powerful tools in the new version - java 8, and I want use them.
So I'm forced to choose between compatibility or richest code.
And I'm wondering if by any chance I can write some methods in java 8, and somehow prevent the compiler of older version to ignore these methods, so my class is compatible "partially" with older version.
Thanks.
You can write two classes and use some toll like ant, maven or gradle to chose which file use for compiling with concrete Java version.
You can set the java compiler to compile against an older jdk (ie jdk 1.5) even if you use jdk 1.8. see javac source and target options
I think the short and easy answer is no.
See this thread: Can Java 8 code be compiled to run on Java 7 jvm?
You can use the java reflection api to check if methods exist in the jvm the code runs on. This allows you to make your code fail-safe even when a method or class is unavailable in the jvm. Doing this is very cumbersome however and I'm pretty sure it's not what your're looking for.
When I programme I don't take care if I'm using the features in Java 7 or Java 5. But as far as I think if I use only Java 5 features my complied byte codes should be run also on a JRE version 5. But how can I check if my compiled code will be compatible with JRE v. 5 or even earlier or no.
I'm interested to know the answer of this question more generally for Web and Enterprise applications.
You can compile your code with a specific version using the -target option
Try compiling with different targets to see which compiles and which doesn't
http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html
My question is if Java JDK and JREs have to be compatible to run?
I mean: will Java applications written using JDK version 8 in future work with current JRE's?
It is possible to use cross-compilation options when compiling. Do that and it will be possible to compile code with SDK 8 that is compatible with Java 1.1. It won't be very advanced code for 1.1, but it will run.
The short answer is No.
If you develop your application in JDK 8 and run it with JRE 7, you would get an UnsupportedClassVersionError.
This question is two part:
JDK vs JRE
forward / backward compatibility.
JRE is the acronym for Java Runtime Environment. JDK is the acronym for Java Development Kit: a set of tools which you use to develop Java programs. The JDK also contains a full JRE. In general there is no compatibility issue between the two. But you might want to take care not to use libraries which are only available in the JDK (for example code generation or the tools.jar)
Java itself is compiling to bytecode, which is forward compatible. That means you can use bytecode of any Java version and run it with any newer version. The other way around generally doesn't work and is checked by using the class file version ("java.lang.UnsupportedClassVersionError: Test : Unsupported major.minor version 51.0").
Then there are Java libraries, including the core libraries. So far there was never anything removed from them, so they are forward compatible. This is probably going to change with Java 9 where a very small usually unused library functions are removed.
Regarding to backwards compatibility, this is possible by setting the Java compiler to produce Bytecode of an older version. Up until Java 8, the compiler was always able to produce bytecode of the last two major versions as well. However, you might successfully compile a Java 8 source to Java 6, but not be able to run it. That is the case when you use libraries that are only available on a never Java. For such cases there is for example the maven animalsniffer plugin which will verify that when you compile against an older version, you actually only use libraries existing in said version.
Why can't the Java compiler compile Java 1.5 source code (with for-each loops for instance) to Java 1.4 bytecode?
I know that you can provide a -target 1.4 switch, which tells the compiler to produce 1.4 compliant bytecode, but this requires -source 1.4 as well.
$ javac -target 1.4 -source 1.5 Test.java
javac: source release 1.5 requires target release 1.5
I'm taking a course in compiler construction now, and as I understand it, compilers transform the source code into an intermediate representation anyway. Why can't such intermediate representation be output as 1.4 compliant bytecode? It sounds like an easy enough task, since, for each loops, varargs etc are basically just syntactic sugar!
(Note that I can see that API classes introduced in Java 1.5 obviously can't be referred to when executing on a 1.4 JVM. I'm still interested in the situation in which you stick to the 1.4 API.)
Because Java 1.5 provides features that are simply not present in a 1.4 VM.
What should the compiler do if your source contains generics? Or an enum definition? What if it does autoboxing?
There are workarounds for all of these issues, but it's not the job of the Java compiler to implement workarounds. Instead you either need to port your source to a Pre-Java-5 level or use a tool such as Retroweaver (there's a more modern replacement for that out there, but I keep forgetting its name, since luckily I no longer need to use it).
Also note that Java 1.5 code that doesn't use any of the new features (enum, auto-boxing, generics) most likely can be compiled using -source 1.4.
You are correct that some enhancements in Java 1.5 did not involve the introduction of any new bytecodes or class file format changes. There are others like annotations and enums that did. Therefore arbitrary Java 1.5 source cannot be compiled to a valid Java 1.4 class. That being said there is a project named retroweaver that aims to transform Java 1.5 class files to Java 1.4 class files available at http://retroweaver.sourceforge.net/.