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 2022/12/31 23:15:31 UTC

[freemarker] 04/09: Forward ported from 2.3-gae: FREEMARKER-198: To avoid deadlock when class initialization happens on multiple threads (like _TemplateAPI->DefaultObjectWrapper, and DefaultObjectWrapper->_TemplateAPI), factored out static fields from _TemplateAPI into their owns classes.

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

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

commit f27a127666c37e8400d8dd4cf079247e9e25605d
Author: ddekany <dd...@apache.org>
AuthorDate: Sat Dec 31 23:46:38 2022 +0100

    Forward ported from 2.3-gae: FREEMARKER-198: To avoid deadlock when class initialization happens on multiple threads (like _TemplateAPI->DefaultObjectWrapper, and DefaultObjectWrapper->_TemplateAPI), factored out static fields from _TemplateAPI into their owns classes.
---
 .../apache/freemarker/core/ConfigurationTest.java  | 85 ++++++----------------
 .../core/model/impl/DefaultObjectWrapperTest.java  | 60 +++------------
 .../org/apache/freemarker/core/NativeSequence.java | 10 +--
 .../java/org/apache/freemarker/core/_CoreAPI.java  |  6 +-
 .../org/apache/freemarker/core/_VersionInts.java   | 32 ++++++++
 5 files changed, 75 insertions(+), 118 deletions(-)

diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
index 8c1791de..f5486e5b 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -19,42 +19,11 @@
 
 package org.apache.freemarker.core;
 
-import static org.apache.freemarker.core.Configuration.*;
-import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
-import org.apache.freemarker.core.Configuration.*;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateStringModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.MemberAccessPolicy;
-import org.apache.freemarker.core.model.impl.MemberSelectorListMemberAccessPolicy;
-import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleString;
-import org.apache.freemarker.core.model.impl.WhitelistMemberAccessPolicy;
+import org.apache.freemarker.core.model.impl.*;
 import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
 import org.apache.freemarker.core.outputformat.OutputFormat;
 import org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
@@ -62,31 +31,9 @@ import org.apache.freemarker.core.outputformat.impl.CombinedMarkupOutputFormat;
 import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
 import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
 import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-import org.apache.freemarker.core.templateresolver.CacheStorageWithGetSize;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactoryException;
-import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
-import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
-import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
-import org.apache.freemarker.core.templateresolver.impl.NullCacheStorage;
-import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
-import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
-import org.apache.freemarker.core.userpkg.DummyOutputFormat;
-import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.NameClashingDummyOutputFormat;
-import org.apache.freemarker.core.userpkg.SeldomEscapedOutputFormat;
+import org.apache.freemarker.core.templateresolver.*;
+import org.apache.freemarker.core.templateresolver.impl.*;
+import org.apache.freemarker.core.userpkg.*;
 import org.apache.freemarker.core.util._CollectionUtils;
 import org.apache.freemarker.core.util._DateUtils;
 import org.apache.freemarker.core.util._NullWriter;
@@ -94,8 +41,22 @@ import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
 import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+import static org.apache.freemarker.core.Configuration.*;
+import static org.apache.freemarker.core.Configuration.ExtendableBuilder.*;
+import static org.apache.freemarker.test.hamcerst.Matchers.containsStringIgnoringCase;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 public class ConfigurationTest {
 
@@ -223,7 +184,7 @@ public class ConfigurationTest {
     @Test
     public void testVersion() {
         Version v = getVersion();
-        assertTrue(v.intValue() >= _CoreAPI.VERSION_INT_3_0_0);
+        assertTrue(v.intValue() >= _VersionInts.VERSION_INT_3_0_0);
         
         try {
             new Builder(new Version(999, 1, 2)).build();
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
index 010705c2..80d8096b 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
@@ -19,57 +19,21 @@
 
 package org.apache.freemarker.core.model.impl;
 
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.NonTemplateCallPlace;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core._CoreAPI;
-import org.apache.freemarker.core.model.AdapterTemplateModel;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.ObjectWrappingException;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateIterableModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.TemplateStringModel;
-import org.apache.freemarker.core.model.WrapperTemplateModel;
-import org.apache.freemarker.core.model.WrappingTemplateModel;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.freemarker.core.*;
+import org.apache.freemarker.core.model.*;
 import org.apache.freemarker.core.util.CallableUtils;
 import org.apache.freemarker.test.TestConfigurationBuilder;
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.*;
+
+import static org.apache.freemarker.test.hamcerst.Matchers.containsStringIgnoringCase;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 public class DefaultObjectWrapperTest {
 
@@ -83,7 +47,7 @@ public class DefaultObjectWrapperTest {
         expected.add(Configuration.VERSION_3_0_0);
 
         List<Version> actual = new ArrayList<>();
-        int i = _CoreAPI.VERSION_INT_3_0_0;
+        int i = _VersionInts.VERSION_INT_3_0_0;
         while (i <= Configuration.getVersion().intValue()) {
             int major = i / 1000000;
             int minor = i % 1000000 / 1000;
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
index a56febfc..cf99ea0e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/NativeSequence.java
@@ -19,17 +19,17 @@
 
 package org.apache.freemarker.core;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelIterator;
 import org.apache.freemarker.core.model.TemplateSequenceModel;
 
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+
 /**
- * A sequence where each items is already a {@link TemplateModel}, so no {@link ObjectWrapper} need to be specified.
+ * A sequence where each item is already a {@link TemplateModel}, so no {@link ObjectWrapper} need to be specified.
  *
  * <p>While this class allows adding items, doing so is not thread-safe, and thus only meant to be done during the
  * initialization of the sequence.
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_CoreAPI.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_CoreAPI.java
index 14de157d..b408c9e1 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_CoreAPI.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_CoreAPI.java
@@ -28,8 +28,8 @@ import org.apache.freemarker.core.util._NullArgumentException;
  * access things inside this package that users shouldn't. 
  */ 
 public final class _CoreAPI {
-
-    public static final int VERSION_INT_3_0_0 = Configuration.VERSION_3_0_0.intValue();
+    // ATTENTION! Don't refer to other classes in the static initializer of this class! Fields that need that must be
+    // moved into a separate class, to avoid class init deadlocks.
 
     // Can't be instantiated
     private _CoreAPI() { }
@@ -66,7 +66,7 @@ public final class _CoreAPI {
                     + incompatibleImprovements + ", but the installed FreeMarker version is only "
                     + Configuration.getVersion() + ". You may need to upgrade FreeMarker in your project.");
         }
-        if (iciV < VERSION_INT_3_0_0) {
+        if (iciV < _VersionInts.VERSION_INT_3_0_0) {
             throw new IllegalArgumentException("\"incompatibleImprovements\" must be at least 3.0.0, but was "
                     + incompatibleImprovements);
         }
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_VersionInts.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_VersionInts.java
new file mode 100644
index 00000000..711f4c3c
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_VersionInts.java
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.freemarker.core;
+
+/**
+ * For internal use only; don't depend on this, there's no backward compatibility guarantee at all!
+ * This class is to work around the lack of module system in Java, i.e., so that other FreeMarker packages can
+ * access things inside this package that users shouldn't.
+ */
+// Because we refer to other classes in the static initializer of this class, be careful with referring this class in
+// the static initializers of other classes, as that can lead to deadlock if the class initialization locks are acquired
+// by the JVM in different orders! This is also why this was extracted from _CoreAPI.
+public class _VersionInts {
+    public static final int VERSION_INT_3_0_0 = Configuration.VERSION_3_0_0.intValue();
+}