You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2023/12/08 17:02:51 UTC

(freemarker) 02/07: Switched to Java 16 as minimal build environment. With this version (since Java 9) we can't use javac "bootclasspath", and "source", and "target", but "release". Also, removed RMI sub generation for the debug API, as rmic was removed since JDK 13 or so, and modern RMI doesn't need stubs anyway (also probably nobody uses the debug API).

This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git

commit 52cae12dc89dc97df6f2f6314ef9bb82820e025c
Author: ddekany <dd...@apache.org>
AuthorDate: Thu Dec 7 21:26:53 2023 +0100

    Switched to Java 16 as minimal build environment. With this version (since Java 9) we can't use javac "bootclasspath", and "source", and "target", but "release". Also, removed RMI sub generation for the debug API, as rmic was removed since JDK 13 or so, and modern RMI doesn't need stubs anyway (also probably nobody uses the debug API).
---
 .github/workflows/ci.yml                         |  6 ++
 README.md                                        | 14 ++---
 build.xml                                        | 35 +++++-------
 osgi.bnd                                         |  4 +-
 src/main/java/freemarker/core/_Java16.java       | 34 +++++++++++
 src/main/java/freemarker/core/_Java16Impl.java   | 57 +++++++++++++++++++
 src/main/java/freemarker/core/_JavaVersions.java | 72 ++++++++++++++++--------
 src/manual/en_US/book.xml                        | 25 ++++++--
 8 files changed, 188 insertions(+), 59 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1fff45aa..95403ad8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,6 +47,12 @@ jobs:
           java-version: 8
           distribution: temurin
 
+      - name: Set up JDK 16
+        uses: actions/setup-java@v3
+        with:
+          java-version: 16
+          distribution: zulu
+
       - name: Prepare build.properties
         shell: bash
         run: >-
diff --git a/README.md b/README.md
index c2dda861..201a6ab8 100644
--- a/README.md
+++ b/README.md
@@ -106,7 +106,7 @@ If you haven't yet, download the source release, or checkout FreeMarker from
 the source code repository. See repository locations here:
 https://freemarker.apache.org/sourcecode.html
 
-You need JDK 8 (not JDK 9!), Apache Ant (tested with 1.9.6) and Ivy (tested
+You need JDK 16, Apache Ant (tested with 1.10.6) and Ivy (integrated into
 with 2.5.0) to be installed. To install Ivy (but be sure it's not already
 installed), issue `ant download-ivy`; it will copy Ivy under `~/.ant/lib`.
 (Alternatively, you can copy `ivy-<version>.jar` into the Ant home `lib`
@@ -114,7 +114,7 @@ subfolder manually.)
 
 It's recommended to copy `build.properties.sample` into `build.properties`,
 and edit its content to fit your system. (Although basic jar building should
-succeeds without the build.properties file too.)
+succeed without the build.properties file too.)
 
 To build `freemarker.jar`, just issue `ant` in the project root directory, and
 it should download all dependencies automatically and build `freemarker.jar`. 
@@ -165,7 +165,7 @@ Below you find the step-by-step setup for Eclipse (originally done on Mars.1):
     Number of imports required for .*: 99
     Number of static imports needed for .*: 1
   - Java -> Installed JRE-s:
-    Ensure that you have JDK 8 installed, and that it was added to Eclipse.
+    Ensure that you have JDK 16 installed, and that it was added to Eclipse.
     Note that it's not JRE, but JDK.
   - Java -> Compiler -> Javadoc:
     "Malformed Javadoc comments": Error
@@ -188,7 +188,7 @@ Below you find the step-by-step setup for Eclipse (originally done on Mars.1):
         src/test/resources
     - On the "Libraries" tab:
       - Delete everyhing from there, except the "JRE System Library [...]"
-      - Edit "JRE System Library [...]" to "Execution Environment" "JavaSE 1.8"
+      - Edit "JRE System Library [...]" to "Execution Environment" "JavaSE 16"
       - Add all jar-s that are directly under the "ide-dependencies" directory
         (use the "Add JARs..." and select all those files).
    - Press "Finish"
@@ -206,7 +206,6 @@ Below you find the step-by-step setup for Eclipse (originally done on Mars.1):
     _Jython22*.java,
     _FreeMarkerPageContext2.java,
     FreeMarkerJspFactory2.java,
-    Java8*.java
   Also, close these files if they are open. Now you shouldn't have any errors.
 - At Project -> Properties -> Java Code Style -> Formatter, check in "Enable
   project specific settings", and then select "FreeMarker" as active profile.
@@ -233,7 +232,7 @@ Originally done on IntelliJ IDEA Community 2018.2.4:
 
 - "New" -> "Project". In order as the IntelliJ will prompt you:
 
-  - Select "Java" on the left side, and "1.8" for SDK on the right side. Press "Next".
+  - Select "Java" on the left side, and "16" for SDK on the right side. Press "Next".
   
   - Template selection: Don't chose anything, "Next"
   
@@ -265,7 +264,7 @@ Originally done on IntelliJ IDEA Community 2018.2.4:
     - Test Resource Folders:  
       src/test/resources
       
-  - Still inside the "Sources" tab, change the "Language level" to "7". (Yes, we use Java 8 SDK with
+  - Still inside the "Sources" tab, change the "Language level" to "7". (Yes, we use Java 16 SDK with
     language level 7 in the IDE, due to the tricks FreeMarker uses to support different Java versions.)
     
   - Switch over to the "Dependencies" tab (still inside "Project Structure" / "Modules"), and add
@@ -281,7 +280,6 @@ Originally done on IntelliJ IDEA Community 2018.2.4:
     _Jython22*.java,  
     _FreeMarkerPageContext2.java,  
     FreeMarkerJspFactory2.java,  
-    Java8*.java  
 
 - You may do "Build" / "Build project" (Ctrl+F9) to see if everything compiles now.
     
diff --git a/build.xml b/build.xml
index 6c499af2..905411f1 100644
--- a/build.xml
+++ b/build.xml
@@ -19,14 +19,13 @@
 -->
 
 <project basedir="." default="jar" name="freemarker"
-  xmlns:ivy="antlib:org.apache.ivy.ant"
-  xmlns:javacc="http://javacc.dev.java.net/"
-  xmlns:docgen="http://freemarker.org/docgen"
-  xmlns:bnd="http://www.aqute.biz/bnd"
-  xmlns:rat="antlib:org.apache.rat.anttasks"
-  xmlns:u="http://freemarker.org/util"
-  xmlns:if="ant:if"
-  xmlns:unless="ant:unless"
+         xmlns:ivy="antlib:org.apache.ivy.ant"
+         xmlns:javacc="http://javacc.dev.java.net/"
+         xmlns:docgen="http://freemarker.org/docgen"
+         xmlns:bnd="http://www.aqute.biz/bnd"
+         xmlns:rat="antlib:org.apache.rat.anttasks"
+         xmlns:u="http://freemarker.org/util"
+         xmlns:unless="ant:unless"
 >
 
   <!-- ================================================================== -->
@@ -59,7 +58,7 @@
   </condition>
   <available property="atLeastJDK8" classname="java.util.function.Predicate"/>
 
-  <!-- When boot.classpath.j2se* is missing, these will be the defaults: -->
+  <!-- When boot.classpath.j* is missing, these will be the defaults: -->
   <!-- Note: Target "dist" doesn't allow using these. -->
   <property name="boot.classpath.j2se1.7" value="${sun.boot.class.path}" />
   <property name="boot.classpath.j2se1.8" value="${sun.boot.class.path}" />
@@ -265,10 +264,12 @@
       includes="freemarker/core/_Java8Impl.java"
     />
 
-    <rmic
-      base="build/classes" includes="freemarker/debug/impl/Rmi*Impl.class"
-      classpathref="ivy.dep"
-      verify="yes" stubversion="1.2"
+    <ivy:cachepath conf="build.base" pathid="ivy.dep" />
+    <javac srcdir="build/src-main-java-filtered" destdir="build/classes" deprecation="off"
+           debug="on" optimize="off" release="16" encoding="utf-8"
+           includeantruntime="false"
+           classpathref="ivy.dep"
+           includes="freemarker/core/_Java16Impl.java"
     />
 
     <ivy:cachepath conf="build.jsp2.0" pathid="ivy.dep.jsp2.0" />
@@ -336,11 +337,6 @@
         freemarker/ext/jython/_Jython25VersionAdapter.java"
     />
 
-    <rmic base="build/classes" classpathref="ivy.dep"
-      includes="build/src-main-java-filtered/freemarker/debug/impl/Rmi*Impl.class"
-      verify="yes" stubversion="1.2"
-    />
-
     <copy toDir="build/classes">
       <fileset dir="src/main/resources"
         excludes="
@@ -364,11 +360,10 @@
 
     <ivy:cachepath conf="build.test" pathid="ivy.dep.build.test" />
     <javac srcdir="src/test/java" destdir="build/test-classes" deprecation="off"
-      debug="on" optimize="off" target="1.8" source="1.8" encoding="utf-8"
+      debug="on" optimize="off" release="16" encoding="utf-8"
       includeantruntime="false"
       classpath="build/classes"
       classpathref="ivy.dep.build.test"
-      bootclasspath="${boot.classpath.j2se1.8}"
     />
     <copy toDir="build/test-classes">
       <fileset dir="src/test/resources"
diff --git a/osgi.bnd b/osgi.bnd
index 3cf11c19..9345879f 100644
--- a/osgi.bnd
+++ b/osgi.bnd
@@ -49,10 +49,10 @@ Import-Package: !freemarker.*, *;resolution:="optional"
 # This is needed for "a.class.from.another.Bundle"?new() to work.
 DynamicImport-Package: *
 
-# The required minimum is 1.7, but we utilize versions up to 1.8 if available.
+# The required minimum is 1.7, but we utilize versions up to 16 if available.
 # See also: http://wiki.eclipse.org/Execution_Environments, "Compiling
 # against more than is required"
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8, JavaSE-1.7
+Bundle-RequiredExecutionEnvironment: JavaSE-16, JavaSE-1.7
 
 # Non-OSGi meta:
 Main-Class: freemarker.core.CommandLine
diff --git a/src/main/java/freemarker/core/_Java16.java b/src/main/java/freemarker/core/_Java16.java
new file mode 100644
index 00000000..84af6cd1
--- /dev/null
+++ b/src/main/java/freemarker/core/_Java16.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.core;
+
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * Used internally only, might change without notice!
+ * Used for accessing functionality that's only present in Java 8 or later.
+ */
+public interface _Java16 {
+
+    boolean isRecord(Class<?> cl);
+
+    Set<Method> getComponentAccessors(Class<?> recordClass);
+
+}
diff --git a/src/main/java/freemarker/core/_Java16Impl.java b/src/main/java/freemarker/core/_Java16Impl.java
new file mode 100644
index 00000000..ba1ba879
--- /dev/null
+++ b/src/main/java/freemarker/core/_Java16Impl.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package freemarker.core;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.RecordComponent;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+/**
+ * Used internally only, might change without notice!
+ * Used for accessing functionality that's only present in Java 16 or later.
+ */
+// Compile this against Java 16
+@SuppressWarnings("Since15") // For IntelliJ inspection
+public class _Java16Impl implements _Java16 {
+
+    public static final _Java16 INSTANCE = new _Java16Impl();
+
+    private _Java16Impl() {
+        // Not meant to be instantiated
+    }
+
+    @Override
+    public boolean isRecord(Class<?> cl) {
+        return cl.isRecord();
+    }
+
+    @Override
+    public Set<Method> getComponentAccessors(Class<?> recordType)  {
+        RecordComponent[] recordComponents = recordType.getRecordComponents();
+        if (recordComponents == null) {
+            throw new IllegalArgumentException("Argument must be a record type");
+        }
+        IdentityHashMap<Method, Void> methods = new IdentityHashMap<>(recordComponents.length);
+        for (RecordComponent recordComponent : recordComponents) {
+            methods.put(recordComponent.getAccessor(), null);
+        }
+        return methods.keySet();
+    }
+}
diff --git a/src/main/java/freemarker/core/_JavaVersions.java b/src/main/java/freemarker/core/_JavaVersions.java
index 5670c369..9023b642 100644
--- a/src/main/java/freemarker/core/_JavaVersions.java
+++ b/src/main/java/freemarker/core/_JavaVersions.java
@@ -31,28 +31,8 @@ public final class _JavaVersions {
         // Not meant to be instantiated
     }
 
-    private static final boolean IS_AT_LEAST_8;
-    static {
-        boolean result = false;
-        String vStr = SecurityUtilities.getSystemProperty("java.version", null);
-        if (vStr != null) {
-            try {
-                Version v = new Version(vStr);
-                result = v.getMajor() == 1 && v.getMinor() >= 8 || v.getMajor() > 1;
-            } catch (Exception e) {
-                // Ignore
-            }
-        } else {
-            try {
-                Class.forName("java.time.Instant");
-                result = true;
-            } catch (Exception e) {
-                // Ignore
-            }
-        }
-        IS_AT_LEAST_8 = result;
-    }
-    
+    private static final boolean IS_AT_LEAST_8 = isAtLeast(8, "java.time.Instant");
+
     /**
      * {@code null} if Java 8 is not available, otherwise the object through with the Java 8 operations are available.
      */
@@ -75,5 +55,51 @@ public final class _JavaVersions {
         }
         JAVA_8 = java8;
     }
-    
+
+    private static final boolean IS_AT_LEAST_16 = isAtLeast(16, "java.net.UnixDomainSocketAddress");
+
+    /**
+     * {@code null} if Java 8 is not available, otherwise the object through with the Java 8 operations are available.
+     */
+    static public final _Java16 JAVA_16;
+    static {
+        _Java16 java16;
+        if (IS_AT_LEAST_16) {
+            try {
+                java16 = (_Java16) Class.forName("freemarker.core._Java16Impl").getField("INSTANCE").get(null);
+            } catch (Exception e) {
+                try {
+                    Logger.getLogger("freemarker.runtime").error("Failed to access Java 16 functionality", e);
+                } catch (Exception e2) {
+                    // Suppressed
+                }
+                java16 = null;
+            }
+        } else {
+            java16 = null;
+        }
+        JAVA_16 = java16;
+    }
+
+    private static boolean isAtLeast(int minimumMinorVersion, String proofClassPresence) {
+        boolean result = false;
+        String vStr = SecurityUtilities.getSystemProperty("java.version", null);
+        if (vStr != null) {
+            try {
+                Version v = new Version(vStr);
+                result = v.getMajor() == 1 && v.getMinor() >= minimumMinorVersion || v.getMajor() > 1;
+            } catch (Exception e) {
+                // Ignore
+            }
+        } else {
+            try {
+                Class.forName(proofClassPresence);
+                result = true;
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+        return result;
+    }
+
 }
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index d9edddb2..e8f98da1 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -20,10 +20,7 @@
 <book conformance="docgen" version="5.0" xml:lang="en"
       xmlns="http://docbook.org/ns/docbook"
       xmlns:xlink="http://www.w3.org/1999/xlink"
-      xmlns:ns5="http://www.w3.org/1998/Math/MathML"
-      xmlns:ns4="http://www.w3.org/2000/svg"
-      xmlns:ns3="http://www.w3.org/1999/xhtml"
-      xmlns:ns="http://docbook.org/ns/docbook">
+>
   <info>
     <title>Apache FreeMarker Manual</title>
 
@@ -16105,8 +16102,9 @@ rif: foo XYr baar</programlisting>
                   setting</link> is less than 2.3.21: Gives what
                   <literal>java.text.DecimalFormat</literal> does with US
                   locale, which are <literal>∞</literal>,
-                  <literal>-∞</literal>, and <literal>�</literal> (U+FFFD,
-                  replacement character).</para>
+                  <literal>-∞</literal>, and <literal>NaN</literal> (before
+                  Java 11 was <literal>�</literal>, i.e., U+FFFD, replacement
+                  character).</para>
                 </listitem>
               </itemizedlist>
             </listitem>
@@ -30088,6 +30086,21 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               <literal>LookAheadSuccess</literal> with stack trace instance
               for each <literal>FMParser</literal> instance.</para>
             </listitem>
+
+            <listitem>
+              <para>We don't generate RMIC stub classes for
+              <literal>freemarker.debug.impl.Rmi*Impl</literal> classes
+              anymore. Almost nobody uses that API, but if you do, you
+              certainly already rely on dynamic stubs anyway. (The
+              <literal>rmic</literal> tool used to generate the stub classes
+              was removed from the JDK, starting with JDK 15.)</para>
+            </listitem>
+
+            <listitem>
+              <para>To build FreeMarker itself (not for just using it), now
+              you need JDK 16 (or later). This doesn't influence the minimum
+              Java version requirement for using FreeMarker.</para>
+            </listitem>
           </itemizedlist>
         </section>
       </section>