Compatibility and migration from Java 9 to Java 8 - java

I'm reading the document about the new Java 9 module system.
The paragraph 3 Compatibility & migration explains how to migrate code
from Java 8 to Java 9, but says nothing on how "migrate" or run an application
written in Java 9 to pre Java 9 runtimes.
So, if I have, say a JAR application written in a modularity way (every module has a module descriptor) what does happen if I deploy it on, i.e, a JDK 8 runtime?

If your class files are compiled with --release 8 flag, then they should run fine on Java 8. module-info.class files will be ignored by the older JVMs.
If your Java 8 project is maven-based, you can easily configure it to include module-info.java: https://maven.apache.org/plugins/maven-compiler-plugin/examples/module-info.html
Also, take a look at JEP 238 (Multi-Release JAR Files). This allows you to take even more advantages of Java 9 features without breaking compatibility with Java 8.

You cannot start a Java application with a JRE which is less than the one it is built for.
If you just use javac without any special options it will produces classes which do run on JREs equal or bigger than the one of the used JDK.
However javac supports cross compilation. You can use JDK 8 to compile JDK 6 compatible class files. Search for Cross-Compilation Options in the javac docs.

Java Class files contain version information. As with any Java version it should not be possible to execute a class file (or jar) that was compiled with a newer major version than your runtime. See: https://stackoverflow.com/a/4692743/6239524

Related

How to deal with multiple jre and a single jar file

I am currently working on a java program, but I feel a little bit lost about how to run the jar file on multiple OS which don't have the same jre version.
Let me explain :
The program I am developing is written in 1.7
The client need it to work on Mac OS (jre 1.6) and Windows (jre 1.7)
I generate a .jar executable file using Maven in Eclipse
How can I make it run on his MAC OS and Windows at the same time ?
Is there a way to export the corresponding jre with the jar file ?
Thanks !
You are a number of distinct questions here.
The program I am developing is written in 1.7. The client need it to work on Mac OS (JRE 1.6) and Windows (JRE 1.7)
As a general rule, if a Java application can be compiled for an older platform (e.g. Java 6), then the compiled code should run on a newer platform. But the converse does not apply. There are two main reasons for this.
The Java .class file format is versioned, and a newer JRE can load classes with an older format. But an older JRE cannot load class with a newer format.
Moreover, the changes to the class file format are made to support new language features. So if your source code uses features added in (say) Java 7, then you won't be able to compile the code to run on (say) Java 6.
Each version of Java adds new classes and interfaces to the class library, and adds new methods to existing classes. If you compile code against the Java 6 SE APIs, then it should be compatible with a Java SE 7 platform. (All the required classes should be present.) However, if you compile the code against Java 7 SE APIs, the code may have dependencies on classes and methods that don't exist in Java 6.
In short, if you want your application to run on Java 6, you need to compile it and test it on Java 6. You also need versions of all of the application's dependencies that are compatible with Java 6.
The other aspect of the above question is supporting different operating systems (Mac OS and Windows). If your application is Pure Java and doesn't have threading problems, it should be OK. Problems arise if:
your application depends on platform specific things; e.g. pathname syntax, external commands, native libraries, or
your application includes native code, or uses Unsafe or abstraction breaking reflection, or it depends on JRE internal APIs, or
your application makes unwarranted assumptions about the thread scheduler, or doesn't strictly follow the rules governing memory visibility (defined in the Java Memory Model), or
your application uses 3rd-party libraries with any of the above issues.
I generate a .jar executable file using Maven in Eclipse
The way that you generate the JAR file doesn't matter. What matters is what Java target the code was compiled for and what Java APIs it was compiled against.
Is there a way to export the corresponding JRE with the JAR file ?
Not with Java 6 or Java 7. The JRE is not part of the JAR file. For this vintage of Java, the options are to get the client to install a JRE as separate step, OR create an installer that will install both your application and the JRE that it requires.
Java 9 introduced a new utility called jlink that will generate a self-contained Java installable from JAR files. These don't require a separate JRE because they have a cut-down JRE as part of the installable.
Finally, a word of advice. Consider carefully whether supporting a Java 6 customer is really in your long term interest
Both Java 6 and Java 7 are end of life. Furthermore, many providers of 3rd party libraries have stopped supporting versions prior to Java 8. This can present serious problems (even show stoppers) if you undertake to support a client who needs Java 6.
In addition, supporting this client will mean that your application codebase will be unable to make use of the new language features and improved APIs in Java 8 and later. Some of the more important language and API changes are:
try-with-resources (Java 7)
Lambdas, method references, type inference, streams and improved date/time handling. (Java 8)
Modules (Java 9)
var (Java 10)
Records (Java 15)
This is liable to lead to your codebase becoming increasingly old fashioned, and in need of a rewrite.
Check the maven-compiler-plugin: https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html but keep in mind that if you're using Java 7 features (e.g try-with-resources), the code will fail when your client(1.6) runs it. So I would suggest to use both source and target as 1.6.

Eclipse Java - Set compiler to Java 6 but still have Java 7 methods/libraries and no complains

For a project I must use Java 6, so I set my eclipse compiler setting to 1.6 (JDK compliance level).
However, I included java.nio.file.Files which is a Java 7 library and I am not getting any complaints. I can ensure that my project specific setting is set to 1.6. I even changed my entire workspace to 1.6 and rebuilt, still no complaints. My colleagues are seeing the complaint on java.nio.files.
Is it becuase I have a jdk7 which is recognizing the java.nio.file.Files even when set to 1.6 spcs?
These are two different things:
the compliance level is about the syntax that you can use when writing Java code (respectively about the Java version number that gets put into compiled byte code)
but the libraries that are available to you depend on the JDK that your project is using!
In other words: if you truly want to restrict your project to Java 6 libraries, you will have to install a Java 6 JDK on your system, and point to that within your project setup ( most likely, your current project setup makes use of a newer-than-Java-6 JDK ).
And the usual disclaimer: Java 6 has had end of life many years ago. You should do whatever you can to upgrade your setup.
JDK compliance level is the level of the Java syntax, not the runtime libraries. It will just prevent you from using language features that were introduced in later versions like try-with-resources which was introduced in JDK 7.
If you want to develop for JDK6, you need to use JDK6.
Java 6 is able to interpret java.nio.file.Files because there is no special Java 7 syntax in contrast to Java 7 and Java 8 (lambda expressions etc.). So you are working on standard libraries. Uninstall Java 7 JDK and install Java 6 JDK and you will that java.nio.file.Files is not available anymore.

Jar compatiblity with Java 8

I'm doing some upgrade work now. From java 7 to java 8, and also upgrade some jar files. How do I know if the jar file is compatible with java 8? Is there any website telling that?
Classes that were compiled with Java 7 almost always run on Java 8. This is backward compatibility requirement. However, there are some incompatibilities that are documented here
If there is some issue with a particular library, you should look for this information on the library's website.

Can call java 7 compile java code from java 6 compiled code

I have program compiled on java 6. And library compiled on java 7. Can I call from java 6 compiled code to java 7 compiled code or I will have run time errors. I know that I will have errors on compilation, but i will change jar after compilation. I run my application on jvm 7.
In general Java 7 is backward compatible, so you can use libraries compiled with Java 6.
For example: If your library compiled with Java 6 uses a javax package, it will use the library comming with Java 7 and compiled with Java 7.
I use Apache CXF 2.4.6 (compiled with Java 5) with Java 7. Apache CXF calls Servlet API (compiled with Java 6) of JBoss 7.
Yes, you can, but there are issues with the classfile formats; see this question for the exact mapping of Java versions and classfile format versions.
Specifically, if you have source code A that you are compiling with JDK 6 but you have JAR in the compilation path that has .class files that are with major version 51, then the compilation will fail because the compiler will not be able to load the class files.
However, when compiling you can specify a '-target 1.6' flag so that the generated classfile is compatible with Java 6. If you have access to the source of your library you can recompile it with that target so that it's compatible with a 1.6 compiler.
Lastly (and obviously), the classfile format version must be understood by the JVM.

About VM/Jar versions

A jar is being ran with JVM 8 , which is compiled with java 6.
Can this jar load another one as a 'library'/plugin that is compiled with java 8 which has
dependency the first jar?
Sure, it can. You can mix jars compiled against different Java versions.
Also note that there's couple of things when talking about Java version used. One is the Java Class Library you compile your code against. This defines APIs you can use in your code.
The second thing is java bytecode version. You can instruct Java 8 to compile code to be Java 6 binary compatible. This doesn't mean that your code will execute against Java 6 though. If you use calls/classes added in Java 7 or 8 then you will hit problems at runtime.
These two are the most important aspects when talking about Java compatibility. Google for Java compatibility or Java source vs. binary compatibility to get more info on the subject.

Categories