提交 b2a2c099 编写于 作者: M malenkov

7064279: Introspector.getBeanInfo() should release some resources in timely manner

Reviewed-by: art, alexp
上级 82b0bea5
......@@ -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();
/**
* <p>
......@@ -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);
}
}
......
......@@ -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<Class<?>, Method[]> declaredMethodCache =
new WeakCache<Class<?>, Method[]>();
private static final Object BEANINFO_CACHE = new Object();
private static final WeakCache<Class<?>, 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<Class<?>, BeanInfo> beanInfoCache;
ThreadGroupContext context = ThreadGroupContext.getContext();
BeanInfo beanInfo;
synchronized (BEANINFO_CACHE) {
beanInfoCache = (Map<Class<?>, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE);
if (beanInfoCache == null) {
beanInfoCache = new WeakHashMap<Class<?>, 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
......
......@@ -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);
}
}
/*
* 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<ThreadGroup, ThreadGroupContext> 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<Class<?>, 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;
}
}
......@@ -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");
}
......
......@@ -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");
}
......
......@@ -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;
}
}
/*
* 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);
}
}
......@@ -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");
......
......@@ -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;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册