How to deal with multiple jre and a single jar file - java

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.

Related

Testing for Java SDK

I am writing an application in Java. Does a Java SDK have to be installed to run the application from the command line? If so, can I package the SDK with the application to be installed when installing the application?
From Java 9 onwards you can use jlink to produce a custom JRE for your application. The JRE includes a copy of the java command and (only) the libraries / classes that your application needs. It will be platform specific.
From Java 14 onwards, you can use jpackage to produce (platform specific) native executables for Java applications.
There are also 3rd-party tools that can generate executables, and third party installer generators that (in some cases) can install Java for the end user.
Note: if you take the approach of distributing your application as a self-contained JRE or native executable, the user no longer has the option of updating their Java to address security related issues. It becomes your problem / responsibility ... as the supplier of the software ... to make available in a timely fashion application updates that incorporate the new Java releases with important security patches.
If you use something like GraalVM to compile a native binary, then there is nothing more you should need for a simple application (meaning, nothing is tried to dynamically load classes at runtime with reflection)
Other than that, the Java JRE is required, and can be included as part of an application package; for example, IntelliJ or Eclipse IDE come with their own JRE.
Thanks everyone for your input.
After doing more research I found that by using a jdk greater than 8.?, it is possible to bundle everything an application needs in the deployment process.

Why aren't there compatible JREs for JavaSE12+?

I am getting an error when trying to run a .java file as a Java Application and I get the following error:
Unbound classpath container: 'JRE System Library [JavaSE-14]' in project <project_name>
I tried to change the execution environment and for JavaSE12 and later versions there are no compatible JREs. (But for JavaSE11 the compatible JRE is java-11-openjdk-amd64)
I do not know what to do because the project I am working on doesn't work with old Java versions. How can I choose an environment for the latest Java versions?
Note: I am using Ubuntu 20.04 if that makes any difference.
tl;dr
I am not a Linux user, so I may not know best. But I suspect the simplest approach to running your .java file is to:
Obtain and install a JDK for Java 15 for Linux
Call java app on the command-line, passing the path to your .java file.
Backwards-compatibility is a priority for the Java team. Most any existing Java app should be able to run with the latest version of Java. There are exceptions, but they are very few.
JRE is passé
The JRE (Java Runtime Environment) was a subset of the JDK (Java Development Kit), omitting some of the programmer tools. The JRE as a separate product seems to be getting phased out.
Oracle and much of the Java community has shifted away from the idea of regular users having Java installed on their personal computers. Instead, apps should be delivered with a JVM specific to their host platform bundled within the app. This bundling of a JVM can be done using newer tools such as jlink and jpackage.
For more info, read:
Java Client Roadmap Update - Oracle (2020-05)
Java is still Free
Obtain a JDK
You said you have a .java file to execute. That file must first be compiled before it can be executed. The more recent versions of the java app can do both steps at the same time, compile & execute.
First download and install a JVM for your host platform.
Java 11 is the current long-term support (LTS) version. Java 15 is the latest release. You may want to read about the six-month release cadence for Java.
You have a bounty of vendor choices providing implementations of Java. Here is a graphic flowchart I made to assist in choosing a vendor.
If the steps shown here are overwhelming, I suggest either:
Using apt-get or similar package installer to obtain a build of OpenJDK for Ubuntu. I am not a Linux-user, so I do not know the details.
Head over to AdoptOpenJDK to download an installer for Linux.
Some motivations to consider in selecting a vendor.
Compile & run your app
Once your JDK is installed, on a console (such as Terminal.app in macOS), run something like the following. The java command should both compile and execute your .java file, if that single file makes up your entire app.
java /path/to/some/folder/MyJavaApp.java

Compatibility and migration from Java 9 to Java 8

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

Java development kit 1.7 and earlier version compatibility

I am currently working on java 1.7 standard version, and I am really fun of the new features:
Nio(new input out put)
non redundant code with collections
...
I want to know if there is a way to switch the class I want to execute depending on the version of (JRE)java runtime environment it will be deployed.
You first need to create some sort of launcher app in order to check the JRE version of the environment, then you can lauch the JAR compiled for those version of the JRE. Your code cannot be compiled to newer versions of the JRE and be executed in an older one. That's why you need to complie the launcher app targeting a very old JRE.
As a side note, you can obtain the JRE version in which your program is running using:
System.getProperty("java.version")
The Java class file(s) are almost always binary compatible with new versions of the language (and the few exceptions, like using enum before the keyword was added, are fairly rare). If you restrict your usage of features to the "lowest common denominator" it is possible to compile back to an arbitrary version. That being said, Java 7 is now quite long in the tooth and I've found Java 8 to be remarkably stable. Finally, if you do choose to use new language features (like lambdas) you cannot use the earlier version of the language.
You can create two compiled build for both version to use language feature differently and have them running on jre 7, but you should just upgrade code compatibility and runtime to 1.8 (Even better)

Can I distribute a JDK with my application?

I am working on an application called Enchanting. The application, based on Scratch, emits Java source code and compiles it for uploading onto LEGO Mindstorms NXT Robots.
While the application is very early, users have a hard time installing it.
Right now Windows users have to:
download and install a Java Developer Kit
download and install LeJOS (a java library for the NXT)
possibly tweak environment variables
then they can download, install, and run Enchanting itself
If I could provide an installer that would include the JDK, and LeJOS, I could figure out the environment variables at run time, and the process becomes:
Download, install, and run Enchanting
Is there a way to redistribute a JDK?
(Incidentally, Processing (a simplified text-based programming environment) seems to offer a version that comes with the JDK, so it appears that there is a legitimate way to do so).
Addendum: I would like a Windows user who does not have java installed to be able to run a single .exe file to install the JDK, LeJOS, and Enchanting.
The information regarding redistribution is here for Java 10 JDK and here for Java 8 JDK. Currently Java 8's is substantially more detailed than Java 10's.
and you can use PackJacket, to package all the files you need and create an installer.
Assuming you satisfy all the legal terms required to distribute stuff, you can use izpack to install all the prerequisites, including a JDK/JVM and configuration of environment variables.
Quite a number of IBM Eclipse based tools have JDKs with them.
Or you could just emit bytecode directly. You could bundle a much smaller (than the JDK) JVM dynamic language then use it to compile to bytecode or use libraries made for that purpose.
(I got the following from the Projects using Kawa page)
App Inventor for Android uses Kawa to translate its visual blocks language.
...The Nice compiler (nicec) uses Kawa's gnu.expr and gnu.bytecode packages to generate Java bytecode. ...
It's this last one is the one that uses the Kawa language framework to generate bytecode.
Don't forget about Groovy, Jython, Clojure, and Ruby. Interesting fact about Groovy, the interpreter can compile Java code since Groovy is (more or less) a superset of Java.

Categories