Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 months ago.
Improve this question
I write a few small, free, desktop command-line applications in Java. I package those as JAR files in releases on GitHub. About a year ago in light of Oracle licensing changes, I switched from the Oracle JDK to Open JDK. Developing on Windows, this is what I currently have installed:
C:\Users\admin>java -version
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12-39)
OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)
Now, about a week ago I was visiting a friend (also a software developer) and a reason came up where we wanted to run my application on his Windows box. He didn't have Java installed. So, watching over his shoulder, he went to the java.com "Download Java for Windows" page (currently listing Java Version 8 Update 341), downloaded, and installed it.
Then when he went to run my application, it failed to run, giving back an error along the lines of (paraphrasing from memory), "This version of the JRE does not support a later version of Java". This surprised both of us; he didn't know there was a later version of Java, and I didn't know compiling with the current OpenJDK would make a non-supported binary.
What's the best practice to fix this release problem?
Your user most likely ran into the issue that Java classes compiled with a newer class file version number do not run on older JVMs. If that is the only issue it can be addressed by recompiling ...
But there is a deeper issue. Older Java class libraries don't support all of the APIs provided by newer versions of Java. Also there have been some important architectural changes starting in Java 9 (e.g. addition of modules, removal of applets and closing off access to JDK internal classes) that "break" applications that run on older Java versions
What this means is that if you develop and test your code on Java 17 (say) there is a significant chance that it won't work on (say) Java 8 ... even if you compiled it for Java 8. And vice versa, because some APIs have been removed, or made inaccessible or ... work differently.
So my advice would be:
Decide on a specific range of Java versions you will support for your application; e.g. Java 8 LTS1 through Java 17 LTS.
Develop targeting the oldest Java version and its APIs.
Build and test on the Java oldest version.
Also test on (at least) all of the other LTS Java versions ... within the range you are supporting.
This will mean that you are limited to using the APIs and Java language features of your oldest supported version. This could hold you back, so you have to choose between that and supporting users with old (out of date) versions of Java.
The issue of users trying to install / use old versions of Java can be addressed in three ways:
Provide clear installation instructions to the user that say what kind / version(s) of Java they need to install, and where to get them from. (And how to set or configure JAVA_HOME if your application relies on that.)
Of course, some users won't read the instructions properly, but that is their lookout ...
Use jlink to turn your application into a custom JVM, and distribute your code that way.
Use jpackage to create platform specific binaries.
If you take the jlink or jpackage routes, the onus will be on you to push out new distributables whenever there are Java security patches that are relevant to your application. Your users won't be able to "just install the latest Java patches" anymore.
Note that jlink is available for Java 9 onwards, and jpackage from Java 16 onwards.
What JDK should I compile with to support most desktop users?
I don't think there is a good answer to that. We can't tell you what proportion of "desktop" users have each version of Java installed. (Or what they are permitted to install; e.g. by corporate policy.) But you can't support old Java versions indefinitely.
I did find this though:
Java 8 still dominates, but Java 17 wave is coming – survey - dated March 2022.
1 - Java 7 and earlier are all well beyond "end of life". You are not helping anyone by trying to support them.
Well, you have a few options...
First of all you can TARGET the version 8 runtime, but you can compile code from later revisions of the language. This may or may not work in all cases, as Java 9 and up do some things rather differently! Still, fairly vanilla Java that isn't doing weird ClassLoader stuff is LIKELY to work, and you can certainly avoid problematic constructs.
Secondly, you can simply stick to Java 8! It is ANCIENT but it is a virtually immortal LTS, due to the reason above that things in Java 9 are different. However, you will miss out on new things.
You COULD go whole hog and move on from Java 17 to GraalVM, which can be had in versions compatible with Java11, Java17, etc. It has the ability to compile code down to a completely stand-alone binary, using native-image, and again unless you do some fairly esoteric stuff, your code will work. The end result will be similar to using something like C++. You can even build shareable libraries.
I guess your other option is to just make sure people are not using Java8. Ideally they're using Java11, but I guess now java17 is the newest LTS, though few people seem to install it.
It looks like you are using Java 17. Developers of apps targeting Java version after 8 are expected to supply the runtime for running the application. This means there is no more 'downloading and installing Java' separately on the user side. This is also why the download page you refer to only offers Java 8.
In practice, this means that you should use jlink to create a runtime image (i.e. the thing that you would previously download and install) that can run your application.
jpackage can also be used to create application images and installers (it calls jlink under the hood). Both of those are tools that come with the JDK.
For your purposes I recommend using jpackage with something like this:
jpackage `
--win-console `
--main-jar app.jar `
--main-class Main `
--name myapp `
--type app-image `
--input input
In this command, input is a folder that has the main app.jar in it (Note: the input folder should not be the current directory, since that will lead to infinite recursion).
--win-console is also needed for console applications on Windows, since otherwise no console is created when running the app.
This command will create a myapp folder that you can zip/tar up and distribute.
This myapp folder has a myapp.exe launcher that can be used to run the application.
Also, note that this will create a runtime image with a default set of modules. If your jar is modular (i.e. it has a module-info file), I suggest using --module instead of --main-jar/--main-class, since that will use the module descriptor to determine the set of modules in the runtime image. (See jpackage --help)
Note that on Windows you will also need to install the wix toolkit. It can be installed easily through e.g. scoop:
scoop install wixtoolset
We are switching from Oracle JDK/JRE to OpenJDK. Now I found only the JDK but I want to have a JRE as well from OpenJDK. This is for installing our application on the clients without the need of having the full JDK.
Is there a way to create a JRE package from the OpenJDK for Windows X64?
Inspired by the article Using jlink to Build Java Runtimes for non-Modular Applications I used the commands:
java --list-modules to get a list of all openjdk modules available
jlink --no-header-files --no-man-pages --compress=2 --add-modules <module-list from step 1> --output java-runtime to create a compact jre.
For OpendJDK 12 this is the command I ended up with:
jlink --no-header-files --no-man-pages --compress=2 --add-modules java.base,java.compiler,java.datatransfer,java.desktop,java.instrument,java.logging,java.management,java.management.rmi,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.se,java.security.jgss,java.security.sasl,java.smartcardio,java.sql,java.sql.rowset,java.transaction.xa,java.xml,java.xml.crypto,jdk.accessibility,jdk.aot,jdk.attach,jdk.charsets,jdk.compiler,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.crypto.mscapi,jdk.dynalink,jdk.editpad,jdk.hotspot.agent,jdk.httpserver,jdk.internal.ed,jdk.internal.jvmstat,jdk.internal.le,jdk.internal.opt,jdk.internal.vm.ci,jdk.internal.vm.compiler,jdk.internal.vm.compiler.management,jdk.jartool,jdk.javadoc,jdk.jcmd,jdk.jconsole,jdk.jdeps,jdk.jdi,jdk.jdwp.agent,jdk.jfr,jdk.jlink,jdk.jshell,jdk.jsobject,jdk.jstatd,jdk.localedata,jdk.management,jdk.management.agent,jdk.management.jfr,jdk.naming.dns,jdk.naming.rmi,jdk.net,jdk.pack,jdk.rmic,jdk.scripting.nashorn,jdk.scripting.nashorn.shell,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.unsupported.desktop,jdk.xml.dom,jdk.zipfs --output java-runtime
As others have mentioned, there's no longer a separate JRE distributed with the JDK since Java 9. You will need to use jlink and specify the modules your code depends on to generate a custom jre.
Because this can be a hassle, I've created a web-based tool to make it easier to create a custom JRE from an OpenJDK implementation (such as Oracle HotSpot, Eclipse OpenJ9, or Amazon Corretto) using jlink. The tool will give you the correct jlink command to run depending on your needs.
I've also included a way to make a standard Java SE JRE for those who just want a basic lightweight (~40-60 MB) JRE. If you know how to use a terminal, it'll take you less than 2 minutes to create a general-use JRE for JDK 9 and up.
Give it a try here - EasyJRE: https://justinmahar.github.io/easyjre/
Amazon Corretto OpenJDK https://aws.amazon.com/corretto/ has the builds for JDK and JRE
So I'm going to post something a little bit easier than what was posted by SteinarH. I didn't want to have to compile that list myself so.... this does it for you. Also for the sense of being a bit more concise I wouldn't label it java-runtime but instead jre-11 (or whatever version you are using).
This is PowerShell:
jlink --no-header-files --no-man-pages --compress=2 --add-modules $($(java --list-modules) -join "," -replace "#[0-9]*") --output jre-11
According to the Building OpenJDK document1:
Windows XP is not a supported platform, but all newer Windows should be able to build OpenJDK.
It then goes on to explain that Cygwin is required to do the build, the requirements for native compilers and libraries, and the issue of the "bootstrap" JDK that is required to compile the Java classes in the source tree.
But the clear implication is that you can build OpenJDK on Windows and for Windows ... even though the end result is not supported by Oracle or the OpenJDK project.
Note that the build document describes the make targets for creating JRE and JDK "images". I think it is saying that these are binary trees that can be copied to a target system and used. You could create ZIPs from them ...
But a simpler approach is to use "jlink" to generate a JRE-like executable; see the accepted answer.
#Andrew Henle points out that there are costs and (if you put yourself in the mindset of a corporate lawyer) risks in rolling your own JRE. Whether you just use it internally or you provide it to customers. If this is a concern, you are in a bit of a bind:
From Java 9 onwards, Oracle does not ship JRE distributions at all. Not for Oracle Java. Not for OpenJDK Java. As far as Oracle is concerned, JREs end after Java 8.
Anything that you build for yourself is a cost and a (erm) risk.
Fortunately, there are 3rd-party vendors who ship JRE distributions for Java on Windows. (Both AdoptOpenJDK and Azul do at the time of writing).
Alternatively, just use an Oracle JDK distro. Disk space is cheap, networks are fast.
1 - That link is for the Java 9 version of the document. For others, you should be able to find a corresponding "building.html" document at the same place in the source tree.
Since Java 9, you can use jlink to create a custom runtime environment for your application, using only the modules you actually need to run, which is typically even smaller than the traditional JRE was.
I'm using openjdk 11 in place of jre8 since oracle announced the license change. My customers were unhappy about them changing the agreement.
To get it to work, all I had to do was rename the sdk folder to jre.
One problem I did have was an external library dll. where open jdk complained it could no longer find in the class path. To fix that I just copied the dlls to the system32 folder.
Hope this helps
Stuart
On this site you can get jdk and jre (the jdk contains jre)
https://adoptopenjdk.net/upstream.html.
But if you need to build a jre you can use the following code in python (I have taken the answer from #SteinarH), the code assumes that you are in the jdk bin and that there is no directory called jre at the previous level.
import os
jmod_str = os.popen('java --list-modules').read()
init = jmod_str.index('#')
end = jmod_str.index('\n')
version = jmod_str[init:end]
jmod_list = jmod_str.replace(version, '').replace('\n', ',')
jmod_list = jmod_list[:-1] if jmod_list[-1] == ',' else jmod_list
cmd = 'jlink --no-header-files --no-man-pages --compress=2 --module-path ..\jmods --add-modules '+ jmod_list + ' --output ..\jre'
As far as I know the only place you can download OpenJDK for Windows is Azul website. However, they only seem to provide full JDK, so if you want just the JRE you need to build it yourself as Stephen C suggested.
For a more straightforward approach i wrote this little tool, which you can use under Windows:
https://github.com/g3t00ls/OpenJDKtoOpenJRE
I personally use OpenJDK from:
https://jdk.java.net/
It basicly does exactly what SteinarH wrote.
Currently it includes all java modules and exludes all jdk modules! A GUI to select required modules / an auto detect function for required modules for even smaller JRE's will probably be added soon!
Currently it still needs jlink, so only >=v9 JDK's will work! This could change in the future!
Reasons for making another answer:
I needed a single line to make a standard JRE to put in my Windows installer
I didn't want to have to update it when I upgrade java
Method:
I back engineered the output from the page that Justin made: https://stackoverflow.com/a/54997476/1280293 (Excellent utility)
I took the output of java --list-modules
selected only lines that start with java
removed the #versionnumber from the end of each line
joined the array into a comma separated string
appended it to jlink --output jre --compress=2 --no-header-files --no-man-pages --module-path ../jmods --add-modules
Notes:
This command assumes you have added your java bin to your path
This creates it's output directory in the folder you run the command from
PowerShell:
jlink --output jre --compress=2 --no-header-files --no-man-pages --module-path ../jmods --add-modules "$((java --list-modules | Select-String -Pattern '^(java[^#]+?)#' | % {"$($_.Matches.Groups[1].value)"}) -join ',')"
Azul Systems provides up-to date Windows JREs.
Here the link to Java 18 Windows JRE:
https://www.azul.com/downloads/?os=windows&architecture=x86-64-bit&package=jre
Amazon Corretto nor AdoptOpenJDK provide Windows JREs.
We are using the Azul distribution since Oracle decided to change its licensing and made very good experience.
Also previous versions can be found:
I have one question in my mind and I should note that I know the differences between JDK and JRE. I am not a new programmer in Java.
What I would like to ask is in Eclipse I can specify the compilation environment (correct me if I a wrong) in window> Preferences but we can also change it for a specific project.
OK. I added jre and jdk folder in the options. I can use both.
But JRE has no javac (no java compiler) in it. So how it is possible that some projects requires that I need to change to jre1.7 to COMPILE?
I was getting some minor.major version error and setting JRE solved my problem?
How can this be possible?
In fact now I realized something.
Ok the question changes a little.
I saw that these are VM not compiler. I understood.
Does JDK have also JRE in it? so if I specify JDK1.8 I am setting jre1.8 as VM and if I specify JRE1.7 I am setting jre1.7 as VM?
Is it right?
It makes confusions. Why JDK has JRE in it?
JDK has whole JRE (regular Java VM) inside, in order to allow you to run what you will develop with it.
Theoretically someone could make some small-JDK with just tools and without JRE, but it would make a whole lot more confusion as to which tools version run with which JVM version (most JDK tools needs JVM to be run). Look at you, how many people have only this problem? So it is bundled together, tools and JRE as a whole named JDK, thanks to that you have some guarantee that those JRE and tools will work together.
JRE - Java Runtime Environment - allows you to run java programs
JDK - Java Development Kit - allows you to run and develop java programs
JDK = JRE + tools for developer
Also note, that You can choose for the java compilation process two things:
compatibility with source version - this is basically the syntax you are allowed to use.
compatibility with VM version - this is the minimum VM level on which you can run the compiled binaries.
example from your post: If you have compiled something as Java 8, you can't run it on Java 7, this is the minor/major version problem you have. But the opposite (to run something for Java 7 on Java 8) is valid.
in your example JDK8 and JRE7 both are just fully functional VM's, but JDK8 has additionally (in comparison to JRE) development tools inside it.
I want to recompile an old jar file (which was compiled in java 1.2). So that there are no errors i need to compile it in Java 1.2 aswell. But havent found a jdk 1.2 which i can install on windows 7 (and 64bit).
Any suggestions?
thanks in advance!
Yes, you can set the version of compiler at compile time. And compile your java code into old versions of java.
From Oracle article : http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javac.html
Cross-Compilation Example
Here we use javac to compile code that will run on a 1.4 VM.
% javac -target 1.2 -bootclasspath jdk1.2/lib/classes.zip \
-extdirs "" OldCode.java
There are two scenarios, just compiling old code and actually developing for an old JRE.
For just compiling you don't need an old JDK, you can adjust the target language level javac compiles with the -target option (see: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html) - Although there may be edge cases that may break the compiled code if the compiler decides to select a different overload for a method that does not exist in the old JRE.
For developing old JRE compatible code, you could use above method but you run the risk accidentially using an API that isn't present in the real old JRE. To avoid that problem you need the actual 1.2 API, meaning you need the rt.jar file from a real 1.2 JRE/JDK. This can be added into your project in your IDE (and the current e.g. 1.8 JDK removed). The detailed procedure how to set this up depends on the IDE. Likewise the 1.2 rt.jar can be provided to javac, also using command line switches. Again you need no runnable 1.2 JRE to compile/develop.
My Java applet only supports 1.4 java run time(1). I am having one machine on which both Java 1.4 and 1.6 environment is installed. Is there some setting available by which I can make sure my applet will always use Java 1.4 run time when it runs?
We are using key event class private data array bData with the help of Java reflection. The data which is there in this array JDK 1.4 and 1.6 is different in both the version.
A Java application compiled with JDK 1.4 will run on JDK 1.6.
You can compile a Java application with JDK 1.6, but compatible with JDK 1.4 by configuring the 'source level'.
Although you can choose your default JDK to be safe, but it depends on your operating system. If you are on Linux, you can choose between available Java versions using pdate-alternatives --config java command (which will modify some symlinks in the hindsight).
On Windows 7:
Control Panel -> Programs -> Java
Select 'Java' tab, and View the Java Runtime Environment settings.
Ensure that your Java 1.4 entry is selected.
There's a way to force a specific installed version to run, but if one Java plugin replaces the other there might be an issue with this. See linked question for further details.
Force Internet Explorer to use a specific Java Runtime Environment install?
Are there any issues with running the 1.4 code on 1.6? If not, you should be fine. Just avoid using anything in the classpath that changed significantly between these versions. Otherwise, look [here][1]. The codebase download thing is interesting, since it lets you download a different classpath. So, regardless of the JRE version, you could force the download of a 1.4 JRE classpath, which should ensure full compatability.
Edit: found an updated guide to using previous classpaths with newer Java versions in applets, which actually seems to work:
http://download.oracle.com/javase/tutorial/deployment/applet/deployingApplet.html
Edit 2: I actually have it working, but it appears to need to download JRE 1.4 and install it, but then it will run the applet with it automatically. However, this might be suitable for your needs.
http://www.2shared.com/file/bl3Rua2e/applet.html -- extract the archive, and then run index.html inside this. All source code is included.