You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/07/10 05:47:16 UTC

[groovy] 02/02: Add `GroovyClassValuePreJava7` back for binary compatibility

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

sunlan pushed a commit to branch GROOVY-9631
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 8643cbf03de371895aa979ac77d30cc97e0b7585
Author: Daniel Sun <su...@apache.org>
AuthorDate: Fri Jul 10 13:44:09 2020 +0800

    Add `GroovyClassValuePreJava7` back for binary compatibility
---
 .../groovy/reflection/GroovyClassValueFactory.java |   7 +-
 .../reflection/GroovyClassValuePreJava7.java       | 107 +++++++++++++++++++++
 2 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
index b761895..0565f92 100644
--- a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.reflection;
 
+import org.apache.groovy.util.SystemUtil;
 import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
 import org.codehaus.groovy.reflection.v7.GroovyClassValueJava7;
 
@@ -28,7 +29,11 @@ class GroovyClassValueFactory {
 	 * See https://bugs.openjdk.java.net/browse/JDK-8136353
 	 * This issue does not exist on IBM Java (J9) so use ClassValue by default on that JVM.
 	 */
+	private static final boolean USE_CLASSVALUE = Boolean.parseBoolean(SystemUtil.getSystemPropertySafe("groovy.use.classvalue", "true"));
+
 	public static <T> GroovyClassValue<T> createGroovyClassValue(ComputeValue<T> computeValue) {
-		return new GroovyClassValueJava7<>(computeValue);
+		return (USE_CLASSVALUE)
+                ? new GroovyClassValueJava7<>(computeValue)
+                : new GroovyClassValuePreJava7<>(computeValue);
 	}
 }
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
new file mode 100644
index 0000000..7b95d64
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -0,0 +1,107 @@
+/*
+ *  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.codehaus.groovy.reflection;
+
+import org.codehaus.groovy.util.Finalizable;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+
+/** Approximation of Java 7's {@link java.lang.ClassValue} that works on earlier versions of Java.
+ * Note that this implementation isn't as good at Java 7's; it doesn't allow for some GC'ing that Java 7 would allow.
+ * But, it's good enough for our use.
+ *
+ * @param <T>
+ */
+@Deprecated
+class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
+	private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
+
+	private class EntryWithValue extends ManagedConcurrentMap.EntryWithValue<Class<?>,T>{
+
+		public EntryWithValue(GroovyClassValuePreJava7Segment segment, Class<?> key, int hash) {
+			super(weakBundle, segment, key, hash, computeValue.computeValue(key));
+		}
+
+		@Override
+		public void setValue(T value) {
+			if(value!=null) super.setValue(value);
+		}
+
+		@Override
+		public void finalizeReference() {
+			T value = getValue();
+			if (value instanceof Finalizable) {
+				((Finalizable) value).finalizeReference();
+			}
+			super.finalizeReference();
+		}
+	}
+
+	private class GroovyClassValuePreJava7Segment extends ManagedConcurrentMap.Segment<Class<?>,T> {
+
+        private static final long serialVersionUID = 1289753977947029168L;
+
+        GroovyClassValuePreJava7Segment(ReferenceBundle bundle, int initialCapacity) {
+			super(bundle, initialCapacity);
+		}
+
+		@Override
+		protected EntryWithValue createEntry(Class<?> key, int hash,
+				T unused) {
+			return new EntryWithValue(this, key, hash);
+		}
+	}
+
+	private class GroovyClassValuePreJava7Map extends ManagedConcurrentMap<Class<?>,T> {
+
+		public GroovyClassValuePreJava7Map() {
+			super(weakBundle);
+		}
+
+		@Override
+		protected GroovyClassValuePreJava7Segment createSegment(Object segmentInfo, int cap) {
+			ReferenceBundle bundle = (ReferenceBundle) segmentInfo;
+			if (bundle==null) throw new IllegalArgumentException("bundle must not be null ");
+			return new GroovyClassValuePreJava7Segment(bundle, cap);
+		}
+
+	}
+
+	private final ComputeValue<T> computeValue;
+
+	private final GroovyClassValuePreJava7Map map = new GroovyClassValuePreJava7Map();
+
+	public GroovyClassValuePreJava7(ComputeValue<T> computeValue){
+		this.computeValue = computeValue;
+	}
+
+	@Override
+	public T get(Class<?> type) {
+		// the value isn't use in the getOrPut call - see the EntryWithValue constructor above
+		T value = ((EntryWithValue)map.getOrPut(type, null)).getValue();
+		//all entries are guaranteed to be EntryWithValue. Value can only be null if computeValue returns null
+		return value;
+	}
+
+	@Override
+	public void remove(Class<?> type) {
+		map.remove(type);
+	}
+
+}