I'm not quite sure how I got into this mess, but for some reason I'm not able to change the current version of Java using alternatives. I can run alternatives --config java and type my selection but when I echo the version number for either java or javac, it spits back out 1.5 every time (despite alternatives showing the current version is 1.6). The server I'm working with is running RHEL5, by the way.
I have verified that the paths used in alternatives are pointing to the correct directories. Here's some output from my session:
[brilewis#myserver]$ sudo
/usr/sbin/update-alternatives --config
java
There are 3 programs which provide
'java'.
Selection Command
** 1 /usr/lib/jvm/jre-1.4.2-gcj/bin/java
+ 2 /usr/java/jdk1.5.0_10/bin/java
3 /usr/java/jdk1.6.0_16/bin/java
Enter to keep the current
selection[+], or type selection number: 3
[brilewis#myserver]$ java -version
java version "1.5.0_10" Java(TM) 2 Runtime
Environment, Standard Edition (build
1.5.0_10-b03) Java HotSpot(TM) Server VM (build 1.5.0_10-b03, mixed mode)
[brilewis#myserver]$ sudo /usr/sbin/update-alternatives --config java
There are 3 programs which provide 'java'.
Selection Command
** 1 /usr/lib/jvm/jre-1.4.2-gcj/bin/java
2 /usr/java/jdk1.5.0_10/bin/java
+ 3 /usr/java/jdk1.6.0_16/bin/java
Enter to keep the current selection[+], or type selection number:
UPDATE: The following is the output of echo $PATH:
/usr/java/jdk1.5.0_10/bin:/usr/local/apache-ant-1.7.1/bin:/usr/local/apache-tomcat-6.0.24:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/NX/bin:/home/brilewis/bin
UPDATE (4/26/10): I followed Bert's suggestion and removed JAVA_HOME from the PATH environment var in /etc/profile. After doing this, I was able to use alternatives to change the version of Java. The only problem is that when I try to run javac, I get "-bash: javac: command not found". This does not happen when the version is set to 1.5.
For Oracle Java 6u30, once you've installed their RPMs you can configure alternatives:
/usr/sbin/alternatives --install "/usr/bin/java" "java" "/usr/java/default/bin/java" 2 \
--slave /usr/bin/javac javac /usr/java/default/bin/javac \
--slave /usr/bin/javadoc javadoc /usr/java/default/bin/javadoc \
--slave /usr/bin/jar jar /usr/java/default/bin/jar \
--slave /usr/bin/keytool keytool /usr/java/default/bin/keytool \
--slave /usr/bin/orbd orbd /usr/java/default/bin/orbd \
--slave /usr/bin/pack200 pack200 /usr/java/default/bin/pack200 \
--slave /usr/bin/rmid rmid /usr/java/default/bin/rmid \
--slave /usr/bin/rmiregistry rmiregistry /usr/java/default/bin/rmiregistry \
--slave /usr/bin/servertool servertool /usr/java/default/bin/servertool \
--slave /usr/bin/tnameserv tnameserv /usr/java/default/bin/tnameserv \
--slave /usr/bin/unpack200 unpack200 /usr/java/default/bin/unpack200 \
--slave /usr/share/man/man1/java.1.gz java.1.gz /usr/java/default/man/man1/java.1.gz \
--slave /usr/share/man/man1/keytool.1.gz keytool.1.gz /usr/java/default/man/man1/keytool.1.gz \
--slave /usr/share/man/man1/orbd.1.gz orbd.1.gz /usr/java/default/man/man1/orbd.1.gz \
--slave /usr/share/man/man1/pack200.1.gz pack200.1.gz /usr/java/default/man/man1/pack200.1.gz \
--slave /usr/share/man/man1/rmid.1.gz rmid.1.gz /usr/java/default/man/man1/rmid.1.gz \
--slave /usr/share/man/man1/rmiregistry.1.gz rmiregistry.1.gz /usr/java/default/man/man1/rmiregistry.1.gz \
--slave /usr/share/man/man1/servertool.1.gz servertool.1.gz /usr/java/default/man/man1/servertool.1.gz \
--slave /usr/share/man/man1/tnameserv.1.gz tnameserv.1.gz /usr/java/default/man/man1/tnameserv.1.gz \
--slave /usr/share/man/man1/unpack200.1.gz unpack200.1.gz /usr/java/default/man/man1/unpack200.1.gz
Then activate the configuration:
/usr/sbin/alternatives --config java
And select /usr/java/default/bin/java from the menu.
Plus you must gzip the man pages
gzip /usr/java/default/man/man1/*.1
Also, the Oracle java RPMs might have clobbered your alternatives symlink so force it to be normal.
ln -sf /etc/alternatives/java /usr/bin/java
I can change the default Java on CentOS using these steps:
Add the IBM JDK:
alternatives --install /usr/bin/java java /opt/WebSphere/AppServer/java/bin/java 3
Set the new IBM JDK as default:
alternatives --config java (then select #3 in the list)
Type java -version at the prompt to see the result.
The only way I was able to solve the problem was to start over again by removing /var/lib/alternatives/java and installing each JDK again. I did the same for javac and jar. After doing this, I was able to switch between versions without any issues.
alternatives works by changing a symlink in the /usr/bin directory. However, if your path contains a valid executable earlier in the path, that will be used instead.
In this case, judging from your previous comments, it sounds like /usr/java/jdk1.5.0_10/bin is somewhere in the path and should be removed.
For a BASH shell, the path is usually set in ~/.bashrc or (less likely?) ~/.bash_profile
Updated with more explanations
Check which java executable is really running, e.g.
$ type java
If this shows something other than /usr/bin/java, then you've likely got a specific JRE/JDK hardcoded in your path. This is fine, but you won't be able to use change Java versions using RH alternatives for any account that hardcodes a specific JRE/JDK in its PATH in this way. However, other packages/accounts (e.g. system processes) that don't hardcode a specific JDK version into its path will use the alternatives-specified JRE.
Check your JAVA_HOME environment variable, e.g.
$ echo $JAVA_HOME
If this is set, this will sometimes point the java executable at a different JRE/JDK, regardless of where the java executable itself lives. Again, its not unusual to set this, but you won't be able to use change Java versions using RH alternatives for any account that hardcodes a different JAVA_HOME.
All that said, for development in my account, I normally set a specific JDK in my path and set JAVA_HOME to point to a specific JDK, rather than rely on the system settings. RH alternatives is fine to control what Java version other packages use, but for my own development, I like to explicitly target the Java I want to use.
When using the alternatives method, if you want to use an alternative, it must first be installed. I believe RPMs would include this as a part of the install, but in the case where manual installs are performed, you can still manually install. For example, with java,
alternatives --install "/usr/bin/java" "java" "/usr/java/example/bin/java" \
--slave /usr/bin/javac javac /usr/java/example/bin/javac \
...
What this does is to install an alternative for the java symlink. For each slave, it also builds/updates the symlink to some other value specified in another alternative, when you switch it. So if you were to switch to a different version of java using alternatives, and the alternative specifies a slave for javac, javac will repoint to the new version as well.
My full list is as follows:
alternatives --install /usr/bin/java java /usr/java/<version>/bin/java 1500 \
--slave /usr/bin/ControlPanel ControlPanel /usr/java/<version>/jre/bin/ControlPanel \
--slave /usr/bin/jar jar /usr/java/<version>/bin/jar \
--slave /usr/bin/javac javac /usr/java/<version>/bin/javac \
--slave /usr/bin/javaws javaws /usr/java/<version>/bin/javaws \
--slave /usr/bin/jcontrol jcontrol /usr/java/<version>/bin/jcontrol \
--slave /usr/bin/keytool keytool /usr/java/<version>/bin/keytool \
--slave /usr/bin/orbd orbd /usr/java/<version>/bin/orbd \
--slave /usr/bin/pack200 pack200 /usr/java/<version>/bin/pack200 \
--slave /usr/bin/policytool policytool /usr/java/<version>/bin/policytool \
--slave /usr/bin/rmid rmid /usr/java/<version>/bin/rmid \
--slave /usr/bin/rmiregistry rmiregistry /usr/java/<version>/bin/rmiregistry \
--slave /usr/bin/servertool servertool /usr/java/<version>/bin/servertool \
--slave /usr/bin/tnameserv tnameserv /usr/java/<version>/bin/tnameserv \
--slave /usr/bin/unpack200 unpack200 /usr/java/<version>/bin/unpack200 \
--slave /usr/share/man/man1/java.1 java.1 /usr/java/<version>/man/man1/java.1 \
--slave /usr/share/man/man1/javac.1 javac.1 /usr/java/<version>/man/man1/javac.1 \
--slave /usr/share/man/man1/javaws.1 javaws.1 /usr/java/<version>/man/man1/javaws.1 \
--slave /usr/share/man/man1/keytool.1 keytool.1 /usr/java/<version>/man/man1/keytool.1 \
--slave /usr/share/man/man1/orbd.1 orbd.1 /usr/java/<version>/man/man1/orbd.1 \
--slave /usr/share/man/man1/pack200.1 pack200.1 /usr/java/<version>/man/man1/pack200.1 \
--slave /usr/share/man/man1/policytool.1 policytool.1 /usr/java/<version>/man/man1/policytool.1 \
--slave /usr/share/man/man1/rmid.1 rmid.1 /usr/java/<version>/man/man1/rmid.1 \
--slave /usr/share/man/man1/rmiregistry.1 rmiregistry.1 /usr/java/<version>/man/man1/rmiregistry.1 \
--slave /usr/share/man/man1/servertool.1 servertool.1 /usr/java/<version>/man/man1/servertool.1 \
--slave /usr/share/man/man1/tnameserv.1 tnameserv.1 /usr/java/<version>/man/man1/tnameserv.1 \
--slave /usr/share/man/man1/unpack200.1 unpack200.1 /usr/java/<version>/man/man1/unpack200.1
Hope this helps.
Related
Background
I'd like to update my JavaFX+Swing desktop application's build process to cross-compile installer-free native binaries for Linux, MacOS, Windows, and JVM targets. The project uses Warp-Packer and BellSoft's FULL version of Liberica OpenJDK 19 to generate a self-extracting, self-running executable for Windows and Linux. In effect, end users can start using the application as follows:
Download the binary.
Run the binary.
I'd like to switch from Warp-Packer to GraalVM for various technical reasons.
Problem
I've tried creating a binary using BellSoft's Native Image Kit, Oracle's GraalVM, and Gluon's GraalVM without success.
Environment
The build environment:
$ java -version
OpenJDK 64-Bit Server VM (build 19.0.1+11, mixed mode, sharing)
$ gradle --version
Gradle 7.6-rc-1
$ uname -a
Linux hostname 6.0.1-arch2-1 #1 SMP PREEMPT_DYNAMIC Thu, 13 Oct 2022 18:58:49 +0000 x86_64 GNU/Linux
Links to the exact versions of OpenJDK and Gradle being used:
https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-linux-amd64-full.tar.gz
https://services.gradle.org/distributions/gradle-7.6-rc-1-bin.zip
The GraalVMs:
BellSoft's Native Image Kit: https://download.bell-sw.com/vm/22.3.0/bellsoft-liberica-vm-full-openjdk17.0.5+8-22.3.0+2-linux-amd64.tar.gz
Oracle's GraalVM: https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.3.0/graalvm-ce-java19-linux-amd64-22.3.0.tar.gz
Gluon's GraalVM: https://github.com/gluonhq/graal/releases/download/gluon-22.1.0.1-Final/graalvm-svm-java17-linux-gluon-22.1.0.1-Final.tar.gz
Note that the application's build.gradle file targets JDK 17:
java {
sourceCompatibility = VERSION_17
targetCompatibility = VERSION_17
}
Further, the application targets JavaFX 19, which could be a problem:
javafx {
version = '19'
modules = ['javafx.controls', 'javafx.swing']
configuration = 'compileOnly'
}
Build
This section provides the complete steps to reproduce the problems I've encountered with each GraalVM implementation.
Native Image Kit
NIK fails due to a bug:
cd /tmp
wget https://download.bell-sw.com/vm/22.3.0/bellsoft-liberica-vm-openjdk17.0.5+8-22.3.0+2-src.tar.gz
mkdir nik
cd nik
tar xf ../bell*gz
grep -n InteropFactoryN graal/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/javafx/JavaFXReflection.java
This shows:
243: "com.sun.javafx.embed.swing.newimpl.InteropFactoryN",
In full context:
static void registerSwing(DuringAnalysisAccess access) {
registerReflectionClasses(access,
"com.sun.javafx.embed.swing.SwingFXUtilsImpl",
"com.sun.javafx.embed.swing.newimpl.InteropFactoryN",
"javafx.embed.swing.SwingNode",
"jdk.swing.interop.LightweightFrameWrapper");
}
If any reflected class doesn't exist, NIK terminates with an error. For example:
Fatal error: org.graalvm.compiler.debug.GraalError: com.oracle.svm.core.util.VMError$HostedError: class com.sun.javafx.embed.swing.newimpl.InteropFactoryN not found
The InteropFactoryN class was removed sometime between javafx-swing 11.0.2 and 12.0.2:
https://repo1.maven.org/maven2/org/openjfx/javafx-swing/11.0.2/javafx-swing-11.0.2-sources.jar
https://repo1.maven.org/maven2/org/openjfx/javafx-swing/12.0.2/javafx-swing-12.0.2-sources.jar
https://repo1.maven.org/maven2/org/openjfx/javafx-swing/17.0.2/javafx-swing-17.0.2-sources.jar
Verified using:
$ jar -tvf javafx-swing-12.0.2-sources.jar | grep FactoryN
$ jar -tvf javafx-swing-17.0.2-sources.jar | grep FactoryN
$ jar -tvf javafx-swing-11.0.2-sources.jar | grep FactoryN
2166 Wed Jan 16 10:19:04 PST 2019 com/sun/javafx/embed/swing/newimpl/InteropFactoryN.java
NIK is built upon OpenJDK 17, and the above confirms that the class was removed and not re-instated. Complete instructions to replicate the bug (Java and Gradle must be installed and available via the PATH):
cd /tmp
git clone https://github.com/DaveJarvis/keenwrite
cd keenwrite
gradle jar
mkdir -p src/main/resources/META-INF/native-image
wget "https://download.bell-sw.com/vm/22.3.0/bellsoft-liberica-vm-full-openjdk17.0.5+8-22.3.0+2-linux-amd64.tar.gz"
tar xf *gz
rm *gz
mv bell* nik
export LD_LIBRARY_PATH="$(pwd)/nik/lib:$LD_LIBRARY_PATH"
# Run the app and use many options.
java \
-agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
--add-opens=javafx.controls/javafx.scene.control=ALL-UNNAMED \
--add-opens=javafx.controls/javafx.scene.control.skin=ALL-UNNAMED \
--add-opens=javafx.graphics/javafx.scene.text=ALL-UNNAMED \
--add-opens=javafx.graphics/com.sun.javafx.css=ALL-UNNAMED \
--add-opens=javafx.graphics/com.sun.javafx.text=ALL-UNNAMED \
--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.application=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.text=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene.traversal=ALL-UNNAMED \
-jar build/libs/keenwrite.jar $#
# Exit the app when most of the features have been exercised.
# Fails due to missing reflective class, InteropFactoryN.
./nik/bin/native-image \
--add-modules=javafx.controls,javafx.swing \
--verbose \
-H:+ReportExceptionStackTraces \
--no-fallback \
--report-unsupported-elements-at-runtime \
-Djava.awt.headless=false \
-cp src/main/resources/META-INF/native-image \
-jar build/libs/keenwrite.jar
Gluon
Gluon fails because the JavaFX modules cannot be found. Here are the build instructions:
cd /tmp
git clone https://github.com/DaveJarvis/keenwrite
cd keenwrite
gradle clean jar
mkdir -p src/main/resources/META-INF/native-image
wget "https://github.com/gluonhq/graal/releases/download/gluon-22.1.0.1-Final/graalvm-svm-java17-linux-gluon-22.1.0.1-Final.tar.gz"
tar xf *gz
rm *gz
mv graalvm* graalvm
export LD_LIBRARY_PATH="$(pwd)/graalvm/lib:$LD_LIBRARY_PATH"
java \
-agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
--add-opens=javafx.controls/javafx.scene.control=ALL-UNNAMED \
--add-opens=javafx.controls/javafx.scene.control.skin=ALL-UNNAMED \
--add-opens=javafx.graphics/javafx.scene.text=ALL-UNNAMED \
--add-opens=javafx.graphics/com.sun.javafx.css=ALL-UNNAMED \
--add-opens=javafx.graphics/com.sun.javafx.text=ALL-UNNAMED \
--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.application=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.text=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED \
--add-exports=javafx.graphics/com.sun.javafx.scene.traversal=ALL-UNNAMED \
-jar build/libs/keenwrite.jar $#
./graalvm/bin/native-image \
--verbose \
-H:+ReportExceptionStackTraces \
--no-fallback \
--report-unsupported-elements-at-runtime \
-Djava.awt.headless=false \
-cp src/main/resources/META-INF/native-image \
-jar build/libs/keenwrite.jar
This fails because GraalVM cannot find JavaFX and Swing. I tried a variety of ways to instruct native-image where to find the JavaFX modules, including:
--module-path /opt/jdk/jmods/ --add-modules=javafx.controls,javafx.swing
I've also downloaded both the JavaFX 19 SDK and the JavaFX 19 jmods and tried using them, such as:
--module-path $(pwd)/javafx-sdk-19 --add-modules=...
--module-path $(pwd)/javafx-jmods-19 --add-modules=...
Neither of those approaches worked.
Oracle
Using the regular GraalVM failed well before any JavaFX issues would be encountered:
cd /tmp
git clone https://github.com/DaveJarvis/keenwrite
cd keenwrite
gradle jar
wget https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.3.0/graalvm-ce-java19-linux-amd64-22.3.0.tar.gz
tar xf graalvm*
rm *gz
mv graalvm* graalvm
./graalvm/bin/gu install native-image
./graalvm/bin/native-image \
--verbose \
-H:+ReportExceptionStackTraces \
--no-fallback \
--report-unsupported-elements-at-runtime \
-Djava.awt.headless=false \
-jar build/libs/keenwrite.jar
This results in the following error:
Fatal error: java.lang.RuntimeException: There was an error linking the native image: Linker command exited with 1
I think the error is caused by:
/usr/bin/ld: /tmp/keenwrite/graalvm/lib/static/linux-amd64/glibc/libawt.a(awt_LoadLibrary.o):(.bss.jvm+0x0): multiple definition of `jvm'; /tmp/keenwrite/graalvm/lib/static/linux-amd64/glibc/libawt_xawt.a(XlibWrapper.o):(.bss.jvm+0x0): first defined here
The full log is at:
https://textdoc.co/kweRFKOHDCV9ZE3A
Supplementary build process details are described on my blog.
Question
How do you cross-compile a JavaFX+Swing application using GraalVM to create a native Linux executable on Linux? More specifically, what steps do I need to run to build a native binary for my application using GraalVM?
Bounty
For some reason StackOverflow didn't update the bounty text. Here's the criteria for awarding:
The answer must provide the exact and complete set of commands to run that will produce a native executable on Linux. Further, the binary must be able to open and render an R Markdown file in the GUI as well as export the file to a PDF. That is, no functionality is lost. The resources and resource bundles don't have to work, but it'd be great if they did.
I am using Gitlab to build a Java tool using ant
The tool requires JDK 17, but ant JDK version is 11, and I'm trying to change it.
So I tried a lot of solutions using a remote repository or remote download site, but after some tries I found out that the VM used to build the tool is not connected to internet (trying to ping google or my IP address doesn't work).
So I tried to upload in the same package with the tool source code the JDK 17 (openjdk-17_linux-x64_bin.tar.gz) and install it there.
Here is the problem, I am not sure how to do this since I don't work with linux, but I tried almost everything on the internet.
Every of these commands are used in a .gitlab-ci.yml file, used for gitlab pipeline.
Here are some examples of what I've tried so far:
- sudo cp /builds/project/openjdk-17_linux-x64_bin.tar.gz /usr/lib/jvm
- sudo tar zxvf "/usr/lib/jvm/openjdk-17_linux-x64_bin.tar.gz" -C /usr/lib/jvm
- echo "JAVA_HOME=/usr/lib/jvm/jdk-17" | sudo tee -a /etc/profile
- echo "PATH=${PATH}:${HOME}/bin:${JAVA_HOME}/bin" | sudo tee -a /etc/profile
- echo "export JAVA_HOME" | sudo tee -a /etc/profile
- echo "export JRE_HOME" | sudo tee -a /etc/profile
- echo "export PATH" | sudo tee -a /etc/profile
- sudo cat /etc/profile
- echo "JAVA_HOME=/usr/lib/jvm/jdk-17" | sudo tee -a /.bashrc
- echo "PATH=${PATH}:${JAVA_HOME}/bin" | sudo tee -a /.bashrc
- echo "JAVA_HOME='/usr/lib/jvm/jdk-17' | sudo tee -a /etc/environment"
- export JAVA_HOME=/usr/lib/jvm/jdk-17
- export PATH=$PATH:$JAVA_HOME/bin
After a lot of combinations of these commands the output of sudo update-alternatives --config java is still:
openjdk version "11.0.12" 2021-07-20
OpenJDK Runtime Environment (build 11.0.12+7-post-Debian-2deb10u1)
OpenJDK 64-Bit Server VM (build 11.0.12+7-post-Debian-2deb10u1, mixed mode, sharing)
But if I try /usr/lib/jvm/jdk-17/bin/java -version it prints 17.
What would be the solution of making the default Java version to be 17. (Also a solution for ant to use the JDK-17 without installing it would be great too, since I need the JDK-17 for ant)
Since you've already found a way to change the jdk on-the-go, you may really want to consider change the base image of your CI to save yourself a lot of time. This step will boost your CI speed. The steps to do that is fairly simple too.
Compose your own Dockerfile
This following is just a pesudo code. You may look into the description of dockerfile builder
FROM your-original-image. This is what you have in your image tag in the gitlab-ci file.
COPY jdk-17-linux-x64.tar.gz /usr/lib/jvm
RUN sudo tar zxvf "/usr/lib/jvm/jdk-17-linux-x64.tar.gz" -C /usr/lib/jvm \
&& sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/java-1.11.0-openjdk-amd64 \
&& sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/default-java \
&& sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/java-11-openjdk-amd64 \
&& sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/openjdk-11 \
&& sudo update-alternatives --remove-all java \
&& sudo update-alternatives --remove-all javac \
&& sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-17/bin/java 1
Build the docker image
If you are using docker hub, then you need to login to docker and get a dockerId which matches the dockerId in the snippet.
If you are using a private repo like harbor or artifactory, you may need the permission to push to it.
docker build . -t dockerId/Name-of-your-image-you-want:latest
Upload the docker image using docker push
docker push dockerId/Name-of-your-image-you-want:latest
change the image tag in your gitlab-ci.yaml to dockerId/Name-of-your-image-you-want:latest
I found a solution.
- sudo cp jdk-17-linux-x64.tar.gz /usr/lib/jvm
- sudo tar zxvf "/usr/lib/jvm/jdk-17-linux-x64.tar.gz" -C /usr/lib/jvm
- sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/java-1.11.0-openjdk-amd64
- sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/default-java
- sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/java-11-openjdk-amd64
- sudo \cp -r /usr/lib/jvm/jdk-17 /usr/lib/jvm/openjdk-11
- sudo update-alternatives --remove-all java
- sudo update-alternatives --remove-all javac
- sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-17/bin/java 1
What I did here was to copy the JDK-17 content to all folders from /usr/lib/jvm folder. So even though the docker image uses JDK-11, I'm rewriting it using JDK-17 uploaded with the source code, and now the tool is built using JKD-17.
PS: I know this is slower and not professional, but in my case, it's easier and more convinient than trying to get help from those who setup the docker container.
It seems Debian does not support openjdk-8-jdk anymore due to a security issue. What is the easiest way to install openjdk-8-jdk for Debian 10 (Buster)?
Alternatively, you can use adoptopenjdk repository:
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -
sudo add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
sudo apt-get update && sudo apt-get install adoptopenjdk-8-hotspot
https://adoptopenjdk.net/installation.html
WARNING: this answer suggest unsupported and dangerous mixing of
Debian releases. Follow the advice on your own risk, as it can break
the system on upgrades, as explained in
http://wiki.debian.org/DontBreakDebian#Don.27t_make_a_FrankenDebian
Package mirror search steps:
In the Search package directories search for openjdk-8-jdk. You can see two results:
stretch (oldstable) (java): OpenJDK Development Kit (JDK)
sid (unstable) (java): OpenJDK Development Kit (JDK)
Choose stretch repository
Scroll to the Download openjdk-8-jdk section and choose your architecture. For example amd64
Now you can see mirrors list and instructions how to install the package via apt:
You should be able to use any of the listed mirrors by adding a line
to your /etc/apt/sources.list like this:
deb http://security.debian.org/debian-security stretch/updates main
Installation steps:
Install software source manager
apt-get update
apt-get install software-properties-common
Add mirror with openjdk-8-jdk
apt-add-repository 'deb http://security.debian.org/debian-security stretch/updates main'
apt-get update
Install openjdk 8
apt-get install openjdk-8-jdk
Note: You can use steps above to find an official Debian mirror with any other package you want to install
You can search the Debian packages site and find out the openjdk-8-jdk package for Debian 10 is only available from unstable (sid) repository currently.
At first it is good to check and save current system-wide symbolic links for already installed Java SDK/JRE packages if any:
ls -la /etc/alternatives | grep java > previous-java-alternatives.txt
Then check is this package can be installed with current configuration:
apt-cache policy openjdk-8-jdk
If no then you need to add unstable repository to the sources list.
The negative output may imply that you prefer to use stable repositories and usually it isn't appropriate for you to update all other software from unstable repositories.
So before adding unstable repository to the sources list make sure APT::Default-Release configuration option is set to "stable":
grep -r Default-Release /etc/apt/
If no (as by default) then set it as recommended in that answer by creating this file:
/etc/apt/apt.conf.d/99defaultrelease
APT::Default-Release "stable";
Now you're ready to add the unstable repository to the sources list.
Before I prefer to check what mirror was selected by me when system was installed. Just look to main sources list:
cat /etc/apt/sources.list
In my case the output shows that mirror.yandex.ru server is used as system source. So I use the same for unstables and add this file:
/etc/apt/sources.list.d/91-debian-unstable.list
deb http://mirror.yandex.ru/debian/ unstable main
deb-src http://mirror.yandex.ru/debian/ unstable main
(I also have 90-debian-testing.list file for the testing repo.)
Then update package lists:
apt update
And check you system wont update from unstable sources:
apt list --upgradable
And recheck is required package can be installed:
apt-cache policy openjdk-8-jdk
Do install the package:
apt install openjdk-8-jdk
Look at new symbolic links:
ls -la /etc/alternatives | grep java-8
Just waste few seconds on them (or continue with man 1 update-alternatives).
This is my script which I use to install OpenJDK 8 on Bitbucket's Pipelines Docker image NodeJS 10.16.2.
But now I see that this docker image is based on Stretch...
It is based on https://github.com/docker-library/openjdk/blob/89851f0abc3a83cfad5248102f379d6a0bd3951a/8-jdk/Dockerfile
#!/bin/bash
set -x #echo on
# based on https://github.com/docker-library/openjdk/blob/89851f0abc3a83cfad5248102f379d6a0bd3951a/8-jdk/Dockerfile
apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
unzip \
xz-utils &&
rm -rf /var/lib/apt/lists/*
echo 'deb http://httpredir.debian.org/debian-security stretch/updates main' >/etc/apt/sources.list.d/jessie-backports.list
# Default to UTF-8 file.encoding
export LANG=C.UTF-8
# add a simple script that can auto-detect the appropriate JAVA_HOME value
# based on whether the JDK or only the JRE is installed
{ \
echo '#!/bin/sh'; \
echo 'set -e'; \
echo; \
echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
} > /usr/local/bin/docker-java-home \
&& chmod +x /usr/local/bin/docker-java-home
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export JAVA_VERSION=8u252
export JAVA_DEBIAN_VERSION=8u252-b09-1~deb9u1
# see https://bugs.debian.org/775775
# and https://github.com/docker-library/java/issues/19#issuecomment-70546872
export CA_CERTIFICATES_JAVA_VERSION=20170929~deb9u3
set -x \
&& apt-get update \
&& apt-get install -y \
openjdk-8-jdk="$JAVA_DEBIAN_VERSION" \
ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \
&& rm -rf /var/lib/apt/lists/* \
&& [ "$JAVA_HOME" = "$(docker-java-home)" ]
# see CA_CERTIFICATES_JAVA_VERSION notes above
/var/lib/dpkg/info/ca-certificates-java.postinst configure
UPDATE
Things change, versions are upped. Here is the latest script which works for https://hub.docker.com/layers/node/library/node/10.16.2/images/sha256-8f420c033acee137f9e902092a04d371bdf1f839559cce60614c0d5905d20294?context=explore
#!/bin/bash
set -x #echo on
# based on https://github.com/docker-library/openjdk/blob/89851f0abc3a83cfad5248102f379d6a0bd3951a/8-jdk/Dockerfile
apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
unzip \
xz-utils &&
rm -rf /var/lib/apt/lists/*
echo 'deb http://httpredir.debian.org/debian-security stretch/updates main' >/etc/apt/sources.list.d/jessie-backports.list
# Default to UTF-8 file.encoding
export LANG=C.UTF-8
# add a simple script that can auto-detect the appropriate JAVA_HOME value
# based on whether the JDK or only the JRE is installed
{ \
echo '#!/bin/sh'; \
echo 'set -e'; \
echo; \
echo 'dirname "$(dirname "$(readlink -f "$(which javac || which java)")")"'; \
} > /usr/local/bin/docker-java-home \
&& chmod +x /usr/local/bin/docker-java-home
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export JAVA_VERSION=8u265
export JAVA_DEBIAN_VERSION=8u265-b01-0+deb9u1
# see https://bugs.debian.org/775775
# and https://github.com/docker-library/java/issues/19#issuecomment-70546872
export CA_CERTIFICATES_JAVA_VERSION=20170929~deb9u3
set -x \
&& apt-get update \
&& apt-get install -y \
openjdk-8-jdk="$JAVA_DEBIAN_VERSION" \
ca-certificates-java="$CA_CERTIFICATES_JAVA_VERSION" \
&& rm -rf /var/lib/apt/lists/* \
&& [ "$JAVA_HOME" = "$(docker-java-home)" ]
# see CA_CERTIFICATES_JAVA_VERSION notes above
/var/lib/dpkg/info/ca-certificates-java.postinst configure
I needed to install a 32-bit version but this wasn't available at adoptopenjdk far as I could see. I tracked down a copy of a binary at java.com i their downloads area:
jre-8u241-linux-i586.tar.gz
All I needed was the JRE (rather than a JDK, but the process should be the same for either) and since it was also for a personal use only, the Oracle binary was OK (they have limitations in this regard).
I downloaded the binary and placed it in the home folder (~/) of the user that needed to run it and then unzipped it like so:
mkdir ~/java && cd ~/java && tar -xf jre-8u241-linux-i586.tar.gz
Then added the location to the path of the user that would run the Java application by appending this line to ~/.profile:
export PATH=$PATH:/home/youruserid/java/jre1.8.0_241/bin
This worked fine for my case but there are no doubt better ways to install a binary. For example so it is available for all Unix users rather than just one.
The easiest way to install JDK8 is using SDKMAN.
$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk install java 8.0.275.hs-adpt
Based one some of the above answers, this is what i used in my shell script on debian buster silm os running node 12.x (node:12.6-buster-slim)
This was in preparing to move to github actions local testing with act, do note that there is no need for sudo as ci testing in this container already is root.
apt-get update -qq
#software-properties-common not installed on slim
apt-get install software-properties-common -y -q
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add -
add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
apt-get update -qq
#man folder needs to be available for adoptopenjdk-8 to finish configuring
mkdir -p /usr/share/man/man1/
apt-get install adoptopenjdk-8-hotspot -y
#ensure openjdk-8-jdk is found for some installations, thanks b8kich for the virtual wrapper
curl https://gitlab.com/b8kich/adopt-openjdk-8-jdk/-/raw/master/adopt-openjdk-8-jdk_0.1_all.deb?inline=false -o adopt-openjdk-8-jdk_0.1_all.deb
dpkg -i adopt-openjdk-8-jdk_0.1_all.deb
I've found, mainly after years of working with deprecated iDrac consoles which have particular java requirements, that installing multiple versions of the JRE or JDK is preferable as you can choose between them as necessary without worrying about other dependencies or breaking your package manager.
This is actually incredibly easy on Debian, and very probably other linux, by eschewing the package manager all together and manually installing whatever versions you need.
Download your desired jre/jdk from the Oracle archives (You will need a free Oracle account) here for whatever architecture you need: https://www.oracle.com/java/technologies/downloads/archive/
I selected "Java SE 8 (8u211 and later)" from the menu and snagged jre-8u271-linux-x64.tar.gz.
From there, extract the archive to a location accessible to the user who will be running java; Typically I'll extract to "/usr/local/lib/jre1.8.0_271/".
From here you can run /usr/local/lib/jre1.8.0_271/bin/java successfully, as well as javaws.
/usr/local/lib/jre1.8.0_271/bin# ./java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
On most of my systems I already have some packaged version of jre installed that's native to the release, so my /usr/bin/java and /usr/bin/javaws typically are symlinks to /etc/alternatives/java /etc/alternatives/javaws, respectively.
To switch the system to a particular jre, just update the relevant symlinks to point to the version of your choice:
rm /usr/bin/java /usr/bin/javaws /usr/bin/jjs /usr/bin/jcontrol
for i in java javaws jjs jcontrol; do ln -s /usr/local/lib/jre1.8.0_271/bin/$i /usr/bin/$i; done
Note that if you need, per say, jre 7, 11 and 17 you can download and extract each version to a particular named folder in /usr/local/lib, or your home directory if you'll be launching it manually, and utilize each of them individually as needed by updating the symlinks or just running them directly.
I just faced a similar problem:
I have on old HP-mini 210 netbook to be used as a "car logger" and it has to use java 8 32bit (required by the logger application).
I'm running a light distro based on Debian 10 (BunsenLabs Lithyum).
After poking around the easyest way I found to install java 8 32bits was by using an openjdk 8 deb package published by OpenLogic (they have 32 or 64 bits):
https://www.openlogic.com/openjdk-downloads
Just download and install (package manager). Worked 100% and now I have a super fast hp-mini "car logger".
I was migrating from Jessie to Buster, and found that not-so-old, legacy code would not compile and run on JDK11.
I managed to copy all java8 folders from my Jessie distribution, reworked the links, and set that as a new JDK on Eclipse. That works so far.
the easiest way I have found to download java 8 on debian buster is to use the command su apt-get install openjdk-8-jdk
I have a circleci build that uses python:3.6.6-stretch. most of my services uses python, but I also need java10 + maven.
Now it seems impossible to install java10 inside python3 docker.
What is the best approach to have a docker that will support python and java ?
Java 10 is not supported anymore and is removed from most of the PPAs. Do not use it if possible.
But if you still need specifically Java 10 you can take a look how it is installed on top of an Ubuntu image by AdoptOpenJDK project.
Your Dockerfile might look somewhat like this:
FROM python:3.6.6-stretch
RUN rm -rf /var/lib/apt/lists/* && apt-get clean && apt-get update && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
RUN set -eux; \
curl -Lso /tmp/openjdk.tar.gz https://github.com/AdoptOpenJDK/openjdk10-releases/releases/download/jdk-10.0.2%2B13/OpenJDK10_x64_Linux_jdk-10.0.2%2B13.tar.gz; \
mkdir -p /opt/java/openjdk; \
cd /opt/java/openjdk; \
tar -xf /tmp/openjdk.tar.gz; \
jdir=$(dirname $(dirname $(find /opt/java/openjdk -name javac))); \
mv ${jdir}/* /opt/java/openjdk; \
rm -rf ${jdir} /tmp/openjdk.tar.gz;
ENV JAVA_HOME=/opt/java/openjdk \
PATH="/opt/java/openjdk/bin:$PATH"
Note: I dropped some SHA sum checks in favor of making the command shorter.
So I did some research into public PPAs, and I couldn't find one that has a compilation of open-jdk10 for Debian-stretch. There is one for multiple versions of Ubuntu.
If you want maven + python 3 + java 10 installed I think you have a couple of options.
Find an image with maven + java 10 then install python 3 yourself.
Download and install the JDK by hand and setup the correct variables to add it to your PATH. See https://www.rosehosting.com/blog/how-to-install-java-10-on-debian-9/
Use an Ubuntu based image like this (https://github.com/FNNDSC/ubuntu-python3/blob/master/Dockerfile), so that you can use this PPA which has distributions of openjdk for 10.
All,
Attempting to install liquibase on Heroku so that we can update our database as part of our NodeJs deployments but running into (I'm guessing) classpath errors.
app structure
bower_components
liquibase
- install
- update
node_modules
src
package.json
...
Heroku can run a postinstall script where we run the liquibase install
package.json
"scripts": {
"postinstall": "./liquibase/install && ./liquibase/update && ./node_modules/bower/bin/bower install && ./node_modules/grunt-cli/bin/grunt bundle --force",
}
liquibase install script. Downloads the postgresql.jar and the liquibase executable and puts them in the liquibase folder.
#!/usr/bin/env bash
wget https://github.com/liquibase/liquibase/releases/download/liquibase-parent-3.5.3/liquibase-3.5.3-bin.tar.gz
mkdir -p ~/liquibase
tar -zx -C ~/liquibase -f liquibase-3.5.3-bin.tar.gz
wget https://jdbc.postgresql.org/download/postgresql-42.1.1.jar
mkdir -p ~/lib
mv postgresql-42.1.1.jar ~/lib/postgresql.jar
After the install, we attempt to run the liquibase update (./liquibase/update)
liquibase \
--logLevel="info" \
--driver="org.postgresql.Driver" \
--classpath="$~/lib/postgresql.jar" \
--changeLogFile="liquibase.xml" \
--url="jdbc:postgresql://$HOST:$PORT/$DATABASE" \
--username="$USERNAME" \
--password="$PASSWORD" \
update
But I get the error
liquibase: command not found
That makes me think liquibase isn't on the path
So I do this
export PATH=${PATH}:~/liquibase
Which gives me this error
Error: Could not find or load main class null
Yay for Java :( So no Java or classpath isn't set?
java -v
java version "1.7.0_151"
OpenJDK Runtime Environment (IcedTea 2.6.11) (7u151-2.6.11-0ubuntu1.14.04.1)
OpenJDK 64-Bit Server VM (build 24.151-b01, mixed mode)
echo $JAVA_HOMENothing
which java/usr/bin/java
Maybe I should set $JAVA_HOME=/usr/bin/java
Again, nothing.
At this point, I've got no clue on how to proceed. Any help would be appreciated.
* SOLVED *
Adding the buildpack helped. Also needed to modify the update script
HOME=~
java -jar $HOME/liquibase/liquibase.jar \
--logLevel="info" \
--driver="org.postgresql.Driver" \
--classpath="$HOME/lib/postgresql.jar" \
--changeLogFile="liquibase.xml" \
--url="jdbc:postgresql://$HOST:$PORT/$DATABASE" \
--username="$USERNAME" \
--password="$PASSWORD" \
update
and then the postinstall script
"scripts": {
"postinstall": "cd liquibase && ./install && ./update && cd .. && ./node_modules/bower/bin/bower install && ./node_modules/grunt-cli/bin/grunt bundle --force"
}
First, you'll want to add the JVM buildpack to your app:
$ heroku buildpacks:add -i 1 heroku/jvm
This will install JDK 8 (instead of the default JDK 7), set JAVA_HOME correctly, and even set JDBC_DATABASE_URL (which you can use directly in your --url option).
The message "Error: Could not find or load main class null" suggests that the java command created by the liquibase script (the one you are running) is either malformed, or incomplete. I think this may be due to the option --classpath="$~/lib/postgresql.jar", which looks odd. Or the location of the liquibase.jar relative to the script.
I think you want your classpath option to look like:
--classpath="/app/path/to/classes:/app/lib/postgresql.jar"
If you still have trouble, I would try running the liquibase.jar directly instead of using the script, like:
java -jar liquibase.jar \
--logLevel="info" \
--driver="org.postgresql.Driver" \
--classpath="/app/path/to/classes:/app/lib/postgresql.jar" \
--changeLogFile="liquibase.xml" \
--url="$JDBC_DATABASE_URL" \
--username="$JDBC_DATABASE_USERNAME" \
--password="$JDBC_DATABASE_PASSWORD" \
update