Added support class to access Java 9 module API
diff --git a/build.gradle.kts b/build.gradle.kts
index e34574c..548df91 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -20,7 +20,7 @@
import java.io.FileOutputStream
import java.nio.charset.StandardCharsets
import java.nio.file.Files
-import java.util.Properties
+import java.util.*
import java.util.stream.Collectors
plugins {
@@ -61,7 +61,11 @@
configureSourceSet("jython20")
configureSourceSet("jython22")
configureSourceSet("jython25") { enableTests() }
- configureSourceSet("core16", "16") { enableTests() }
+ configureSourceSet("core9", "9") { enableTests() }
+ configureSourceSet("core16", "16") {
+ enableTests();
+ addDependencySourceSet("core9");
+ }
configureGeneratedSourceSet("jakartaServlet") {
val jakartaSourceGenerators = generateJakartaSources("javaxServlet")
@@ -589,6 +593,7 @@
// so make a best effort for a combined classpath.
plusConfigurations = listOf(
configurations["combinedClasspath"],
+ configurations["core9CompileClasspath"],
configurations["core16CompileClasspath"],
configurations["testUtilsCompileClasspath"],
configurations["javaxServletTestCompileClasspath"]
diff --git a/buildSrc/src/main/kotlin/freemarker/build/FreemarkerRootExtension.kt b/buildSrc/src/main/kotlin/freemarker/build/FreemarkerRootExtension.kt
index ff23f7a..35dd452 100644
--- a/buildSrc/src/main/kotlin/freemarker/build/FreemarkerRootExtension.kt
+++ b/buildSrc/src/main/kotlin/freemarker/build/FreemarkerRootExtension.kt
@@ -19,7 +19,6 @@
package freemarker.build
-import java.util.concurrent.atomic.AtomicBoolean
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
@@ -36,14 +35,11 @@
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.named
-import org.gradle.kotlin.dsl.register
-import org.gradle.kotlin.dsl.setProperty
-import org.gradle.kotlin.dsl.the
+import org.gradle.kotlin.dsl.*
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.language.jvm.tasks.ProcessResources
import org.gradle.testing.base.TestingExtension
+import java.util.concurrent.atomic.AtomicBoolean
private const val TEST_UTILS_SOURCE_SET_NAME = "test-utils"
@@ -146,6 +142,11 @@
}
}
+ fun addDependencySourceSet(dependencySourceSetName: String) {
+ val dependencySourceSet = context.sourceSets.named(dependencySourceSetName).get();
+ context.inheritCompileRuntimeAndOutput(sourceSet, dependencySourceSet)
+ }
+
fun enableTests(testJavaVersion: String = ext.testJavaVersion) =
configureTests(JavaLanguageVersion.of(testJavaVersion))
diff --git a/freemarker-core/src/main/java/freemarker/core/_Java9.java b/freemarker-core/src/main/java/freemarker/core/_Java9.java
new file mode 100644
index 0000000..6f1a56e
--- /dev/null
+++ b/freemarker-core/src/main/java/freemarker/core/_Java9.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * Used internally only, might change without notice!
+ * Used for accessing functionality that's only present in Java 9 or later.
+ */
+public interface _Java9 {
+
+ boolean isAccessibleAccordingToModuleExports(Class<?> m);
+
+}
diff --git a/freemarker-core/src/main/java/freemarker/core/_JavaVersions.java b/freemarker-core/src/main/java/freemarker/core/_JavaVersions.java
index c47d936..4a3957e 100644
--- a/freemarker-core/src/main/java/freemarker/core/_JavaVersions.java
+++ b/freemarker-core/src/main/java/freemarker/core/_JavaVersions.java
@@ -32,6 +32,13 @@
}
/**
+ * {@code null} if Java 9 is not available, otherwise the object through with the Java 9 operations are available.
+ */
+ static public final _Java9 JAVA_9 = isAtLeast(9, "java.lang.Module")
+ ? tryLoadJavaSupportSingleton(9, _Java9.class)
+ : null;
+
+ /**
* {@code null} if Java 16 is not available, otherwise the object through with the Java 16 operations are available.
*/
static public final _Java16 JAVA_16 = isAtLeast(16, "java.net.UnixDomainSocketAddress")
diff --git a/freemarker-core9/src/main/java/freemarker/core/_Java9Impl.java b/freemarker-core9/src/main/java/freemarker/core/_Java9Impl.java
new file mode 100644
index 0000000..700d801
--- /dev/null
+++ b/freemarker-core9/src/main/java/freemarker/core/_Java9Impl.java
@@ -0,0 +1,46 @@
+/*
+ * 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 freemarker.ext.beans.BeansWrapper;
+
+/**
+ * Used internally only, might change without notice!
+ * Used for accessing functionality that's only present in Java 9 or later.
+ */
+// Compile this against Java 9
+@SuppressWarnings("Since15") // For IntelliJ inspection
+public class _Java9Impl implements _Java9 {
+
+ public static final _Java9 INSTANCE = new _Java9Impl();
+
+ private static final Module ACCESSOR_MODULE = BeansWrapper.class.getModule();
+
+ private _Java9Impl() {
+ // Not meant to be instantiated
+ }
+
+ @Override
+ public boolean isAccessibleAccordingToModuleExports(Class<?> accessedClass) {
+ Module accessedModule = accessedClass.getModule();
+ Package accessedPackage = accessedClass.getPackage();
+
+ return accessedModule.isExported(accessedPackage.getName(), ACCESSOR_MODULE);
+ }
+}
diff --git a/freemarker-core9/src/test/java/freemarker/core/Java9ImplTest.java b/freemarker-core9/src/test/java/freemarker/core/Java9ImplTest.java
new file mode 100644
index 0000000..35cd1a4
--- /dev/null
+++ b/freemarker-core9/src/test/java/freemarker/core/Java9ImplTest.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 static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Method;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class Java9ImplTest {
+
+ @Test
+ public void testIsAccessibleAccordingToModuleExports() throws Exception {
+ assertNotNull(_JavaVersions.JAVA_9);
+ assertTrue(_JavaVersions.JAVA_9.isAccessibleAccordingToModuleExports(Document.class));
+ assertFalse(_JavaVersions.JAVA_9.isAccessibleAccordingToModuleExports(getSomeInternalClass()));
+ }
+
+ private static Class<?> getSomeInternalClass() throws SAXException, IOException, ParserConfigurationException,
+ NoSuchMethodException {
+ Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new InputSource(new StringReader("<a></a>")));
+
+ Method internalClassMethod = document.getClass().getMethod("getDocumentElement");
+ Class<?> internalClass = internalClassMethod.getDeclaringClass();
+ assertThat(internalClass.getName(), Matchers.startsWith("com."));
+
+ return internalClass;
+ }
+}