提交 03d6b6f9 编写于 作者: M malenkov

6397609: DOC: De-register API required for PropertyEditorManager and/or doc change

Reviewed-by: peterz, rupashka
上级 7f86cd1d
/*
* 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);
}
}
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package java.beans; package java.beans;
import com.sun.beans.WeakCache;
import sun.beans.editors.*; import sun.beans.editors.*;
/** /**
...@@ -55,33 +56,31 @@ import sun.beans.editors.*; ...@@ -55,33 +56,31 @@ import sun.beans.editors.*;
public class PropertyEditorManager { public class PropertyEditorManager {
/** /**
* Register an editor class to be used to edit values of * Registers an editor class to edit values of the given target class.
* a 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}.
* *
* <p>First, if there is a security manager, its <code>checkPropertiesAccess</code> * @param targetType the class object of the type to be edited
* method is called. This could result in a SecurityException. * @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
* *
* @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.
* @see SecurityManager#checkPropertiesAccess * @see SecurityManager#checkPropertiesAccess
*/ */
public static synchronized void registerEditor(Class<?> targetType, Class<?> editorClass) {
public static void registerEditor(Class<?> targetType, Class<?> editorClass) {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
sm.checkPropertiesAccess(); sm.checkPropertiesAccess();
} }
initialize();
if (editorClass == null) {
registry.remove(targetType);
} else {
registry.put(targetType, editorClass); registry.put(targetType, editorClass);
} }
}
/** /**
* Locate a value editor for a given target type. * Locate a value editor for a given target type.
...@@ -90,10 +89,8 @@ public class PropertyEditorManager { ...@@ -90,10 +89,8 @@ public class PropertyEditorManager {
* @return An editor object for the given target class. * @return An editor object for the given target class.
* The result is null if no suitable editor can be found. * The result is null if no suitable editor can be found.
*/ */
public static synchronized PropertyEditor findEditor(Class<?> targetType) { public static synchronized PropertyEditor findEditor(Class<?> targetType) {
initialize(); Class editorClass = registry.get(targetType);
Class editorClass = (Class)registry.get(targetType);
if (editorClass != null) { if (editorClass != null) {
try { try {
Object o = editorClass.newInstance(); Object o = editorClass.newInstance();
...@@ -143,10 +140,7 @@ public class PropertyEditorManager { ...@@ -143,10 +140,7 @@ public class PropertyEditorManager {
* e.g. Sun implementation initially sets to {"sun.beans.editors"}. * e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/ */
public static synchronized String[] getEditorSearchPath() { public static synchronized String[] getEditorSearchPath() {
// Return a copy of the searchPath. return searchPath.clone();
String result[] = new String[searchPath.length];
System.arraycopy(searchPath, 0, result, 0, searchPath.length);
return result;
} }
/** /**
...@@ -162,23 +156,22 @@ public class PropertyEditorManager { ...@@ -162,23 +156,22 @@ public class PropertyEditorManager {
* of system properties. * of system properties.
* @see SecurityManager#checkPropertiesAccess * @see SecurityManager#checkPropertiesAccess
*/ */
public static synchronized void setEditorSearchPath(String[] path) {
public static synchronized void setEditorSearchPath(String path[]) {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
sm.checkPropertiesAccess(); sm.checkPropertiesAccess();
} }
if (path == null) { searchPath = (path != null)
path = new String[0]; ? path.clone()
} : EMPTY;
searchPath = path;
} }
private static synchronized void initialize() { private static String[] searchPath = { "sun.beans.editors" };
if (registry != null) { private static final String[] EMPTY = {};
return; private static final WeakCache<Class<?>, Class<?>> registry;
}
registry = new java.util.Hashtable(); static {
registry = new WeakCache<Class<?>, Class<?>>();
registry.put(Byte.TYPE, ByteEditor.class); registry.put(Byte.TYPE, ByteEditor.class);
registry.put(Short.TYPE, ShortEditor.class); registry.put(Short.TYPE, ShortEditor.class);
registry.put(Integer.TYPE, IntegerEditor.class); registry.put(Integer.TYPE, IntegerEditor.class);
...@@ -187,7 +180,4 @@ public class PropertyEditorManager { ...@@ -187,7 +180,4 @@ public class PropertyEditorManager {
registry.put(Float.TYPE, FloatEditor.class); registry.put(Float.TYPE, FloatEditor.class);
registry.put(Double.TYPE, DoubleEditor.class); registry.put(Double.TYPE, DoubleEditor.class);
} }
private static String[] searchPath = { "sun.beans.editors" };
private static java.util.Hashtable registry;
} }
/*
* 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;
}
}
}
/*
* 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;
}
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,18 +23,6 @@ ...@@ -23,18 +23,6 @@
import java.beans.PropertyEditor; import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager; 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 { final class TestEditor {
private final PropertyEditor editor; private final PropertyEditor editor;
...@@ -53,8 +41,7 @@ final class TestEditor { ...@@ -53,8 +41,7 @@ final class TestEditor {
void testJava(Object value) { void testJava(Object value) {
this.editor.setValue(value); this.editor.setValue(value);
MemoryFileManager manager = new MemoryFileManager(); Object object = execute("Executor", "execute", this.editor.getJavaInitializationString());
Object object = manager.invoke(this.editor.getJavaInitializationString());
System.out.println("Property value before: " + value); System.out.println("Property value before: " + value);
System.out.println("Property value after: " + object); System.out.println("Property value after: " + object);
...@@ -87,98 +74,21 @@ final class TestEditor { ...@@ -87,98 +74,21 @@ final class TestEditor {
: object1.equals(object2); : object1.equals(object2);
} }
private static final class MemoryFileManager extends ForwardingJavaFileManager { private static Object execute(String classname, String methodname, String value) {
private static final String CLASS = "Executor"; String content
private static final String METHOD = "execute"; = "public class " + classname + " {"
private static final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler(); + " public static Object " + methodname + "() throws Exception {"
private final Map<String, MemoryClass> map = new HashMap<String, MemoryClass>(); + " return " + value + ";"
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 { try {
return c.getMethod(METHOD).invoke(null); MemoryClassLoader loader = new MemoryClassLoader();
Class type = loader.compile(classname, content);
return type.getMethod(methodname).invoke(null);
} }
catch (Exception exception) { catch (Exception exception) {
throw new Error(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 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);
}
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;
}
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册