diff --git a/src/share/classes/java/beans/Beans.java b/src/share/classes/java/beans/Beans.java
index b71a2ac5a4d3b5d6f57a45e3cbcf9d6f1aa96188..03f0dc8d76e842233b488c508f33b6572ecda815 100644
--- a/src/share/classes/java/beans/Beans.java
+++ b/src/share/classes/java/beans/Beans.java
@@ -32,7 +32,6 @@ import java.applet.AppletContext;
import java.applet.AppletStub;
import java.applet.AudioClip;
-import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.beans.beancontext.BeanContext;
@@ -53,15 +52,11 @@ import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
-import sun.awt.AppContext;
-
/**
* This class provides some general purpose beans control methods.
*/
public class Beans {
- private static final Object DESIGN_TIME = new Object();
- private static final Object GUI_AVAILABLE = new Object();
/**
*
@@ -395,8 +390,7 @@ public class Beans {
* @see DesignMode
*/
public static boolean isDesignTime() {
- Object value = AppContext.getAppContext().get(DESIGN_TIME);
- return (value instanceof Boolean) && (Boolean) value;
+ return ThreadGroupContext.getContext().isDesignTime();
}
/**
@@ -413,8 +407,7 @@ public class Beans {
*
*/
public static boolean isGuiAvailable() {
- Object value = AppContext.getAppContext().get(GUI_AVAILABLE);
- return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless();
+ return ThreadGroupContext.getContext().isGuiAvailable();
}
/**
@@ -440,7 +433,7 @@ public class Beans {
if (sm != null) {
sm.checkPropertiesAccess();
}
- AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime));
+ ThreadGroupContext.getContext().setDesignTime(isDesignTime);
}
/**
@@ -466,7 +459,7 @@ public class Beans {
if (sm != null) {
sm.checkPropertiesAccess();
}
- AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable));
+ ThreadGroupContext.getContext().setGuiAvailable(isGuiAvailable);
}
}
diff --git a/src/share/classes/java/beans/Introspector.java b/src/share/classes/java/beans/Introspector.java
index 36ead726bd43a4a1382be5db5d412f810c2b87ae..2d85beef4c8b349ad1b61c70866843e53f76c5d1 100644
--- a/src/share/classes/java/beans/Introspector.java
+++ b/src/share/classes/java/beans/Introspector.java
@@ -26,7 +26,6 @@
package java.beans;
import com.sun.beans.WeakCache;
-import com.sun.beans.finder.BeanInfoFinder;
import com.sun.beans.finder.ClassFinder;
import java.awt.Component;
@@ -44,9 +43,7 @@ import java.util.EventListener;
import java.util.EventObject;
import java.util.List;
import java.util.TreeMap;
-import java.util.WeakHashMap;
-import sun.awt.AppContext;
import sun.reflect.misc.ReflectUtil;
/**
@@ -98,10 +95,7 @@ public class Introspector {
public final static int IGNORE_ALL_BEANINFO = 3;
// Static Caches to speed up introspection.
- private static WeakCache, Method[]> declaredMethodCache =
- new WeakCache, Method[]>();
-
- private static final Object BEANINFO_CACHE = new Object();
+ private static final WeakCache, Method[]> declaredMethodCache = new WeakCache<>();
private Class beanClass;
private BeanInfo explicitBeanInfo;
@@ -134,8 +128,6 @@ public class Introspector {
static final String SET_PREFIX = "set";
static final String IS_PREFIX = "is";
- private static final Object FINDER_KEY = new Object();
-
//======================================================================
// Public methods
//======================================================================
@@ -160,20 +152,15 @@ public class Introspector {
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
- Map, BeanInfo> beanInfoCache;
+ ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
- synchronized (BEANINFO_CACHE) {
- beanInfoCache = (Map, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE);
- if (beanInfoCache == null) {
- beanInfoCache = new WeakHashMap, BeanInfo>();
- AppContext.getAppContext().put(BEANINFO_CACHE, beanInfoCache);
- }
- beanInfo = beanInfoCache.get(beanClass);
+ synchronized (declaredMethodCache) {
+ beanInfo = context.getBeanInfo(beanClass);
}
if (beanInfo == null) {
beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
- synchronized (BEANINFO_CACHE) {
- beanInfoCache.put(beanClass, beanInfo);
+ synchronized (declaredMethodCache) {
+ context.putBeanInfo(beanClass, beanInfo);
}
}
return beanInfo;
@@ -306,7 +293,7 @@ public class Introspector {
*/
public static String[] getBeanInfoSearchPath() {
- return getFinder().getPackages();
+ return ThreadGroupContext.getContext().getBeanInfoFinder().getPackages();
}
/**
@@ -330,7 +317,7 @@ public class Introspector {
if (sm != null) {
sm.checkPropertiesAccess();
}
- getFinder().setPackages(path);
+ ThreadGroupContext.getContext().getBeanInfoFinder().setPackages(path);
}
@@ -342,11 +329,8 @@ public class Introspector {
*/
public static void flushCaches() {
- synchronized (BEANINFO_CACHE) {
- Map beanInfoCache = (Map) AppContext.getAppContext().get(BEANINFO_CACHE);
- if (beanInfoCache != null) {
- beanInfoCache.clear();
- }
+ synchronized (declaredMethodCache) {
+ ThreadGroupContext.getContext().clearBeanInfoCache();
declaredMethodCache.clear();
}
}
@@ -370,11 +354,8 @@ public class Introspector {
if (clz == null) {
throw new NullPointerException();
}
- synchronized (BEANINFO_CACHE) {
- Map beanInfoCache = (Map) AppContext.getAppContext().get(BEANINFO_CACHE);
- if (beanInfoCache != null) {
- beanInfoCache.put(clz, null);
- }
+ synchronized (declaredMethodCache) {
+ ThreadGroupContext.getContext().removeBeanInfo(clz);
declaredMethodCache.put(clz, null);
}
}
@@ -452,7 +433,7 @@ public class Introspector {
* @return Instance of an explicit BeanInfo class or null if one isn't found.
*/
private static BeanInfo findExplicitBeanInfo(Class beanClass) {
- return getFinder().find(beanClass);
+ return ThreadGroupContext.getContext().getBeanInfoFinder().find(beanClass);
}
/**
@@ -1275,7 +1256,7 @@ public class Introspector {
if (!ReflectUtil.isPackageAccessible(clz)) {
return new Method[0];
}
- synchronized (BEANINFO_CACHE) {
+ synchronized (declaredMethodCache) {
Method[] result = declaredMethodCache.get(clz);
if (result == null) {
result = clz.getMethods();
@@ -1426,17 +1407,6 @@ public class Introspector {
return false;
}
- private static BeanInfoFinder getFinder() {
- AppContext context = AppContext.getAppContext();
- Object object = context.get(FINDER_KEY);
- if (object instanceof BeanInfoFinder) {
- return (BeanInfoFinder) object;
- }
- BeanInfoFinder finder = new BeanInfoFinder();
- context.put(FINDER_KEY, finder);
- return finder;
- }
-
/**
* Try to create an instance of a named class.
* First try the classloader of "sibling", then try the system
diff --git a/src/share/classes/java/beans/PropertyEditorManager.java b/src/share/classes/java/beans/PropertyEditorManager.java
index 6bdfa95f41b786c49b76913b3a1865a653ec4dd2..3fee3f40887277e7a7715c49cb71e7abc048d49b 100644
--- a/src/share/classes/java/beans/PropertyEditorManager.java
+++ b/src/share/classes/java/beans/PropertyEditorManager.java
@@ -25,9 +25,6 @@
package java.beans;
-import com.sun.beans.finder.PropertyEditorFinder;
-import sun.awt.AppContext;
-
/**
* The PropertyEditorManager can be used to locate a property editor for
* any given type name. This property editor must support the
@@ -55,8 +52,6 @@ import sun.awt.AppContext;
public class PropertyEditorManager {
- private static final Object FINDER_KEY = new Object();
-
/**
* Registers an editor class to edit values of the given target class.
* If the editor class is {@code null},
@@ -81,7 +76,7 @@ public class PropertyEditorManager {
if (sm != null) {
sm.checkPropertiesAccess();
}
- getFinder().register(targetType, editorClass);
+ ThreadGroupContext.getContext().getPropertyEditorFinder().register(targetType, editorClass);
}
/**
@@ -92,7 +87,7 @@ public class PropertyEditorManager {
* The result is null if no suitable editor can be found.
*/
public static PropertyEditor findEditor(Class> targetType) {
- return getFinder().find(targetType);
+ return ThreadGroupContext.getContext().getPropertyEditorFinder().find(targetType);
}
/**
@@ -104,7 +99,7 @@ public class PropertyEditorManager {
* e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/
public static String[] getEditorSearchPath() {
- return getFinder().getPackages();
+ return ThreadGroupContext.getContext().getPropertyEditorFinder().getPackages();
}
/**
@@ -125,17 +120,6 @@ public class PropertyEditorManager {
if (sm != null) {
sm.checkPropertiesAccess();
}
- getFinder().setPackages(path);
- }
-
- private static PropertyEditorFinder getFinder() {
- AppContext context = AppContext.getAppContext();
- Object object = context.get(FINDER_KEY);
- if (object instanceof PropertyEditorFinder) {
- return (PropertyEditorFinder) object;
- }
- PropertyEditorFinder finder = new PropertyEditorFinder();
- context.put(FINDER_KEY, finder);
- return finder;
+ ThreadGroupContext.getContext().getPropertyEditorFinder().setPackages(path);
}
}
diff --git a/src/share/classes/java/beans/ThreadGroupContext.java b/src/share/classes/java/beans/ThreadGroupContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc1d38a1457705a695c4f19e49b9824efbf66fa8
--- /dev/null
+++ b/src/share/classes/java/beans/ThreadGroupContext.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.beans;
+
+import com.sun.beans.finder.BeanInfoFinder;
+import com.sun.beans.finder.PropertyEditorFinder;
+
+import java.awt.GraphicsEnvironment;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * The {@code ThreadGroupContext} is an application-dependent
+ * context referenced by the specific {@link ThreadGroup}.
+ * This is a replacement for the {@link sun.awt.AppContext}.
+ *
+ * @author Sergey Malenkov
+ */
+final class ThreadGroupContext {
+
+ private static final Map contexts = new WeakHashMap<>();
+
+ /**
+ * Returns the appropriate {@code AppContext} for the caller,
+ * as determined by its {@code ThreadGroup}.
+ *
+ * @return the application-dependent context
+ */
+ static ThreadGroupContext getContext() {
+ ThreadGroup group = Thread.currentThread().getThreadGroup();
+ synchronized (contexts) {
+ ThreadGroupContext context = contexts.get(group);
+ if (context == null) {
+ context = new ThreadGroupContext();
+ contexts.put(group, context);
+ }
+ return context;
+ }
+ }
+
+ private volatile boolean isDesignTime;
+ private volatile Boolean isGuiAvailable;
+
+ private Map, BeanInfo> beanInfoCache;
+ private BeanInfoFinder beanInfoFinder;
+ private PropertyEditorFinder propertyEditorFinder;
+
+
+ boolean isDesignTime() {
+ return this.isDesignTime;
+ }
+
+ void setDesignTime(boolean isDesignTime) {
+ this.isDesignTime = isDesignTime;
+ }
+
+
+ boolean isGuiAvailable() {
+ Boolean isGuiAvailable = this.isGuiAvailable;
+ return (isGuiAvailable != null)
+ ? isGuiAvailable.booleanValue()
+ : !GraphicsEnvironment.isHeadless();
+ }
+
+ void setGuiAvailable(boolean isGuiAvailable) {
+ this.isGuiAvailable = Boolean.valueOf(isGuiAvailable);
+ }
+
+
+ BeanInfo getBeanInfo(Class> type) {
+ return (this.beanInfoCache != null)
+ ? this.beanInfoCache.get(type)
+ : null;
+ }
+
+ BeanInfo putBeanInfo(Class> type, BeanInfo info) {
+ if (this.beanInfoCache == null) {
+ this.beanInfoCache = new WeakHashMap<>();
+ }
+ return this.beanInfoCache.put(type, info);
+ }
+
+ void removeBeanInfo(Class> type) {
+ if (this.beanInfoCache != null) {
+ this.beanInfoCache.remove(type);
+ }
+ }
+
+ void clearBeanInfoCache() {
+ if (this.beanInfoCache != null) {
+ this.beanInfoCache.clear();
+ }
+ }
+
+
+ synchronized BeanInfoFinder getBeanInfoFinder() {
+ if (this.beanInfoFinder == null) {
+ this.beanInfoFinder = new BeanInfoFinder();
+ }
+ return this.beanInfoFinder;
+ }
+
+ synchronized PropertyEditorFinder getPropertyEditorFinder() {
+ if (this.propertyEditorFinder == null) {
+ this.propertyEditorFinder = new PropertyEditorFinder();
+ }
+ return this.propertyEditorFinder;
+ }
+}
diff --git a/test/java/beans/Beans/6669869/TestDesignTime.java b/test/java/beans/Beans/6669869/TestDesignTime.java
index b73cee4bbfd0304055b74e30ae8622ab85fbd782..731ab4a9f4b6c4400ebfa8c72a68fe720e4430fd 100644
--- a/test/java/beans/Beans/6669869/TestDesignTime.java
+++ b/test/java/beans/Beans/6669869/TestDesignTime.java
@@ -29,7 +29,6 @@
*/
import java.beans.Beans;
-import sun.awt.SunToolkit;
public class TestDesignTime implements Runnable {
public static void main(String[] args) throws InterruptedException {
@@ -44,7 +43,6 @@ public class TestDesignTime implements Runnable {
}
public void run() {
- SunToolkit.createNewAppContext();
if (Beans.isDesignTime()) {
throw new Error("shared DesignTime property");
}
diff --git a/test/java/beans/Beans/6669869/TestGuiAvailable.java b/test/java/beans/Beans/6669869/TestGuiAvailable.java
index 615688286b3866092c6b59103ca06188f9c01526..67d88ae34f5c8d8f0a8163f0038dd62215ab84f8 100644
--- a/test/java/beans/Beans/6669869/TestGuiAvailable.java
+++ b/test/java/beans/Beans/6669869/TestGuiAvailable.java
@@ -30,7 +30,6 @@
import java.awt.GraphicsEnvironment;
import java.beans.Beans;
-import sun.awt.SunToolkit;
public class TestGuiAvailable implements Runnable {
public static void main(String[] args) throws InterruptedException {
@@ -45,7 +44,6 @@ public class TestGuiAvailable implements Runnable {
}
public void run() {
- SunToolkit.createNewAppContext();
if (Beans.isGuiAvailable() == GraphicsEnvironment.isHeadless()) {
throw new Error("shared GuiAvailable property");
}
diff --git a/test/java/beans/Introspector/6380849/TestBeanInfo.java b/test/java/beans/Introspector/6380849/TestBeanInfo.java
index 8232756d7bc36d72ed04f4e9db47aa4490836acf..6d685350412547578df372b0395573a7429d54f5 100644
--- a/test/java/beans/Introspector/6380849/TestBeanInfo.java
+++ b/test/java/beans/Introspector/6380849/TestBeanInfo.java
@@ -41,8 +41,6 @@ import java.beans.Introspector;
import java.lang.ref.Reference;
import java.lang.reflect.Field;
-import sun.awt.SunToolkit;
-
public class TestBeanInfo implements Runnable {
private static final String[] SEARCH_PATH = { "infos" }; // NON-NLS: package name
@@ -81,9 +79,6 @@ public class TestBeanInfo implements Runnable {
private boolean passed;
public void run() {
- if (this.passed) {
- SunToolkit.createNewAppContext();
- }
Introspector.flushCaches();
test(FirstBean.class, FirstBeanBeanInfo.class);
@@ -98,7 +93,5 @@ public class TestBeanInfo implements Runnable {
test(SecondBean.class, SecondBeanBeanInfo.class);
test(ThirdBean.class, null);
test(ThirdBeanBeanInfo.class, ThirdBeanBeanInfo.class);
-
- this.passed = true;
}
}
diff --git a/test/java/beans/Introspector/7064279/Test7064279.java b/test/java/beans/Introspector/7064279/Test7064279.java
new file mode 100644
index 0000000000000000000000000000000000000000..91d10fe7d4208f6440ebc6f74498cf60bb185915
--- /dev/null
+++ b/test/java/beans/Introspector/7064279/Test7064279.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7064279
+ * @summary Tests that Introspector does not have strong references to context class loader
+ * @author Sergey Malenkov
+ */
+
+import java.beans.Introspector;
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+public class Test7064279 {
+
+ public static void main(String[] args) throws Exception {
+ WeakReference ref = new WeakReference(test("test.jar", "test.Test"));
+ try {
+ int[] array = new int[1024];
+ while (true) {
+ array = new int[array.length << 1];
+ }
+ }
+ catch (OutOfMemoryError error) {
+ System.gc();
+ }
+ if (null != ref.get()) {
+ throw new Error("ClassLoader is not released");
+ }
+ }
+
+ private static Object test(String jarName, String className) throws Exception {
+ StringBuilder sb = new StringBuilder(256);
+ sb.append("file:");
+ sb.append(System.getProperty("test.src", "."));
+ sb.append(File.separatorChar);
+ sb.append(jarName);
+
+ ClassLoader newLoader = new URLClassLoader(new URL[] { new URL(sb.toString()) });
+ ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
+
+ Thread.currentThread().setContextClassLoader(newLoader);
+ test(newLoader.loadClass(className));
+ Thread.currentThread().setContextClassLoader(oldLoader);
+
+ return newLoader;
+ }
+
+ private static void test(Class type) throws Exception {
+ Introspector.getBeanInfo(type);
+ }
+}
diff --git a/test/java/beans/Introspector/7064279/test.jar b/test/java/beans/Introspector/7064279/test.jar
new file mode 100644
index 0000000000000000000000000000000000000000..7516a335f766541beeef3cf70ec4772be684cc14
Binary files /dev/null and b/test/java/beans/Introspector/7064279/test.jar differ
diff --git a/test/java/beans/Introspector/Test6660539.java b/test/java/beans/Introspector/Test6660539.java
index d1cb62827627cc767e9519a0ac1cfc6bbaa60ea7..349f1b3930b0bdf5ddeff4ec9865620a70c57735 100644
--- a/test/java/beans/Introspector/Test6660539.java
+++ b/test/java/beans/Introspector/Test6660539.java
@@ -28,8 +28,6 @@
* @author Sergey Malenkov
*/
-import sun.awt.SunToolkit;
-
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
@@ -49,7 +47,6 @@ public class Test6660539 implements Runnable {
}
public void run() {
- SunToolkit.createNewAppContext();
for (PropertyDescriptor pd : getPropertyDescriptors()) {
if (pd.getDisplayName().equals(NAME))
throw new Error("shared BeanInfo cache");
diff --git a/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java b/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java
index 5d42144764049f19333137d3020f74e7376761fa..e07254a2d169163aff45f4226f58aefd575f9c35 100644
--- a/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java
+++ b/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java
@@ -36,7 +36,6 @@ import java.awt.Font;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
-import sun.awt.SunToolkit;
import sun.beans.editors.BooleanEditor;
import sun.beans.editors.ByteEditor;
import sun.beans.editors.ColorEditor;
@@ -77,12 +76,7 @@ public class TestPropertyEditor implements Runnable {
}
}
- private boolean passed;
-
public void run() {
- if (this.passed) {
- SunToolkit.createNewAppContext();
- }
PropertyEditorManager.registerEditor(ThirdBean.class, ThirdBeanEditor.class);
test(FirstBean.class, FirstBeanEditor.class);
@@ -135,7 +129,5 @@ public class TestPropertyEditor implements Runnable {
test(Color.class, null);
test(Font.class, null);
test(Enumeration.class, EnumEditor.class);
-
- this.passed = true;
}
}