6397609: DOC: De-register API required for PropertyEditorManager and/or doc change
Reviewed-by: peterz, rupashka
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/beans/WeakCache.java Wed Sep 03 21:00:04 2008 +0400
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.beans;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * A hashtable-based cache with weak keys and weak values.
+ * An entry in the map will be automatically removed
+ * when its key is no longer in the ordinary use.
+ * A value will be automatically removed as well
+ * when it is no longer in the ordinary use.
+ *
+ * @since 1.7
+ *
+ * @author Sergey A. Malenkov
+ */
+public final class WeakCache<K, V> {
+ private final Map<K, Reference<V>> map = new WeakHashMap<K, Reference<V>>();
+
+ /**
+ * Returns a value to which the specified {@code key} is mapped,
+ * or {@code null} if this map contains no mapping for the {@code key}.
+ *
+ * @param key the key whose associated value is returned
+ * @return a value to which the specified {@code key} is mapped
+ */
+ public V get(K key) {
+ Reference<V> reference = this.map.get(key);
+ if (reference == null) {
+ return null;
+ }
+ V value = reference.get();
+ if (value == null) {
+ this.map.remove(key);
+ }
+ return value;
+ }
+
+ /**
+ * Associates the specified {@code value} with the specified {@code key}.
+ * Removes the mapping for the specified {@code key} from this cache
+ * if it is present and the specified {@code value} is {@code null}.
+ * If the cache previously contained a mapping for the {@code key},
+ * the old value is replaced by the specified {@code value}.
+ *
+ * @param key the key with which the specified value is associated
+ * @param value the value to be associated with the specified key
+ */
+ public void put(K key, V value) {
+ if (value != null) {
+ this.map.put(key, new WeakReference<V>(value));
+ }
+ else {
+ this.map.remove(key);
+ }
+ }
+}
--- a/jdk/src/share/classes/java/beans/PropertyEditorManager.java Mon Sep 01 17:36:57 2008 +0400
+++ b/jdk/src/share/classes/java/beans/PropertyEditorManager.java Wed Sep 03 21:00:04 2008 +0400
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2008 Sun Microsystems, Inc. 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
@@ -25,6 +25,7 @@
package java.beans;
+import com.sun.beans.WeakCache;
import sun.beans.editors.*;
/**
@@ -55,32 +56,30 @@
public class PropertyEditorManager {
/**
- * Register an editor class to be used to edit values of
- * a given target class.
- *
- * <p>First, if there is a security manager, its <code>checkPropertiesAccess</code>
- * method is called. This could result in a SecurityException.
+ * Registers an editor class to edit values of the given target class.
+ * If the editor class is {@code null},
+ * then any existing definition will be removed.
+ * Thus this method can be used to cancel the registration.
+ * The registration is canceled automatically
+ * if either the target or editor class is unloaded.
+ * <p>
+ * If there is a security manager, its {@code checkPropertiesAccess}
+ * method is called. This could result in a {@linkplain SecurityException}.
*
- * @param targetType the Class object of the type to be edited
- * @param editorClass the Class object of the editor class. If
- * this is null, then any existing definition will be removed.
- * @exception SecurityException if a security manager exists and its
- * <code>checkPropertiesAccess</code> method doesn't allow setting
- * of system properties.
+ * @param targetType the class object of the type to be edited
+ * @param editorClass the class object of the editor class
+ * @throws SecurityException if a security manager exists and
+ * its {@code checkPropertiesAccess} method
+ * doesn't allow setting of system properties
+ *
* @see SecurityManager#checkPropertiesAccess
*/
-
- public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
+ public static synchronized void registerEditor(Class<?> targetType, Class<?> editorClass) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
- initialize();
- if (editorClass == null) {
- registry.remove(targetType);
- } else {
- registry.put(targetType, editorClass);
- }
+ registry.put(targetType, editorClass);
}
/**
@@ -90,10 +89,8 @@
* @return An editor object for the given target class.
* The result is null if no suitable editor can be found.
*/
-
public static synchronized PropertyEditor findEditor(Class<?> targetType) {
- initialize();
- Class editorClass = (Class)registry.get(targetType);
+ Class editorClass = registry.get(targetType);
if (editorClass != null) {
try {
Object o = editorClass.newInstance();
@@ -143,10 +140,7 @@
* e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/
public static synchronized String[] getEditorSearchPath() {
- // Return a copy of the searchPath.
- String result[] = new String[searchPath.length];
- System.arraycopy(searchPath, 0, result, 0, searchPath.length);
- return result;
+ return searchPath.clone();
}
/**
@@ -162,23 +156,22 @@
* of system properties.
* @see SecurityManager#checkPropertiesAccess
*/
-
- public static synchronized void setEditorSearchPath(String path[]) {
+ public static synchronized void setEditorSearchPath(String[] path) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
- if (path == null) {
- path = new String[0];
- }
- searchPath = path;
+ searchPath = (path != null)
+ ? path.clone()
+ : EMPTY;
}
- private static synchronized void initialize() {
- if (registry != null) {
- return;
- }
- registry = new java.util.Hashtable();
+ private static String[] searchPath = { "sun.beans.editors" };
+ private static final String[] EMPTY = {};
+ private static final WeakCache<Class<?>, Class<?>> registry;
+
+ static {
+ registry = new WeakCache<Class<?>, Class<?>>();
registry.put(Byte.TYPE, ByteEditor.class);
registry.put(Short.TYPE, ShortEditor.class);
registry.put(Integer.TYPE, IntegerEditor.class);
@@ -187,7 +180,4 @@
registry.put(Float.TYPE, FloatEditor.class);
registry.put(Double.TYPE, DoubleEditor.class);
}
-
- private static String[] searchPath = { "sun.beans.editors" };
- private static java.util.Hashtable registry;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/PropertyEditor/MemoryClassLoader.java Wed Sep 03 21:00:04 2008 +0400
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public final class MemoryClassLoader extends ClassLoader {
+ private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ private final MemoryFileManager manager = new MemoryFileManager(this.compiler);
+
+ public Class<?> compile(String name, String content) {
+ compile(new Source(name, content));
+ try {
+ return findClass(name);
+ }
+ catch (ClassNotFoundException exception) {
+ throw new Error(exception);
+ }
+ }
+
+ public void compile(Source... sources) {
+ List<Source> list = new ArrayList<Source>();
+ if (sources != null) {
+ for (Source source : sources) {
+ if (source != null) {
+ list.add(source);
+ }
+ }
+ }
+ synchronized (this.manager) {
+ this.compiler.getTask(null, this.manager, null, null, null, list).call();
+ }
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ synchronized (this.manager) {
+ Output mc = this.manager.map.remove(name);
+ if (mc != null) {
+ byte[] array = mc.toByteArray();
+ return defineClass(name, array, 0, array.length);
+ }
+ }
+ return super.findClass(name);
+ }
+
+ private static final class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+ private final Map<String, Output> map = new HashMap<String, Output>();
+
+ MemoryFileManager(JavaCompiler compiler) {
+ super(compiler.getStandardFileManager(null, null, null));
+ }
+
+ @Override
+ public Output getJavaFileForOutput(Location location, String name, Kind kind, FileObject source) {
+ Output mc = this.map.get(name);
+ if (mc == null) {
+ mc = new Output(name);
+ this.map.put(name, mc);
+ }
+ return mc;
+ }
+ }
+
+ private static class MemoryFileObject extends SimpleJavaFileObject {
+ MemoryFileObject(String name, Kind kind) {
+ super(toURI(name, kind.extension), kind);
+ }
+
+ private static URI toURI(String name, String extension) {
+ try {
+ return new URI("mfm:///" + name.replace('.', '/') + extension);
+ }
+ catch (URISyntaxException exception) {
+ throw new Error(exception);
+ }
+ }
+ }
+
+ private static final class Output extends MemoryFileObject {
+ private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ Output(String name) {
+ super(name, Kind.CLASS);
+ }
+
+ byte[] toByteArray() {
+ return this.baos.toByteArray();
+ }
+
+ @Override
+ public ByteArrayOutputStream openOutputStream() {
+ this.baos.reset();
+ return this.baos;
+ }
+ }
+
+ public static final class Source extends MemoryFileObject {
+ private final String content;
+
+ Source(String name, String content) {
+ super(name, Kind.SOURCE);
+ this.content = content;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignore) {
+ return this.content;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/PropertyEditor/Test6397609.java Wed Sep 03 21:00:04 2008 +0400
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6397609
+ * @summary Tests autocleaning
+ * @author Sergey Malenkov
+ */
+
+import java.beans.PropertyEditorManager;
+
+public class Test6397609 {
+ public static void main(String[] args) throws Exception {
+ MemoryClassLoader loader = new MemoryClassLoader();
+ PropertyEditorManager.registerEditor(
+ Object.class,
+ loader.compile("Editor",
+ "public class Editor extends java.beans.PropertyEditorSupport {}"));
+
+ if (!isEditorExist(Object.class)) {
+ throw new Error("the editor is lost");
+ }
+ loader = null; // clean the reference
+ if (isEditorExist(Object.class)) {
+ throw new Error("unexpected editor is found");
+ }
+ }
+
+ private static boolean isEditorExist(Class type) {
+ for (int i = 0; i < 10; i++) {
+ System.gc(); // clean all weak references
+ if (null == PropertyEditorManager.findEditor(type)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
--- a/jdk/test/java/beans/PropertyEditor/TestEditor.java Mon Sep 01 17:36:57 2008 +0400
+++ b/jdk/test/java/beans/PropertyEditor/TestEditor.java Wed Sep 03 21:00:04 2008 +0400
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2006-2008 Sun Microsystems, Inc. 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
@@ -23,18 +23,6 @@
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
-import java.io.ByteArrayOutputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import javax.tools.FileObject;
-import javax.tools.ForwardingJavaFileManager;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileObject.Kind;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.ToolProvider;
final class TestEditor {
private final PropertyEditor editor;
@@ -53,8 +41,7 @@
void testJava(Object value) {
this.editor.setValue(value);
- MemoryFileManager manager = new MemoryFileManager();
- Object object = manager.invoke(this.editor.getJavaInitializationString());
+ Object object = execute("Executor", "execute", this.editor.getJavaInitializationString());
System.out.println("Property value before: " + value);
System.out.println("Property value after: " + object);
@@ -87,98 +74,21 @@
: object1.equals(object2);
}
- private static final class MemoryFileManager extends ForwardingJavaFileManager {
- private static final String CLASS = "Executor";
- private static final String METHOD = "execute";
- private static final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler();
- private final Map<String, MemoryClass> map = new HashMap<String, MemoryClass>();
- private final MemoryClassLoader loader = new MemoryClassLoader();
-
- MemoryFileManager() {
- super(COMPILER.getStandardFileManager(null, null, null));
- }
-
- public Object invoke(String expression) {
- MemorySource file = new MemorySource(CLASS, METHOD, expression);
- if (!COMPILER.getTask(null, this, null, null, null, Arrays.asList(file)).call())
- throw new Error("compilation failed");
-
- MemoryClass mc = this.map.get(CLASS);
- if (mc == null)
- throw new Error("class not found: " + CLASS);
-
- Class c = this.loader.loadClass(CLASS, mc.toByteArray());
- try {
- return c.getMethod(METHOD).invoke(null);
- }
- catch (Exception exception) {
- throw new Error(exception);
- }
- }
-
- public MemoryClass getJavaFileForOutput(Location location, String name, Kind kind, FileObject source) {
- MemoryClass type = this.map.get(name);
- if (type == null) {
- type = new MemoryClass(name);
- this.map.put(name, type);
- }
- return type;
- }
- }
-
- private static final class MemoryClassLoader extends ClassLoader {
- public Class<?> loadClass(String name, byte[] array) {
- return defineClass(name, array, 0, array.length);
- }
- }
+ private static Object execute(String classname, String methodname, String value) {
+ String content
+ = "public class " + classname + " {"
+ + " public static Object " + methodname + "() throws Exception {"
+ + " return " + value + ";"
+ + " }"
+ + "}";
- private static class MemoryObject extends SimpleJavaFileObject {
- protected MemoryObject(String name, Kind kind) {
- super(toURI(name, kind.extension), kind);
- }
-
- private static URI toURI(String name, String extension) {
- try {
- return new URI("mfm:///" + name.replace('.', '/') + extension);
- }
- catch (URISyntaxException exception) {
- throw new Error(exception);
- }
- }
- }
-
- private static final class MemoryClass extends MemoryObject {
- private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- MemoryClass(String className) {
- super(className, Kind.CLASS);
+ try {
+ MemoryClassLoader loader = new MemoryClassLoader();
+ Class type = loader.compile(classname, content);
+ return type.getMethod(methodname).invoke(null);
}
-
- public ByteArrayOutputStream openOutputStream() {
- this.baos.reset();
- return this.baos;
- }
-
- public byte[] toByteArray() {
- return this.baos.toByteArray();
- }
- }
-
- private static final class MemorySource extends MemoryObject {
- private final String value;
-
- MemorySource(String className, String methodName, String expression) {
- super(className, Kind.SOURCE);
- this.value
- = "public class " + className + " {\n"
- + " public static Object " + methodName + "() throws Exception {\n"
- + " return " + expression + ";\n"
- + " }\n"
- + "}\n";
- }
-
- public CharSequence getCharContent(boolean ignore) {
- return this.value;
+ catch (Exception exception) {
+ throw new Error(exception);
}
}
}