Skip to content

Commit

Permalink
Statically linked JavaNImpl classes, utilizing "JEP 238: Multi-Releas…
Browse files Browse the repository at this point in the history
…e JAR Files"
  • Loading branch information
ddekany committed Jul 9, 2024
1 parent ec3fd7c commit f292ff3
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 123 deletions.
5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -144,6 +144,9 @@ tasks.sourcesJar.configure {
into("META-INF")
}

exclude("freemarker/core/_Java9Impl.java")
exclude("freemarker/core/_Java16Impl.java")

// Depend on the createBuildInfo task and include the generated file
dependsOn(createBuildInfo)
from(buildInfoFile())
Expand Down
9 changes: 9 additions & 0 deletions freemarker-core/src/main/java/freemarker/core/_Java16.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
* Used for accessing functionality that's only present in Java 16 or later.
*/
public interface _Java16 {
/**
* Using "JEP 238: Multi-Release JAR Files", links to the proper version of the {@link _Java16Impl} class.
*/
_Java16 INSTANCE = new _Java16Impl();

/**
* Tells if Java 16 features can be used in the current run-time environment.
*/
boolean isSupported();

boolean isRecord(Class<?> cl);

Expand Down
50 changes: 50 additions & 0 deletions freemarker-core/src/main/java/freemarker/core/_Java16Impl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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!
* Pre-Java-16 implementation of {@link _Java16}.
*/
// We also have a Java 16 versions of this class in freemarker-core16, and we put all versions into
// the jar artifact via "JEP 238: Multi-Release JAR Files".
public final class _Java16Impl implements _Java16 {
@Override
public boolean isSupported() {
return false;
}

@Override
public boolean isRecord(Class<?> cl) {
throw newNoRecordSupportException();
}

@Override
public Set<Method> getComponentAccessors(Class<?> recordClass){
throw newNoRecordSupportException();
}

private UnsupportedOperationException newNoRecordSupportException() {
return new UnsupportedOperationException("Record support needs at least Java 16");
}
}
9 changes: 9 additions & 0 deletions freemarker-core/src/main/java/freemarker/core/_Java9.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
* Used for accessing functionality that's only present in Java 9 or later.
*/
public interface _Java9 {
/**
* Using "JEP 238: Multi-Release JAR Files", links to the proper version of the {@link _Java9Impl} class.
*/
_Java9 INSTANCE = new _Java9Impl();

/**
* Tells if Java 9 features can be used in the current run-time environment.
*/
boolean isSupported();

boolean isAccessibleAccordingToModuleExports(Class<?> m);

Expand Down
38 changes: 38 additions & 0 deletions freemarker-core/src/main/java/freemarker/core/_Java9Impl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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!
* Pre-Java-9 implementation of {@link _Java9}.
*/
// We also have a Java 9 versions of this class in freemarker-core9, and we put all versions into
// the jar artifact via "JEP 238: Multi-Release JAR Files".
public class _Java9Impl implements _Java9 {
@Override
public boolean isSupported() {
return false;
}

@Override
public boolean isAccessibleAccordingToModuleExports(Class<?> m) {
throw new UnsupportedOperationException("Requires at least Java 9");
}
}
95 changes: 0 additions & 95 deletions freemarker-core/src/main/java/freemarker/core/_JavaVersions.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
import java.util.concurrent.ConcurrentHashMap;

import freemarker.core.BugException;
import freemarker.core._JavaVersions;
import freemarker.core._Java16;
import freemarker.core._Java9;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecisionInput;
import freemarker.ext.util.ModelCache;
Expand Down Expand Up @@ -200,7 +201,7 @@ class ClassIntrospector {
this.defaultZeroArgumentNonVoidMethodPolicy = builder.getDefaultZeroArgumentNonVoidMethodPolicy();
this.recordZeroArgumentNonVoidMethodPolicy = builder.getRecordZeroArgumentNonVoidMethodPolicy();
this.recordAware = defaultZeroArgumentNonVoidMethodPolicy != recordZeroArgumentNonVoidMethodPolicy;
if (recordAware && _JavaVersions.JAVA_16 == null) {
if (recordAware && !_Java16.INSTANCE.isSupported()) {
throw new IllegalArgumentException(
"defaultZeroArgumentNonVoidMethodPolicy != recordZeroArgumentNonVoidMethodPolicy, " +
"but record support is not available (as Java 16 support is not available).");
Expand Down Expand Up @@ -343,7 +344,7 @@ private void addBeanInfoToClassIntrospectionData(
ClassMemberAccessPolicy effClassMemberAccessPolicy) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);

boolean treatClassAsRecord = recordAware && _JavaVersions.JAVA_16.isRecord(clazz);
boolean treatClassAsRecord = recordAware && _Java16.INSTANCE.isRecord(clazz);
ZeroArgumentNonVoidMethodPolicy zeroArgumentNonVoidMethodPolicy = treatClassAsRecord
? recordZeroArgumentNonVoidMethodPolicy
: defaultZeroArgumentNonVoidMethodPolicy;
Expand Down Expand Up @@ -835,7 +836,7 @@ private static Map<ExecutableMemberSignature, List<Method>> discoverAccessibleMe
private static void discoverAccessibleMethods(
Class<?> clazz, Map<ExecutableMemberSignature, List<Method>> accessibles) {
if (Modifier.isPublic(clazz.getModifiers())
&& (_JavaVersions.JAVA_9 == null || _JavaVersions.JAVA_9.isAccessibleAccordingToModuleExports(clazz))) {
&& (!_Java9.INSTANCE.isSupported() || _Java9.INSTANCE.isAccessibleAccordingToModuleExports(clazz))) {
try {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import java.util.Iterator;
import java.util.Map;

import freemarker.core._JavaVersions;
import freemarker.core._Java16;
import freemarker.template.Configuration;
import freemarker.template.Version;
import freemarker.template._TemplateAPI;
Expand Down Expand Up @@ -76,9 +76,10 @@ final class ClassIntrospectorBuilder implements Cloneable {
this.incompatibleImprovements = normalizeIncompatibleImprovementsVersion(incompatibleImprovements);
treatDefaultMethodsAsBeanMembers = incompatibleImprovements.intValue() >= _VersionInts.V_2_3_26;
defaultZeroArgumentNonVoidMethodPolicy = ZeroArgumentNonVoidMethodPolicy.METHOD_ONLY;
recordZeroArgumentNonVoidMethodPolicy = incompatibleImprovements.intValue() >= _VersionInts.V_2_3_33 && _JavaVersions.JAVA_16 != null
? ZeroArgumentNonVoidMethodPolicy.BOTH_METHOD_AND_PROPERTY_UNLESS_BEAN_PROPERTY_READ_METHOD
: defaultZeroArgumentNonVoidMethodPolicy;
recordZeroArgumentNonVoidMethodPolicy
= incompatibleImprovements.intValue() >= _VersionInts.V_2_3_33 && _Java16.INSTANCE.isSupported()
? ZeroArgumentNonVoidMethodPolicy.BOTH_METHOD_AND_PROPERTY_UNLESS_BEAN_PROPERTY_READ_METHOD
: defaultZeroArgumentNonVoidMethodPolicy;
memberAccessPolicy = DefaultMemberAccessPolicy.getInstance(this.incompatibleImprovements);
}

Expand Down
13 changes: 6 additions & 7 deletions freemarker-core16/src/main/java/freemarker/core/_Java16Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@

/**
* Used internally only, might change without notice!
* Used for accessing functionality that's only present in Java 16 or later.
* Java 16 implementation of {@link _Java16}.
*/
// Compile this against Java 16
// We also have a pre-Java-16 versions of this class in freemarker-core, and we put all versions into
// the jar artifact via "JEP 238: Multi-Release JAR Files".
@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 isSupported() {
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.ext.beans;

import static org.junit.Assert.*;

import org.junit.Test;

import freemarker.core._Java16;
import freemarker.core._Java16Impl;

public class Java16TestClassLoadingCorrectTest {
@Test
public void java16Supported() {
// This can be a problem if the test is not ran from the jar, and the impl class from the core takes precedence
assertTrue(
"Multi-Release JAR selection of the proper " + _Java16Impl.class.getName() + " variant didn't happen in the Java 16 test environment",
_Java16.INSTANCE.isSupported());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import freemarker.core._Java16;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateMethodModelEx;

Expand All @@ -42,6 +43,8 @@
public class NotExportedInternalPackageTest {
@Test
public void java16InternalClassAvoidanceTest() throws Exception {
assertTrue(_Java16.INSTANCE.isSupported());

BeansWrapper bw = new BeansWrapper();

Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
Expand Down
13 changes: 6 additions & 7 deletions freemarker-core9/src/main/java/freemarker/core/_Java9Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@

/**
* Used internally only, might change without notice!
* Used for accessing functionality that's only present in Java 9 or later.
* Java 9 implementation of {@link _Java9}.
*/
// Compile this against Java 9
// We also have a pre-Java-9 versions of this class in freemarker-core, and we put all versions into
// the jar artifact via "JEP 238: Multi-Release JAR Files".
@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 isSupported() {
return true;
}

@Override
Expand Down
Loading

0 comments on commit f292ff3

Please sign in to comment.