Project

General

Profile

Switching Between Java 8 and Java 11 or Java 17

Introduction

In FWD v3.x, only Java 8 is supported.

Starting in FWD v4, all Java 8, Java 11 and Java 17 are supported. Java 11 support was implemented in #5567, Java 17 support was added in #6692

For Java 11 upgrade there were two main goals:

  • bring Java 11 support to FWD
  • minimize impact on support for Java 8 (do not break it)

Java 17 upgrade task #6692 there were another two main goals:

  • bring Java 17 support to FWD
  • upgrade all possible components FWD depends on to remove security vulnerabilities
  • upgrade gradle

Java 8 stays as main FWD runtime platform, but any project can be upgraded to Java 11 if up to 30% performance degradation is accepted or to Java 17 if up to 15% performance degradation is accepted.

Older project configurations were designed to run on Java 8, so nothing needs to be done to keep those configurations on Java 8. If a project wants to support Java 11 or Java 17, then changes to scripts/runtime are needed. The changes may be implemented such that, one can switch only the current Java runtime from Java 8 to Java 11 or Java 17 and back are needed for migration.

Additionally some tweaks to the FWD code have been implemented to make its code compatible with newer Java VM APIs and to remove build warnings (most of).

Note that the JAVA UDF (PL/Java) feature was not tested and is not supported with Java 11 nor with Java 17.

Performance in Java 11 or Java 17

All other things being equal (same hardware, OS, converted code and configuration), Java 11 is up to 30% slower than Java 8 and Java 17 is up to 15% slower than Java 8 in general. This has been measured in simulations as well as with real converted application code. For this reason, it is recommended to avoid Java 11 in production installations and move directly to Java 17 if performance loss is acceptable.

Supported Configurations

In this context, "build" indicates the level of Java utilized to create FWD. "Conversion" indicates the level of Java utilized to convert and compile an application. And "runtime" indicates the level of Java utilized to run the aforementioned application.

The following configurations are tested and supported:

  • Build Java 8, Conversion Java 8, Runtime Java 8 - build processes tools and code, conversion and compiled generated/custom code are executed with Java 8 runtime,
  • Build Java 11, Conversion Java 11, Runtime Java 11 - build processes tools and code, conversion and compiled generated/custom code are executed with Java 11 runtime,
  • Build Java 17, Conversion Java 17, Runtime Java 17 - build processes tools and code, conversion and compiled generated/custom code are executed with Java 17 runtime,

Java 9/10, Java 12-16 and Java 18+ have not been tested and are not supported in any way.

Unsupported Configurations

Following configurations are not tested and are not supported.

  • Build Java 8, Conversion Java 8, Runtime Java 11
  • Build Java 8, Conversion Java 11, Runtime Java 11

Updated Dependencies

The following changes were brought by #5567:

  • AspectJ was upgraded to 1.9.7
  • reflectasm was upgraded to version 1.11.6
  • gwt-user, gwt-dev and gwt-codeserver were upgraded to version: 2.9.0
Branch #6692 that allowed upgrading to Java 17 brought even more dependencies updates, the most important ones are:
  • gradle was upgraded to version 7.6.4
  • batik was upgraded to version 1.17
  • bonucycastle libs were upgraded to version jdk15to18-1.69
  • gremlin libs were upgraded to version -3.7.0
  • jetty-all is not using uber-jar anymore and was upgraded to version 9.4.54.v20240208
  • janusgraph was upgraded to 1.0
  • acme4j was removed
  • fwd-slf4j.jar is not needed anymore

TODO - fill all updated dependencies

Java 11 Migration Process

Some changes may be needed to a given project configuration. These are outlined in this section. If migrating to Java 17, there are subsequent migration steps, and both should be performed. All example code comes from hotel_gui.

Once the java runtime is switched and application fully rebuilt everything should work as before. By "rebuilt" we mean that FWD needs to be recompiled and any converted code needs to be recompiled.

FWD Service Provider Interface (fwdspi.jar)

The introduction of Java Platform Module System (JPMS) and Unicode Consortium's Common Locale Data Repository (CLDR) took place in Java 9. This section provides a little background, since many of the script updates were required due to this change.

The JPMS introduced a significant change to the way the location of JAR files containing your SPI (or any other JAR files) are found. The java.ext.dirs system property was removed, and instead can just be located in your classpath.

The CLDR locale provider change improved the accuracy and coverage of locale data. CLDR is an industry-standard repository for locale data and is widely used across various platforms and applications. The java.locale.providers is where this is specified. CLDR was introduced as the new default provider for locale data. For Java 9 and later:
  • SPI: Allows for the use of custom locale service providers that implement the java.util.spi.LocaleServiceProvider interface.
  • CLDR: Uses the Unicode Consortium's CLDR data, which provides comprehensive and up-to-date locale data.
  • COMPAT: Provides compatibility with the JRE locale data provider from previous Java versions (Java 8 and earlier).

The JRE provider was deprecated in favor of COMPAT. The COMPAT provider ensures backward compatibility with the locale data provided by the JRE in earlier Java versions, but it is not the default provider in Java 9 and later.

FWD Build Scripts

FWD build scripts (build.xml and build.gradle) detect the Java version runtime and configure environment according to the detected java version. No changes are required.

Conversion

Conversion is independent of the Java runtime version. No changes to the conversion process are required. Source files converted/generated with FWD running Java 8 are identical to files generated by FWD running Java 11 or Java 17.

Project Build Scripts

Project-specific (custom) build scripts (mainly build.xml and build_db.xml) must be updated accordingly to reflect a new way Java 11 and newer supports SPI feature. The below examples are from hotel_gui.

Changes to build.xml allow for detection of the currently utilized Java version with a condition:

   <condition property="java_11_spi">
       <javaversion atleast="11"/>
   </condition>

Elsewhere, the property java_11_spi can be used to have separate targets where different actions are to take place. Below illustrates if and unless usage to have separate deployapp.prepare tasks, based upon which Java is in use:
   <target name="deployapp.prepare" depends="deployapp.prepare.java8,deployapp.prepare.java11" 
           description="Deploys the generated jars for the application (not FWD) by copying them to the location expected by the runtime scripts." >

      <!-- copy the required jars to the distribution directory -->
      <copy file="${build.home}/lib/${appname}.jar" todir="${deploy.home}/lib"/>      
   </target>
   <target name="deployapp.prepare.java8" unless="java_11_spi" 
           description="Deploys the FWD *and* generated jars by copying them to the location expected by the runtime scripts, Java 8 version." >

      <!-- create the deploy lib folder -->
      <delete dir="${deploy.home}/lib" />
      <mkdir dir="${deploy.home}/lib"/>

      <!-- create and populate the extension lib folder -->
      <mkdir dir="${deploy.home}/lib/spi"/>
      <copy file="${fwd.lib.home}/fwdspi.jar" todir="${deploy.home}/lib/spi/"/>
   </target>
   <target name="deployapp.prepare.java11" if="java_11_spi" 
           description="Deploys the FWD *and* generated jars by copying them to the location expected by the runtime scripts for Java 11+" >

      <!-- create the deploy lib folder -->
      <delete dir="${deploy.home}/lib" />
      <mkdir dir="${deploy.home}/lib"/>
      <copy file="${fwd.lib.home}/fwdspi.jar" todir="${deploy.home}/lib/"/>
   </target>

Then, later on, the db.spi.lib property will be set appropriately:
      <if>
         <available file="${fwd.lib.home}/spi/fwdspi.jar" />
         <then>
            <property name="db.spi.lib" value="${fwd.lib.home}/spi" />
         </then>
         <else>
            <property name="db.spi.lib" value="${deploy.home}/lib/spi" />
         </else>
      </if>

In build_db.xml, the java.ext.dirs property will either be set to the db.spi.lib value, as set in build.xml, or nothing:

   <condition property="java.ext.dir.param" value="-Djava.ext.dirs=${db.spi.lib}" else="-Dignorethis">
     <not>
       <javaversion atleast="11"/>
     </not>
   </condition>
   <condition property="java.locale.providers.param" else="-Djava.locale.providers=SPI,JRE" value="-Djava.locale.providers=SPI,CLDR,COMPAT">
       <javaversion atleast="11"/>
   </condition>

The java.ext.dirs property is then used (<jvmarg value="${java.ext.dir.param}"/>), instead of a hard-coded value that only worked for Java 8.

FWD Server Runtime

FWD server scripts (usually located in deploy/server/server.sh need to be updated to reflect a new way Java 11 (and newer) supports SPI feature and CLDR. In summary:

  • fwdspi.jar needs to be added to classpath
  • -Djava.ext.dirs= directive must be removed from server java command line
  • -Djava.locale.providers should be now SPI,CLDR,COMPAT instead of SPI,CLDR

Scripts supporting both Java 8 and Java 11 (and newer) need to detect Java version and act accordingly.

A small amount of bash can be utilized to make the determination of which Java is in place, provided awk is available:

# Determine the configured JDK
#jver is 18 for java 1.8, 15 for java 1.5, 110 for java 11, 170 for java 17 etc.
prog="java" 
jver=$(${prog} -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{sub("^$", "0", $2); print $1$2}')

After this, the $jver contains an integer which can be checked where necessary, such that appropriate action can be taken to configure SPI and CLDR. The below example will set spi to -Djava.locale.providers=SPI,CLDR,COMPAT if the version is greater than Java 8, or -Djava.locale.providers=SPI,JRE -Djava.ext.dirs=${prog_result}:../lib/spi where the prog_result should be the existing value for the Java property java.ext.dirs with ../lib/spi tacked onto the end. It uses com.goldencode.util.PrintSystemProp, from p2j.jar to help.
   for f in ../lib/*.jar
   do
      cpath=$cpath:$f
   done
   if [ $jver -eq 18 ]; then
      # Using java 8
      prog_result=$(${prog} -classpath ${cpath} com.goldencode.util.PrintSystemProp java.ext.dirs 2> /dev/null)
      spi="-Djava.locale.providers=SPI,JRE -Djava.ext.dirs=${prog_result}:../lib/spi" 
   elif [ $jver -gt 18 ]; then
      spi="-Djava.locale.providers=SPI,CLDR,COMPAT" 
   else
      echo "Using invalid java (must be 8 or greater). Exiting." 
      exit 1
   fi

The spi value is subsequently passed to the ServerDriver. Remember that java.ext.dirs was deprecated starting with Java 9, so is not included with Java 11 or greater.

FWD Client Runtime

For standard installation no update is required for FWD client scripts to run with Java 11.

FWD Spawner Runtime

spawner needs to be rebuilt with Java 11 and reinstalled/redeployed, as spawner binary has hardcoded reference to Java libraries runtime present at compile time.
For the standard installation spawner build script is a part of FWD build script, thus only rebuild and reinstall is necessary.
For other types of installations build scripts need to be updated accordingly.

Java 17 Migration Process - additional steps

Migration to Java 17 requires all steps required to migrate to Java 11 first and additional steps specified below - depending on a project only some of those steps might be required.

FWD Build Scripts

FWD build scripts (build.xml and build.gradle) detect the Java version runtime (8,11,17) and configure environment according to the detected java version, so no changes are needed.

Conversion

Conversion is independent of the Java runtime version. No changes to the conversion process are required. Source files converted/generated with FWD running Java 8 are identical to files generated by FWD running Java 11 or Java 17.

Opening API

In current FWD version Java 17 requires opening java.base APIs when building FWD administration console by adding following lines to JVM arguments:

           <jvmarg line="--add-opens"/>
           <jvmarg value="java.base/java.lang=ALL-UNNAMED"/>

JVM command line parameter --add-opens java.base/java.lang=ALL-UNNAMED needs to be added for any use case there is an java.lang.IllegalAccessError thrown by an application.

Explicit importing of com.goldencode.p2j.persist.Record

As Java 17 defines its own Record type its necessary to explicitly specify that application code needs FWD Record and not java.lang.Record by putting following header into all relevant files:

import com.goldencode.p2j.persist.Record;

Changes to JavaScript dependencies.

Note that due to changed way JS dependencies are managed version string needs to be removed from JS dependencies name. So following changes needs to be implemented:
  • jquery-3.4.1.js needs to be changed to jquery.js -

Spawner installation

Note that privileged mode inside ant or gradle is not supported anymore, so installation that requires privileged access needs to be moved to scripts e.g. postinstall.sh like in following install_spawner.sh:

#!/bin/bash

[[ "$fspawn"* != "$HOME"* ]] && [[ $(whoami) != "root" ]] && mysudo="sudo" 

fspawn=/opt/spawner
pwd=$PWD
postbuild=${pwd}/p2j/src/native/postbuild.sh
spawn_prog=${pwd}/p2j/build/native/spawn
p2j_lib=${pwd}/p2j/build/lib

# Use sudo if elevation is required (destination for spawn is outside $HOME and we are *not* root)
sudo install -d /opt/spawner/
sudo chmod gou+rx /opt/ /opt/spawner/

cd p2j
ANT_OPTS="$ANT_OPTS -Xmx4g" 
ant $@ jar native -Dspawn.install.folder=$fspawn -Dsrv.certs=$pwd/deploy/server/srv-certs.store
(cd build/native && $mysudo $postbuild $fspawn $spawn_prog $pwd/deploy/server/srv-certs.store )
$mysudo chmod gou+rx $fspawn
cd ../
ant deploy.prepare

For details please check install_spawner.sh in hotel_gui project.

Simplified Migration Plan

Simplified plan to migrate a project from Java 8 to Java 11 or Java 17:

  1. Development: migrate any custom (software out of FWD project) platform extensions to Java 11.
  2. Install java 17 or Java 17 on build server
  3. Switch build server environment to java 17 or java 17
  4. Build FWD for Java 11 or Java 17
  5. Build the project for Java 11 with FWD for java 11 or Build the project for Java 17 with FWD for java 17
  6. Test the project for java 11 with FWD for java 11 or Test the project for java 17 with FWD for java 17
  7. Install Java 11 or Java 17 on runtime servers
  8. Install the project for Java 11 or Java 17 on runtime servers, I'd suggest to install spawner in different directory if quick rollback is needed
  9. Stop app for java 8, run app for java 11 or Java 17 on runtime servers (with updated spawner directory configuration if needed)

Java 11 or Java 17 Migration Process Q&A and Tips

  • Make sure spawner is also migrated.
  • On Ubuntu Linux 20.04 its possible to switch Java version system wide with sudo update-java-alternatives --set <java_version_string>
  • On Ubuntu Linux 20.04 its possible to check Java version by executing 'ls -l /proc/<pid>/exe' - to make sure correct version of JVM is in use
  • .g files were changed to fix Java 11/17 compile warnings, there are no functional changes. -> If you stay on Java 8 full conversion is not needed, if you switch to Java 11/17 full conversion is recommended.

© 2024 Golden Code Development Corporation. ALL RIGHTS RESERVED.