From aed8d054a74fc0cb05226fb98cd05a20b1693f16 Mon Sep 17 00:00:00 2001 From: malenkov Date: Thu, 2 Jul 2009 19:48:11 +0400 Subject: [PATCH] 6380849: RFE: Automatic discovery of PersistanceDelegates Reviewed-by: rupashka, alexp --- .../com/sun/beans/finder/BeanInfoFinder.java | 102 +++++++++++++ .../com/sun/beans/finder/InstanceFinder.java | 111 ++++++++++++++ .../finder/PersistenceDelegateFinder.java | 63 ++++++++ .../beans/finder/PropertyEditorFinder.java | 81 ++++++++++ jdk/src/share/classes/java/beans/Encoder.java | 23 +-- .../classes/java/beans/Introspector.java | 101 ++++--------- .../java/beans/PropertyEditorManager.java | 96 ++++-------- .../Introspector/6380849/TestBeanInfo.java | 102 +++++++++++++ .../Introspector/6380849/beans/FirstBean.java | 4 + .../6380849/beans/FirstBeanBeanInfo.java | 11 ++ .../6380849/beans/SecondBean.java | 4 + .../Introspector/6380849/beans/ThirdBean.java | 4 + .../6380849/infos/SecondBeanBeanInfo.java | 13 ++ .../6380849/infos/ThirdBeanBeanInfo.java | 11 ++ .../PropertyEditor/6380849/FirstBean.java | 2 + .../6380849/FirstBeanEditor.java | 4 + .../PropertyEditor/6380849/SecondBean.java | 2 + .../6380849/TestPropertyEditor.java | 141 ++++++++++++++++++ .../PropertyEditor/6380849/ThirdBean.java | 2 + .../6380849/editors/SecondBeanEditor.java | 6 + .../6380849/editors/ThirdBeanEditor.java | 6 + .../java/beans/XMLEncoder/6380849/Bean.java | 2 + .../6380849/BeanPersistenceDelegate.java | 5 + .../6380849/TestPersistenceDelegate.java | 60 ++++++++ 24 files changed, 811 insertions(+), 145 deletions(-) create mode 100644 jdk/src/share/classes/com/sun/beans/finder/BeanInfoFinder.java create mode 100644 jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java create mode 100644 jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java create mode 100644 jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java create mode 100644 jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java create mode 100644 jdk/test/java/beans/Introspector/6380849/beans/FirstBean.java create mode 100644 jdk/test/java/beans/Introspector/6380849/beans/FirstBeanBeanInfo.java create mode 100644 jdk/test/java/beans/Introspector/6380849/beans/SecondBean.java create mode 100644 jdk/test/java/beans/Introspector/6380849/beans/ThirdBean.java create mode 100644 jdk/test/java/beans/Introspector/6380849/infos/SecondBeanBeanInfo.java create mode 100644 jdk/test/java/beans/Introspector/6380849/infos/ThirdBeanBeanInfo.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/FirstBean.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/FirstBeanEditor.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/SecondBean.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/ThirdBean.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/editors/SecondBeanEditor.java create mode 100644 jdk/test/java/beans/PropertyEditor/6380849/editors/ThirdBeanEditor.java create mode 100644 jdk/test/java/beans/XMLEncoder/6380849/Bean.java create mode 100644 jdk/test/java/beans/XMLEncoder/6380849/BeanPersistenceDelegate.java create mode 100644 jdk/test/java/beans/XMLEncoder/6380849/TestPersistenceDelegate.java diff --git a/jdk/src/share/classes/com/sun/beans/finder/BeanInfoFinder.java b/jdk/src/share/classes/com/sun/beans/finder/BeanInfoFinder.java new file mode 100644 index 0000000000..3e1c37c2d5 --- /dev/null +++ b/jdk/src/share/classes/com/sun/beans/finder/BeanInfoFinder.java @@ -0,0 +1,102 @@ +/* + * Copyright 2009 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.finder; + +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; + +/** + * This is utility class that provides functionality + * to find a {@link BeanInfo} for a JavaBean specified by its type. + * + * @since 1.7 + * + * @author Sergey A. Malenkov + */ +public final class BeanInfoFinder + extends InstanceFinder { + + private static final String DEFAULT = "sun.beans.infos"; + + public BeanInfoFinder() { + super(BeanInfo.class, true, "BeanInfo", DEFAULT); + } + + private static boolean isValid(Class type, Method method) { + return (method != null) && type.equals(method.getDeclaringClass()); + } + + @Override + protected BeanInfo instantiate(Class type, String name) { + BeanInfo info = super.instantiate(type, name); + if (info != null) { + // make sure that the returned BeanInfo matches the class + BeanDescriptor bd = info.getBeanDescriptor(); + if (bd != null) { + if (type.equals(bd.getBeanClass())) { + return info; + } + } + else { + PropertyDescriptor[] pds = info.getPropertyDescriptors(); + if (pds != null) { + for (PropertyDescriptor pd : pds) { + Method method = pd.getReadMethod(); + if (method == null) { + method = pd.getWriteMethod(); + } + if (isValid(type, method)) { + return info; + } + } + } + else { + MethodDescriptor[] mds = info.getMethodDescriptors(); + if (mds != null) { + for (MethodDescriptor md : mds) { + if (isValid(type, md.getMethod())) { + return info; + } + } + } + } + } + } + return null; + } + + @Override + protected BeanInfo instantiate(Class type, String prefix, String name) { + // this optimization will only use the BeanInfo search path + // if is has changed from the original + // or trying to get the ComponentBeanInfo + return !DEFAULT.equals(prefix) || "ComponentBeanInfo".equals(name) + ? super.instantiate(type, prefix, name) + : null; + } +} diff --git a/jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java b/jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java new file mode 100644 index 0000000000..ddf4b80264 --- /dev/null +++ b/jdk/src/share/classes/com/sun/beans/finder/InstanceFinder.java @@ -0,0 +1,111 @@ +/* + * Copyright 2009 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.finder; + +/** + * This is utility class that provides basic functionality + * to find an auxiliary class for a JavaBean specified by its type. + * + * @since 1.7 + * + * @author Sergey A. Malenkov + */ +class InstanceFinder { + + private static final String[] EMPTY = { }; + + private final Class type; + private final boolean allow; + private final String suffix; + private String[] packages; + + InstanceFinder(Class type, boolean allow, String suffix, String... packages) { + this.type = type; + this.allow = allow; + this.suffix = suffix; + this.packages = packages.clone(); + } + + public String[] getPackages() { + return (this.packages.length > 0) + ? this.packages.clone() + : this.packages; + } + + public void setPackages(String... packages) { + this.packages = (packages != null) && (packages.length > 0) + ? packages.clone() + : EMPTY; + } + + public T find(Class type) { + if (type == null) { + return null; + } + String name = type.getName() + this.suffix; + T object = instantiate(type, name); + if (object != null) { + return object; + } + if (this.allow) { + object = instantiate(type, null); + if (object != null) { + return object; + } + } + int index = name.lastIndexOf('.') + 1; + if (index > 0) { + name = name.substring(index); + } + for (String prefix : this.packages) { + object = instantiate(type, prefix, name); + if (object != null) { + return object; + } + } + return null; + } + + protected T instantiate(Class type, String name) { + if (type != null) { + try { + if (name != null) { + type = ClassFinder.findClass(name, type.getClassLoader()); + } + if (this.type.isAssignableFrom(type)) { + return (T) type.newInstance(); + } + } + catch (Exception exception) { + // ignore any exceptions + } + } + return null; + } + + protected T instantiate(Class type, String prefix, String name) { + return instantiate(type, prefix + '.' + name); + } +} diff --git a/jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java b/jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java new file mode 100644 index 0000000000..f7638b65ca --- /dev/null +++ b/jdk/src/share/classes/com/sun/beans/finder/PersistenceDelegateFinder.java @@ -0,0 +1,63 @@ +/* + * Copyright 2009 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.finder; + +import java.beans.PersistenceDelegate; +import java.util.HashMap; +import java.util.Map; + +/** + * This is utility class that provides functionality + * to find a {@link PersistenceDelegate} for a JavaBean specified by its type. + * + * @since 1.7 + * + * @author Sergey A. Malenkov + */ +public final class PersistenceDelegateFinder + extends InstanceFinder { + + private final Map, PersistenceDelegate> registry; + + public PersistenceDelegateFinder() { + super(PersistenceDelegate.class, true, "PersistenceDelegate"); + this.registry = new HashMap, PersistenceDelegate>(); + } + + public void register(Class type, PersistenceDelegate delegate) { + if (delegate != null) { + this.registry.put(type, delegate); + } + else { + this.registry.remove(type); + } + } + + @Override + public PersistenceDelegate find(Class type) { + PersistenceDelegate delegate = this.registry.get(type); + return (delegate != null) ? delegate : super.find(type); + } +} diff --git a/jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java b/jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java new file mode 100644 index 0000000000..604952a1a2 --- /dev/null +++ b/jdk/src/share/classes/com/sun/beans/finder/PropertyEditorFinder.java @@ -0,0 +1,81 @@ +/* + * Copyright 2009 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.finder; + +import com.sun.beans.WeakCache; + +import java.beans.PropertyEditor; + +import sun.beans.editors.BooleanEditor; +import sun.beans.editors.ByteEditor; +import sun.beans.editors.DoubleEditor; +import sun.beans.editors.EnumEditor; +import sun.beans.editors.FloatEditor; +import sun.beans.editors.IntegerEditor; +import sun.beans.editors.LongEditor; +import sun.beans.editors.ShortEditor; + +/** + * This is utility class that provides functionality + * to find a {@link PropertyEditor} for a JavaBean specified by its type. + * + * @since 1.7 + * + * @author Sergey A. Malenkov + */ +public final class PropertyEditorFinder + extends InstanceFinder { + + private final WeakCache, Class> registry; + + public PropertyEditorFinder() { + super(PropertyEditor.class, false, "Editor", "sun.beans.editors"); + + this.registry = new WeakCache, Class>(); + this.registry.put(Byte.TYPE, ByteEditor.class); + this.registry.put(Short.TYPE, ShortEditor.class); + this.registry.put(Integer.TYPE, IntegerEditor.class); + this.registry.put(Long.TYPE, LongEditor.class); + this.registry.put(Boolean.TYPE, BooleanEditor.class); + this.registry.put(Float.TYPE, FloatEditor.class); + this.registry.put(Double.TYPE, DoubleEditor.class); + } + + public void register(Class type, Class editor) { + this.registry.put(type, editor); + } + + @Override + public PropertyEditor find(Class type) { + PropertyEditor editor = instantiate(this.registry.get(type), null); + if (editor == null) { + editor = super.find(type); + if ((editor == null) && (null != type.getEnumConstants())) { + editor = new EnumEditor(type); + } + } + return editor; + } +} diff --git a/jdk/src/share/classes/java/beans/Encoder.java b/jdk/src/share/classes/java/beans/Encoder.java index 2fcd5b5c72..92e3d695bc 100644 --- a/jdk/src/share/classes/java/beans/Encoder.java +++ b/jdk/src/share/classes/java/beans/Encoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 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 @@ -24,7 +24,8 @@ */ package java.beans; -import java.util.Collections; +import com.sun.beans.finder.PersistenceDelegateFinder; + import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; @@ -45,8 +46,7 @@ import java.util.Map; */ public class Encoder { - private final Map, PersistenceDelegate> delegates - = Collections.synchronizedMap(new HashMap, PersistenceDelegate>()); + private final PersistenceDelegateFinder finder = new PersistenceDelegateFinder(); private Map bindings = new IdentityHashMap(); private ExceptionListener exceptionListener; boolean executeStatements = true; @@ -166,8 +166,13 @@ public class Encoder { * @see java.beans.BeanInfo#getBeanDescriptor */ public PersistenceDelegate getPersistenceDelegate(Class type) { - PersistenceDelegate pd = this.delegates.get(type); - return (pd != null) ? pd : MetaData.getPersistenceDelegate(type); + synchronized (this.finder) { + PersistenceDelegate pd = this.finder.find(type); + if (pd != null) { + return pd; + } + } + return MetaData.getPersistenceDelegate(type); } /** @@ -184,10 +189,8 @@ public class Encoder { public void setPersistenceDelegate(Class type, PersistenceDelegate persistenceDelegate) { - if (persistenceDelegate != null) { - this.delegates.put(type, persistenceDelegate); - } else { - this.delegates.remove(type); + synchronized (this.finder) { + this.finder.register(type, persistenceDelegate); } } diff --git a/jdk/src/share/classes/java/beans/Introspector.java b/jdk/src/share/classes/java/beans/Introspector.java index 6a50cbe7f7..b43911cf12 100644 --- a/jdk/src/share/classes/java/beans/Introspector.java +++ b/jdk/src/share/classes/java/beans/Introspector.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 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.finder.BeanInfoFinder; import com.sun.beans.finder.ClassFinder; import java.lang.ref.Reference; @@ -45,6 +46,8 @@ import java.util.EventListener; import java.util.List; import java.util.WeakHashMap; import java.util.TreeMap; + +import sun.awt.AppContext; import sun.reflect.misc.ReflectUtil; /** @@ -137,10 +140,6 @@ public class Introspector { // events maps from String names to EventSetDescriptors private Map events; - private final static String DEFAULT_INFO_PATH = "sun.beans.infos"; - - private static String[] searchPath = { DEFAULT_INFO_PATH }; - private final static EventSetDescriptor[] EMPTY_EVENTSETDESCRIPTORS = new EventSetDescriptor[0]; static final String ADD_PREFIX = "add"; @@ -149,7 +148,7 @@ public class Introspector { static final String SET_PREFIX = "set"; static final String IS_PREFIX = "is"; - private static final String BEANINFO_SUFFIX = "BeanInfo"; + private static final Object FINDER_KEY = new Object(); //====================================================================== // Public methods @@ -309,13 +308,11 @@ public class Introspector { * Sun implementation initially sets to {"sun.beans.infos"}. */ - public static synchronized String[] getBeanInfoSearchPath() { - // Return a copy of the searchPath. - String result[] = new String[searchPath.length]; - for (int i = 0; i < searchPath.length; i++) { - result[i] = searchPath[i]; + public static String[] getBeanInfoSearchPath() { + BeanInfoFinder finder = getFinder(); + synchronized (finder) { + return finder.getPackages(); } - return result; } /** @@ -334,12 +331,15 @@ public class Introspector { * @see SecurityManager#checkPropertiesAccess */ - public static synchronized void setBeanInfoSearchPath(String path[]) { + public static void setBeanInfoSearchPath(String[] path) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } - searchPath = path; + BeanInfoFinder finder = getFinder(); + synchronized (finder) { + finder.setPackages(path); + } } @@ -447,67 +447,14 @@ public class Introspector { * then it checks to see if the class is its own BeanInfo. Finally, * the BeanInfo search path is prepended to the class and searched. * + * @param beanClass the class type of the bean * @return Instance of an explicit BeanInfo class or null if one isn't found. */ - private static synchronized BeanInfo findExplicitBeanInfo(Class beanClass) { - String name = beanClass.getName() + BEANINFO_SUFFIX; - try { - return (java.beans.BeanInfo)instantiate(beanClass, name); - } catch (Exception ex) { - // Just drop through - - } - // Now try checking if the bean is its own BeanInfo. - try { - if (isSubclass(beanClass, java.beans.BeanInfo.class)) { - return (java.beans.BeanInfo)beanClass.newInstance(); - } - } catch (Exception ex) { - // Just drop through + private static BeanInfo findExplicitBeanInfo(Class beanClass) { + BeanInfoFinder finder = getFinder(); + synchronized (finder) { + return finder.find(beanClass); } - // Now try looking for .fooBeanInfo - name = name.substring(name.lastIndexOf('.')+1); - - for (int i = 0; i < searchPath.length; i++) { - // This optimization will only use the BeanInfo search path if is has changed - // from the original or trying to get the ComponentBeanInfo. - if (!DEFAULT_INFO_PATH.equals(searchPath[i]) || - DEFAULT_INFO_PATH.equals(searchPath[i]) && "ComponentBeanInfo".equals(name)) { - try { - String fullName = searchPath[i] + "." + name; - java.beans.BeanInfo bi = (java.beans.BeanInfo)instantiate(beanClass, fullName); - - // Make sure that the returned BeanInfo matches the class. - if (bi.getBeanDescriptor() != null) { - if (bi.getBeanDescriptor().getBeanClass() == beanClass) { - return bi; - } - } else if (bi.getPropertyDescriptors() != null) { - PropertyDescriptor[] pds = bi.getPropertyDescriptors(); - for (int j = 0; j < pds.length; j++) { - Method method = pds[j].getReadMethod(); - if (method == null) { - method = pds[j].getWriteMethod(); - } - if (method != null && method.getDeclaringClass() == beanClass) { - return bi; - } - } - } else if (bi.getMethodDescriptors() != null) { - MethodDescriptor[] mds = bi.getMethodDescriptors(); - for (int j = 0; j < mds.length; j++) { - Method method = mds[j].getMethod(); - if (method != null && method.getDeclaringClass() == beanClass) { - return bi; - } - } - } - } catch (Exception ex) { - // Silently ignore any errors. - } - } - } - return null; } /** @@ -1483,6 +1430,16 @@ 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. diff --git a/jdk/src/share/classes/java/beans/PropertyEditorManager.java b/jdk/src/share/classes/java/beans/PropertyEditorManager.java index a456c2bff5..d884e9f0c0 100644 --- a/jdk/src/share/classes/java/beans/PropertyEditorManager.java +++ b/jdk/src/share/classes/java/beans/PropertyEditorManager.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 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,8 +25,8 @@ package java.beans; -import com.sun.beans.WeakCache; -import sun.beans.editors.*; +import com.sun.beans.finder.PropertyEditorFinder; +import sun.awt.AppContext; /** * The PropertyEditorManager can be used to locate a property editor for @@ -55,6 +55,8 @@ import sun.beans.editors.*; 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}, @@ -74,12 +76,15 @@ public class PropertyEditorManager { * * @see SecurityManager#checkPropertiesAccess */ - public static synchronized void registerEditor(Class targetType, Class editorClass) { + public static void registerEditor(Class targetType, Class editorClass) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } - registry.put(targetType, editorClass); + PropertyEditorFinder finder = getFinder(); + synchronized (finder) { + finder.register(targetType, editorClass); + } } /** @@ -89,46 +94,11 @@ public class PropertyEditorManager { * @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) { - Class editorClass = registry.get(targetType); - if (editorClass != null) { - try { - Object o = editorClass.newInstance(); - return (PropertyEditor)o; - } catch (Exception ex) { - System.err.println("Couldn't instantiate type editor \"" + - editorClass.getName() + "\" : " + ex); - } - } - - // Now try adding "Editor" to the class name. - - String editorName = targetType.getName() + "Editor"; - try { - return (PropertyEditor) Introspector.instantiate(targetType, editorName); - } catch (Exception ex) { - // Silently ignore any errors. - } - - // Now try looking for .fooEditor - int index = editorName.lastIndexOf('.') + 1; - if (index > 0) { - editorName = editorName.substring(index); + public static PropertyEditor findEditor(Class targetType) { + PropertyEditorFinder finder = getFinder(); + synchronized (finder) { + return finder.find(targetType); } - for (String path : searchPath) { - String name = path + '.' + editorName; - try { - return (PropertyEditor) Introspector.instantiate(targetType, name); - } catch (Exception ex) { - // Silently ignore any errors. - } - } - - if (null != targetType.getEnumConstants()) { - return new EnumEditor(targetType); - } - // We couldn't find a suitable Editor. - return null; } /** @@ -139,8 +109,11 @@ public class PropertyEditorManager { *

The default value for this array is implementation-dependent, * e.g. Sun implementation initially sets to {"sun.beans.editors"}. */ - public static synchronized String[] getEditorSearchPath() { - return searchPath.clone(); + public static String[] getEditorSearchPath() { + PropertyEditorFinder finder = getFinder(); + synchronized (finder) { + return finder.getPackages(); + } } /** @@ -156,28 +129,25 @@ public class PropertyEditorManager { * of system properties. * @see SecurityManager#checkPropertiesAccess */ - public static synchronized void setEditorSearchPath(String[] path) { + public static void setEditorSearchPath(String[] path) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPropertiesAccess(); } - searchPath = (path != null) - ? path.clone() - : EMPTY; + PropertyEditorFinder finder = getFinder(); + synchronized (finder) { + finder.setPackages(path); + } } - private static String[] searchPath = { "sun.beans.editors" }; - private static final String[] EMPTY = {}; - private static final WeakCache, Class> registry; - - static { - registry = new WeakCache, Class>(); - registry.put(Byte.TYPE, ByteEditor.class); - registry.put(Short.TYPE, ShortEditor.class); - registry.put(Integer.TYPE, IntegerEditor.class); - registry.put(Long.TYPE, LongEditor.class); - registry.put(Boolean.TYPE, BooleanEditor.class); - registry.put(Float.TYPE, FloatEditor.class); - registry.put(Double.TYPE, DoubleEditor.class); + 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; } } diff --git a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java new file mode 100644 index 0000000000..b149bffb82 --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java @@ -0,0 +1,102 @@ +/** + * Copyright 2009 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 6380849 + * @summary Tests BeanInfo finder + * @author Sergey Malenkov + */ + +import beans.FirstBean; +import beans.FirstBeanBeanInfo; +import beans.SecondBean; +import beans.ThirdBean; + +import infos.SecondBeanBeanInfo; +import infos.ThirdBeanBeanInfo; + +import java.beans.BeanInfo; +import java.beans.Introspector; +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 + + public static void main(String[] args) throws InterruptedException { + TestBeanInfo test = new TestBeanInfo(); + test.run(); + // the following tests fails on previous build + ThreadGroup group = new ThreadGroup("$$$"); // NON-NLS: unique thread name + Thread thread = new Thread(group, test); + thread.start(); + thread.join(); + } + + private static void test(Class type, Class expected) { + BeanInfo actual; + try { + actual = Introspector.getBeanInfo(type); + type = actual.getClass(); + Field field = type.getDeclaredField("targetBeanInfo"); // NON-NLS: field name + field.setAccessible(true); + actual = (BeanInfo) field.get(actual); + } + catch (Exception exception) { + throw new Error("unexpected error", exception); + } + if ((actual == null) && (expected != null)) { + throw new Error("expected info is not found"); + } + if ((actual != null) && !actual.getClass().equals(expected)) { + throw new Error("found unexpected info"); + } + } + + private boolean passed; + + public void run() { + if (this.passed) { + SunToolkit.createNewAppContext(); + } + Introspector.flushCaches(); + + test(FirstBean.class, FirstBeanBeanInfo.class); + test(SecondBean.class, null); + test(ThirdBean.class, null); + test(ThirdBeanBeanInfo.class, ThirdBeanBeanInfo.class); + + Introspector.setBeanInfoSearchPath(SEARCH_PATH); + Introspector.flushCaches(); + + test(FirstBean.class, FirstBeanBeanInfo.class); + test(SecondBean.class, SecondBeanBeanInfo.class); + test(ThirdBean.class, null); + test(ThirdBeanBeanInfo.class, ThirdBeanBeanInfo.class); + + this.passed = true; + } +} diff --git a/jdk/test/java/beans/Introspector/6380849/beans/FirstBean.java b/jdk/test/java/beans/Introspector/6380849/beans/FirstBean.java new file mode 100644 index 0000000000..cafb44e0ba --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/beans/FirstBean.java @@ -0,0 +1,4 @@ +package beans; + +public class FirstBean { +} diff --git a/jdk/test/java/beans/Introspector/6380849/beans/FirstBeanBeanInfo.java b/jdk/test/java/beans/Introspector/6380849/beans/FirstBeanBeanInfo.java new file mode 100644 index 0000000000..f4d1355703 --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/beans/FirstBeanBeanInfo.java @@ -0,0 +1,11 @@ +package beans; + +import java.beans.BeanDescriptor; +import java.beans.SimpleBeanInfo; + +public class FirstBeanBeanInfo extends SimpleBeanInfo { + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(FirstBean.class); + } +} diff --git a/jdk/test/java/beans/Introspector/6380849/beans/SecondBean.java b/jdk/test/java/beans/Introspector/6380849/beans/SecondBean.java new file mode 100644 index 0000000000..fbde390272 --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/beans/SecondBean.java @@ -0,0 +1,4 @@ +package beans; + +public class SecondBean { +} diff --git a/jdk/test/java/beans/Introspector/6380849/beans/ThirdBean.java b/jdk/test/java/beans/Introspector/6380849/beans/ThirdBean.java new file mode 100644 index 0000000000..8fb8b9a92b --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/beans/ThirdBean.java @@ -0,0 +1,4 @@ +package beans; + +public class ThirdBean { +} diff --git a/jdk/test/java/beans/Introspector/6380849/infos/SecondBeanBeanInfo.java b/jdk/test/java/beans/Introspector/6380849/infos/SecondBeanBeanInfo.java new file mode 100644 index 0000000000..999a6df904 --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/infos/SecondBeanBeanInfo.java @@ -0,0 +1,13 @@ +package infos; + +import beans.SecondBean; + +import java.beans.BeanDescriptor; +import java.beans.SimpleBeanInfo; + +public class SecondBeanBeanInfo extends SimpleBeanInfo { + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(SecondBean.class); + } +} diff --git a/jdk/test/java/beans/Introspector/6380849/infos/ThirdBeanBeanInfo.java b/jdk/test/java/beans/Introspector/6380849/infos/ThirdBeanBeanInfo.java new file mode 100644 index 0000000000..7d295bd07b --- /dev/null +++ b/jdk/test/java/beans/Introspector/6380849/infos/ThirdBeanBeanInfo.java @@ -0,0 +1,11 @@ +package infos; + +import java.beans.BeanDescriptor; +import java.beans.SimpleBeanInfo; + +public class ThirdBeanBeanInfo extends SimpleBeanInfo { + @Override + public BeanDescriptor getBeanDescriptor() { + return new BeanDescriptor(ThirdBeanBeanInfo.class); + } +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/FirstBean.java b/jdk/test/java/beans/PropertyEditor/6380849/FirstBean.java new file mode 100644 index 0000000000..e112dbfaa7 --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/FirstBean.java @@ -0,0 +1,2 @@ +public class FirstBean { +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/FirstBeanEditor.java b/jdk/test/java/beans/PropertyEditor/6380849/FirstBeanEditor.java new file mode 100644 index 0000000000..8a227be21f --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/FirstBeanEditor.java @@ -0,0 +1,4 @@ +import java.beans.PropertyEditorSupport; + +public class FirstBeanEditor extends PropertyEditorSupport { +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/SecondBean.java b/jdk/test/java/beans/PropertyEditor/6380849/SecondBean.java new file mode 100644 index 0000000000..51eea29580 --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/SecondBean.java @@ -0,0 +1,2 @@ +public class SecondBean { +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java b/jdk/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java new file mode 100644 index 0000000000..f7f4d1b1ad --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/TestPropertyEditor.java @@ -0,0 +1,141 @@ +/** + * Copyright 2009 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 6380849 + * @summary Tests PropertyEditor finder + * @author Sergey Malenkov + */ + +import editors.SecondBeanEditor; +import editors.ThirdBeanEditor; + +import java.awt.Color; +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; +import sun.beans.editors.DoubleEditor; +import sun.beans.editors.EnumEditor; +import sun.beans.editors.FloatEditor; +import sun.beans.editors.FontEditor; +import sun.beans.editors.IntegerEditor; +import sun.beans.editors.LongEditor; +import sun.beans.editors.ShortEditor; +import sun.beans.editors.StringEditor; + +public class TestPropertyEditor implements Runnable { + + private enum Enumeration { + FIRST, SECOND, THIRD + } + + private static final String[] SEARCH_PATH = { "editors" }; // NON-NLS: package name + + public static void main(String[] args) throws InterruptedException { + TestPropertyEditor test = new TestPropertyEditor(); + test.run(); + // the following tests fails on previous build + ThreadGroup group = new ThreadGroup("$$$"); // NON-NLS: unique thread name + Thread thread = new Thread(group, test); + thread.start(); + thread.join(); + } + + private static void test(Class type, Class expected) { + PropertyEditor actual = PropertyEditorManager.findEditor(type); + if ((actual == null) && (expected != null)) { + throw new Error("expected editor is not found"); + } + if ((actual != null) && !actual.getClass().equals(expected)) { + throw new Error("found unexpected editor"); + } + } + + private boolean passed; + + public void run() { + if (this.passed) { + SunToolkit.createNewAppContext(); + } + PropertyEditorManager.registerEditor(ThirdBean.class, ThirdBeanEditor.class); + + test(FirstBean.class, FirstBeanEditor.class); + test(SecondBean.class, null); + test(ThirdBean.class, ThirdBeanEditor.class); + // test editors for default primitive types + test(Byte.TYPE, ByteEditor.class); + test(Short.TYPE, ShortEditor.class); + test(Integer.TYPE, IntegerEditor.class); + test(Long.TYPE, LongEditor.class); + test(Boolean.TYPE, BooleanEditor.class); + test(Float.TYPE, FloatEditor.class); + test(Double.TYPE, DoubleEditor.class); + // test editors for default object types + test(Byte.class, ByteEditor.class); + test(Short.class, ShortEditor.class); + test(Integer.class, IntegerEditor.class); + test(Long.class, LongEditor.class); + test(Boolean.class, BooleanEditor.class); + test(Float.class, FloatEditor.class); + test(Double.class, DoubleEditor.class); + test(String.class, StringEditor.class); + test(Color.class, ColorEditor.class); + test(Font.class, FontEditor.class); + test(Enumeration.class, EnumEditor.class); + + PropertyEditorManager.registerEditor(ThirdBean.class, null); + PropertyEditorManager.setEditorSearchPath(SEARCH_PATH); + + test(FirstBean.class, FirstBeanEditor.class); + test(SecondBean.class, SecondBeanEditor.class); + test(ThirdBean.class, ThirdBeanEditor.class); + // test editors for default primitive types + test(Byte.TYPE, ByteEditor.class); + test(Short.TYPE, ShortEditor.class); + test(Integer.TYPE, IntegerEditor.class); + test(Long.TYPE, LongEditor.class); + test(Boolean.TYPE, BooleanEditor.class); + test(Float.TYPE, FloatEditor.class); + test(Double.TYPE, DoubleEditor.class); + // test editors for default object types + test(Byte.class, null); + test(Short.class, null); + test(Integer.class, null); + test(Long.class, null); + test(Boolean.class, null); + test(Float.class, null); + test(Double.class, null); + test(String.class, null); + test(Color.class, null); + test(Font.class, null); + test(Enumeration.class, EnumEditor.class); + + this.passed = true; + } +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/ThirdBean.java b/jdk/test/java/beans/PropertyEditor/6380849/ThirdBean.java new file mode 100644 index 0000000000..094ab830ef --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/ThirdBean.java @@ -0,0 +1,2 @@ +public class ThirdBean { +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/editors/SecondBeanEditor.java b/jdk/test/java/beans/PropertyEditor/6380849/editors/SecondBeanEditor.java new file mode 100644 index 0000000000..e8b48e0f2e --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/editors/SecondBeanEditor.java @@ -0,0 +1,6 @@ +package editors; + +import java.beans.PropertyEditorSupport; + +public class SecondBeanEditor extends PropertyEditorSupport { +} diff --git a/jdk/test/java/beans/PropertyEditor/6380849/editors/ThirdBeanEditor.java b/jdk/test/java/beans/PropertyEditor/6380849/editors/ThirdBeanEditor.java new file mode 100644 index 0000000000..14bf7b8d16 --- /dev/null +++ b/jdk/test/java/beans/PropertyEditor/6380849/editors/ThirdBeanEditor.java @@ -0,0 +1,6 @@ +package editors; + +import java.beans.PropertyEditorSupport; + +public class ThirdBeanEditor extends PropertyEditorSupport { +} diff --git a/jdk/test/java/beans/XMLEncoder/6380849/Bean.java b/jdk/test/java/beans/XMLEncoder/6380849/Bean.java new file mode 100644 index 0000000000..5414597919 --- /dev/null +++ b/jdk/test/java/beans/XMLEncoder/6380849/Bean.java @@ -0,0 +1,2 @@ +public class Bean { +} diff --git a/jdk/test/java/beans/XMLEncoder/6380849/BeanPersistenceDelegate.java b/jdk/test/java/beans/XMLEncoder/6380849/BeanPersistenceDelegate.java new file mode 100644 index 0000000000..34278b419e --- /dev/null +++ b/jdk/test/java/beans/XMLEncoder/6380849/BeanPersistenceDelegate.java @@ -0,0 +1,5 @@ +import java.beans.DefaultPersistenceDelegate; + +public class BeanPersistenceDelegate + extends DefaultPersistenceDelegate { +} diff --git a/jdk/test/java/beans/XMLEncoder/6380849/TestPersistenceDelegate.java b/jdk/test/java/beans/XMLEncoder/6380849/TestPersistenceDelegate.java new file mode 100644 index 0000000000..35dde1ab79 --- /dev/null +++ b/jdk/test/java/beans/XMLEncoder/6380849/TestPersistenceDelegate.java @@ -0,0 +1,60 @@ +/** + * Copyright 2009 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 6380849 + * @summary Tests PersistenceDelegate finder + * @author Sergey Malenkov + */ + +import java.beans.PersistenceDelegate; +import java.beans.XMLEncoder; +import java.beans.DefaultPersistenceDelegate; + +public class TestPersistenceDelegate { + + private static final XMLEncoder ENCODER = new XMLEncoder(System.out); + + public static void main(String[] args) throws InterruptedException { + Class type = TestPersistenceDelegate.class; + test(type, DefaultPersistenceDelegate.class); + ENCODER.setPersistenceDelegate(type, new BeanPersistenceDelegate()); + test(type, BeanPersistenceDelegate.class); + ENCODER.setPersistenceDelegate(type, null); + test(type, DefaultPersistenceDelegate.class); + // the following tests fails on previous build + test(Bean.class, BeanPersistenceDelegate.class); + test(BeanPersistenceDelegate.class, BeanPersistenceDelegate.class); + } + + private static void test(Class type, Class expected) { + PersistenceDelegate actual = ENCODER.getPersistenceDelegate(type); + if ((actual == null) && (expected != null)) { + throw new Error("expected delegate is not found"); + } + if ((actual != null) && !actual.getClass().equals(expected)) { + throw new Error("found unexpected delegate"); + } + } +} -- GitLab