/* * Copyright (c) 1998, 2004, 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 sun.swing; import java.beans.*; import java.lang.reflect.Method; public class BeanInfoUtils { /* The values of these createPropertyDescriptor() and * createBeanDescriptor() keywords are the names of the * properties they're used to set. */ public static final String BOUND = "bound"; public static final String CONSTRAINED = "constrained"; public static final String PROPERTYEDITORCLASS = "propertyEditorClass"; public static final String READMETHOD = "readMethod"; public static final String WRITEMETHOD = "writeMethod"; public static final String DISPLAYNAME = "displayName"; public static final String EXPERT = "expert"; public static final String HIDDEN = "hidden"; public static final String PREFERRED = "preferred"; public static final String SHORTDESCRIPTION = "shortDescription"; public static final String CUSTOMIZERCLASS = "customizerClass"; static private void initFeatureDescriptor(FeatureDescriptor fd, String key, Object value) { if (DISPLAYNAME.equals(key)) { fd.setDisplayName((String)value); } if (EXPERT.equals(key)) { fd.setExpert(((Boolean)value).booleanValue()); } if (HIDDEN.equals(key)) { fd.setHidden(((Boolean)value).booleanValue()); } if (PREFERRED.equals(key)) { fd.setPreferred(((Boolean)value).booleanValue()); } else if (SHORTDESCRIPTION.equals(key)) { fd.setShortDescription((String)value); } /* Otherwise assume that we have an arbitrary FeatureDescriptor * "attribute". */ else { fd.setValue(key, value); } } /** * Create a beans PropertyDescriptor given an of keyword/value * arguments. The following sample call shows all of the supported * keywords: *
* createPropertyDescriptor("contentPane", new Object[] { * BOUND, Boolean.TRUE, * CONSTRAINED, Boolean.TRUE, * PROPERTYEDITORCLASS, package.MyEditor.class, * READMETHOD, "getContentPane", * WRITEMETHOD, "setContentPane", * DISPLAYNAME, "contentPane", * EXPERT, Boolean.FALSE, * HIDDEN, Boolean.FALSE, * PREFERRED, Boolean.TRUE, * SHORTDESCRIPTION, "A top level window with a window manager border", * "random attribute","random object value" * } * ); ** The keywords correspond to
java.beans.PropertyDescriptor
and
* java.beans.FeatureDescriptor
properties, e.g. providing a value
* for displayName is comparable to FeatureDescriptor.setDisplayName()
.
* Using createPropertyDescriptor instead of the PropertyDescriptor
* constructor and set methods is preferrable in that it regularizes
* the code in a java.beans.BeanInfo.getPropertyDescriptors()
* method implementation. One can use createPropertyDescriptor
* to set FeatureDescriptor
attributes, as in "random attribute"
* "random object value".
*
* All properties should provide a reasonable value for the
* SHORTDESCRIPTION
keyword and should set BOUND
* to Boolean.TRUE
if neccessary. The remaining keywords
* are optional. There's no need to provide values for keywords like
* READMETHOD if the correct value can be computed, i.e. if the properties
* get/is method follows the standard beans pattern.
*
* The PREFERRED keyword is not supported by the JDK1.1 java.beans package. * It's still worth setting it to true for properties that are most * likely to be interested to the average developer, e.g. AbstractButton.title * is a preferred property, AbstractButton.focusPainted is not. * * @see java.beans#BeanInfo * @see java.beans#PropertyDescriptor * @see java.beans#FeatureDescriptor */ public static PropertyDescriptor createPropertyDescriptor(Class cls, String name, Object[] args) { PropertyDescriptor pd = null; try { pd = new PropertyDescriptor(name, cls); } catch (IntrospectionException e) { // Try creating a read-only property, in case setter isn't defined. try { pd = createReadOnlyPropertyDescriptor(name, cls); } catch (IntrospectionException ie) { throwError(ie, "Can't create PropertyDescriptor for " + name + " "); } } for(int i = 0; i < args.length; i += 2) { String key = (String)args[i]; Object value = args[i + 1]; if (BOUND.equals(key)) { pd.setBound(((Boolean)value).booleanValue()); } else if (CONSTRAINED.equals(key)) { pd.setConstrained(((Boolean)value).booleanValue()); } else if (PROPERTYEDITORCLASS.equals(key)) { pd.setPropertyEditorClass((Class)value); } else if (READMETHOD.equals(key)) { String methodName = (String)value; Method method; try { method = cls.getMethod(methodName, new Class[0]); pd.setReadMethod(method); } catch(Exception e) { throwError(e, cls + " no such method as \"" + methodName + "\""); } } else if (WRITEMETHOD.equals(key)) { String methodName = (String)value; Method method; try { Class type = pd.getPropertyType(); method = cls.getMethod(methodName, new Class[]{type}); pd.setWriteMethod(method); } catch(Exception e) { throwError(e, cls + " no such method as \"" + methodName + "\""); } } else { initFeatureDescriptor(pd, key, value); } } return pd; } /** * Create a BeanDescriptor object given an of keyword/value * arguments. The following sample call shows all of the supported * keywords: *
* createBeanDescriptor(JWindow..class, new Object[] { * CUSTOMIZERCLASS, package.MyCustomizer.class, * DISPLAYNAME, "JFrame", * EXPERT, Boolean.FALSE, * HIDDEN, Boolean.FALSE, * PREFERRED, Boolean.TRUE, * SHORTDESCRIPTION, "A top level window with a window manager border", * "random attribute","random object value" * } * ); ** The keywords correspond to
java.beans.BeanDescriptor
and
* java.beans.FeatureDescriptor
properties, e.g. providing a value
* for displayName is comparable to FeatureDescriptor.setDisplayName()
.
* Using createBeanDescriptor instead of the BeanDescriptor
* constructor and set methods is preferrable in that it regularizes
* the code in a java.beans.BeanInfo.getBeanDescriptor()
* method implementation. One can use createBeanDescriptor
* to set FeatureDescriptor
attributes, as in "random attribute"
* "random object value".
*
* @see java.beans#BeanInfo
* @see java.beans#PropertyDescriptor
*/
public static BeanDescriptor createBeanDescriptor(Class cls, Object[] args)
{
Class customizerClass = null;
/* For reasons I don't understand, customizerClass is a
* readOnly property. So we have to find it and pass it
* to the constructor here.
*/
for(int i = 0; i < args.length; i += 2) {
if (CUSTOMIZERCLASS.equals((String)args[i])) {
customizerClass = (Class)args[i + 1];
break;
}
}
BeanDescriptor bd = new BeanDescriptor(cls, customizerClass);
for(int i = 0; i < args.length; i += 2) {
String key = (String)args[i];
Object value = args[i + 1];
initFeatureDescriptor(bd, key, value);
}
return bd;
}
static private PropertyDescriptor createReadOnlyPropertyDescriptor(
String name, Class cls) throws IntrospectionException {
Method readMethod = null;
String base = capitalize(name);
Class[] parameters = new Class[0];
// Is it a boolean?
try {
readMethod = cls.getMethod("is" + base, parameters);
} catch (Exception ex) {}
if (readMethod == null) {
try {
// Try normal accessor pattern.
readMethod = cls.getMethod("get" + base, parameters);
} catch (Exception ex2) {}
}
if (readMethod != null) {
return new PropertyDescriptor(name, readMethod, null);
}
try {
// Try indexed accessor pattern.
parameters = new Class[1];
parameters[0] = int.class;
readMethod = cls.getMethod("get" + base, parameters);
} catch (NoSuchMethodException nsme) {
throw new IntrospectionException(
"cannot find accessor method for " + name + " property.");
}
return new IndexedPropertyDescriptor(name, null, null, readMethod, null);
}
// Modified methods from java.beans.Introspector
private static String capitalize(String s) {
if (s.length() == 0) {
return s;
}
char chars[] = s.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
/**
* Fatal errors are handled by calling this method.
*/
public static void throwError(Exception e, String s) {
throw new Error(e.toString() + " " + s);
}
}