summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorJohn Keiser <shalom@gnu.org>1998-07-31 02:12:35 +0000
committerJohn Keiser <shalom@gnu.org>1998-07-31 02:12:35 +0000
commit5f3d9badb40dab548e3704bd93ea188814d18ed3 (patch)
treecb5368dc124e473073d70995bf8056315509079d /gnu
parentc28591f25cf3c2fa7f039b95942e74e52fb0fb96 (diff)
downloadclasspath-5f3d9badb40dab548e3704bd93ea188814d18ed3.tar.gz
Helpers for java.beans.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/java/beans/BeanInfoEmbryo.java143
-rw-r--r--gnu/java/beans/EmptyBeanInfo.java52
-rw-r--r--gnu/java/beans/ExplicitBeanInfo.java126
-rw-r--r--gnu/java/beans/IntrospectionIncubator.java357
4 files changed, 678 insertions, 0 deletions
diff --git a/gnu/java/beans/BeanInfoEmbryo.java b/gnu/java/beans/BeanInfoEmbryo.java
new file mode 100644
index 000000000..b54a13d33
--- /dev/null
+++ b/gnu/java/beans/BeanInfoEmbryo.java
@@ -0,0 +1,143 @@
+/*
+ * gnu.java.beans.BeanInfoEmbryo: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.java.beans;
+
+import java.beans.*;
+import java.util.*;
+
+/**
+ ** A BeanInfoEmbryo accumulates information about a Bean
+ ** while it is in the process of being created, and then
+ ** when you are done accumulating the information, the
+ ** getBeanInfo() method may be called to create a BeanInfo
+ ** object based on the information.<P>
+ **
+ ** This class is not well-synchronized. (It can be, it
+ ** just isn't yet.)
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see java.beans.BeanInfo
+ **/
+
+public class BeanInfoEmbryo {
+ BeanDescriptor beanDescriptor;
+ Vector additionalBeanInfo = new Vector();
+ Hashtable properties = new Hashtable();
+ Hashtable events = new Hashtable();
+ Hashtable methods = new Hashtable();
+
+ BeanInfo[] AadditionalBeanInfo;
+ PropertyDescriptor[] Aproperties;
+ EventSetDescriptor[] Aevents;
+ MethodDescriptor[] Amethods;
+
+ public BeanInfoEmbryo() {
+ }
+
+ public BeanInfo getBeanInfo() {
+ if(additionalBeanInfo != null) {
+ AadditionalBeanInfo = new BeanInfo[additionalBeanInfo.size()];
+ additionalBeanInfo.copyInto(AadditionalBeanInfo);
+ }
+ if(properties != null) {
+ Aproperties = new PropertyDescriptor[properties.size()];
+ int i = 0;
+ Enumeration enum = properties.elements();
+ while(enum.hasMoreElements()) {
+ Aproperties[i] = (PropertyDescriptor)enum.nextElement();
+ i++;
+ }
+ }
+ if(events != null) {
+ Aevents = new EventSetDescriptor[events.size()];
+ int i = 0;
+ Enumeration enum = events.elements();
+ while(enum.hasMoreElements()) {
+ Aevents[i] = (EventSetDescriptor)enum.nextElement();
+ i++;
+ }
+ }
+ if(methods != null) {
+ Amethods = new MethodDescriptor[methods.size()];
+ int i = 0;
+ Enumeration enum = methods.elements();
+ while(enum.hasMoreElements()) {
+ Amethods[i] = (MethodDescriptor)enum.nextElement();
+ i++;
+ }
+ }
+ return new ExplicitBeanInfo(beanDescriptor,AadditionalBeanInfo,Aproperties,-1,Aevents,-1,Amethods,null);
+ }
+
+ public void setBeanDescriptor(BeanDescriptor b) {
+ beanDescriptor = b;
+ }
+
+ public void setAdditionalBeanInfo(BeanInfo[] b) {
+ additionalBeanInfo = null;
+ AadditionalBeanInfo = b;
+ }
+ public void addAdditionalBeanInfo(BeanInfo b) {
+ additionalBeanInfo.addElement(b);
+ }
+ public void setParentBeanInfo(BeanInfo b) {
+ BeanInfo[] ba = new BeanInfo[1];
+ ba[0] = b;
+ setAdditionalBeanInfo(ba);
+ }
+
+ public boolean hasProperty(String name) {
+ return properties.get(name) != null;
+ }
+ public void setProperties(PropertyDescriptor[] p) {
+ properties = null;
+ Aproperties = p;
+ }
+ public void addProperty(PropertyDescriptor p) {
+ properties.put(p.getName(),p);
+ }
+ public void addIndexedProperty(IndexedPropertyDescriptor p) {
+ properties.put(p.getName(),p);
+ }
+
+ public boolean hasEvent(String name) {
+ return events.get(name) != null;
+ }
+ public void addEvent(EventSetDescriptor e) {
+ events.put(e.getName(),e);
+ }
+ public void setEvents(EventSetDescriptor[] e) {
+ events = null;
+ Aevents = e;
+ }
+
+ public boolean hasMethod(String name) {
+ return methods.get(name) != null;
+ }
+ public void addMethod(MethodDescriptor m) {
+ methods.put(m.getName(),m);
+ }
+ public void setMethods(MethodDescriptor[] m) {
+ methods = null;
+ Amethods = m;
+ }
+} \ No newline at end of file
diff --git a/gnu/java/beans/EmptyBeanInfo.java b/gnu/java/beans/EmptyBeanInfo.java
new file mode 100644
index 000000000..07f938bf4
--- /dev/null
+++ b/gnu/java/beans/EmptyBeanInfo.java
@@ -0,0 +1,52 @@
+/*
+ * gnu.java.beans.EmptyBeanInfo: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.java.beans;
+
+import java.beans.*;
+
+/**
+ ** EmptyBeanInfo is a BeanInfo that discloses no
+ ** information about the Bean and does not allow
+ ** Introspection. The Introspector uses instances of this
+ ** class to create empty BeanInfos, but it could also be
+ ** used as a base class for BeanInfos that do not allow
+ ** Introspection and provide only a little bit of
+ ** information.<P>
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see gnu.java.beans.ExplicitBeanInfo
+ ** @see java.beans.BeanInfo
+ **/
+
+public class EmptyBeanInfo extends ExplicitBeanInfo {
+ /** Create a new EmptyBeanInfo. **/
+ public EmptyBeanInfo(Class beanClass) {
+ super(new BeanDescriptor(beanClass,null),
+ new BeanInfo[0],
+ new PropertyDescriptor[0],
+ -1,
+ new EventSetDescriptor[0],
+ -1,
+ new MethodDescriptor[0],
+ null);
+ }
+} \ No newline at end of file
diff --git a/gnu/java/beans/ExplicitBeanInfo.java b/gnu/java/beans/ExplicitBeanInfo.java
new file mode 100644
index 000000000..3b6c3f035
--- /dev/null
+++ b/gnu/java/beans/ExplicitBeanInfo.java
@@ -0,0 +1,126 @@
+/*
+ * gnu.java.beans.ExplicitBeanInfo: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.java.beans;
+
+import java.beans.*;
+
+/**
+ ** ExplicitBeanInfo lets you specify in the constructor
+ ** all the various parts of the BeanInfo.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see java.beans.BeanInfo
+ **/
+
+public class ExplicitBeanInfo implements BeanInfo {
+ /** The BeanDescriptor returned by getBeanDescriptor. **/
+ protected BeanDescriptor beanDescriptor;
+
+ /** The EventSetDescriptor array returned by
+ ** getEventSetDescriptors().
+ **/
+ protected EventSetDescriptor[] eventSetDescriptors = new EventSetDescriptor[0];
+
+ /** The PropertyDescriptor array returned by
+ ** getPropertyDescriptors().
+ **/
+ protected PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[0];
+
+ /** The MethodDescriptor array returned by
+ ** getMethodDescriptors().
+ **/
+ protected MethodDescriptor[] methodDescriptors;
+
+ /** The default property index. **/
+ protected int defaultPropertyIndex;
+
+ /** The default event index. **/
+ protected int defaultEventIndex;
+
+ /** The BeanInfo array returned by
+ ** getAdditionalBeanInfo().
+ **/
+ protected BeanInfo[] additionalBeanInfo;
+
+ /** The set of icons. **/
+ protected java.awt.Image[] icons;
+
+ public ExplicitBeanInfo(BeanDescriptor beanDescriptor,
+ BeanInfo[] additionalBeanInfo,
+ PropertyDescriptor[] propertyDescriptors,
+ int defaultPropertyIndex,
+ EventSetDescriptor[] eventSetDescriptors,
+ int defaultEventIndex,
+ MethodDescriptor[] methodDescriptors,
+ java.awt.Image[] icons) {
+ this.beanDescriptor = beanDescriptor;
+ this.additionalBeanInfo = additionalBeanInfo;
+ this.propertyDescriptors = propertyDescriptors;
+ this.defaultPropertyIndex = defaultPropertyIndex;
+ this.eventSetDescriptors = eventSetDescriptors;
+ this.defaultEventIndex = defaultEventIndex;
+ this.methodDescriptors = methodDescriptors;
+ this.icons = icons;
+ }
+
+ /** Get Bean descriptor. **/
+ public BeanDescriptor getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ /** Get Bean events. **/
+ public EventSetDescriptor[] getEventSetDescriptors() {
+ return eventSetDescriptors;
+ }
+
+ /** Get default event set. **/
+ public int getDefaultEventIndex() {
+ return defaultEventIndex;
+ }
+
+ /** Get Bean properties. **/
+ public PropertyDescriptor[] getPropertyDescriptors() {
+ return propertyDescriptors;
+ }
+
+ /** Get "default" property. **/
+ public int getDefaultPropertyIndex() {
+ return defaultPropertyIndex;
+ }
+
+ /** Get Bean methods. **/
+ public MethodDescriptor[] getMethodDescriptors() {
+ return methodDescriptors;
+ }
+
+ /** Get additional Bean info. **/
+ public BeanInfo[] getAdditionalBeanInfo() {
+ return additionalBeanInfo;
+ }
+
+ /** Get Bean icons.
+ ** @param iconType the type of icon
+ **/
+ public java.awt.Image getIcon(int iconType) {
+ return icons != null ? icons[iconType] : null;
+ }
+} \ No newline at end of file
diff --git a/gnu/java/beans/IntrospectionIncubator.java b/gnu/java/beans/IntrospectionIncubator.java
new file mode 100644
index 000000000..aa08f81a8
--- /dev/null
+++ b/gnu/java/beans/IntrospectionIncubator.java
@@ -0,0 +1,357 @@
+/*
+ * gnu.java.beans.IntrospectionIncubator: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.java.beans;
+
+import java.beans.*;
+import java.util.*;
+import java.lang.reflect.*;
+import gnu.java.lang.*;
+
+/**
+ ** IntrospectionIncubator takes in a bunch of Methods, and
+ ** Introspects only those Methods you give it.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see gnu.java.beans.ExplicitBeanInfo
+ ** @see java.beans.BeanInfo
+ **/
+
+public class IntrospectionIncubator {
+ Hashtable propertyMethods = new Hashtable();
+ Hashtable listenerMethods = new Hashtable();
+ Vector otherMethods = new Vector();
+
+ public IntrospectionIncubator(Class beanClass) {
+ addMethods(beanClass.getDeclaredMethods());
+ }
+
+ public IntrospectionIncubator() {
+ }
+
+ /* Paving the way for automatic Introspection */
+ public void addMethod(Method method) {
+ if(Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
+ String name = gnu.java.lang.ClassHelper.getTruncatedName(method.getName());
+ Class retType = method.getReturnType();
+ Class[] params = method.getParameterTypes();
+ boolean isVoid = retType.equals(java.lang.Void.TYPE);
+ if(name.startsWith("is")
+ && retType.equals(java.lang.Boolean.TYPE)
+ && params.length == 0) {
+ addToPropertyHash(name,method,IS);
+ } else if(name.startsWith("get") && !isVoid) {
+ if(params.length == 0) {
+ addToPropertyHash(name,method,GET);
+ } else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) {
+ addToPropertyHash(name,method,GET_I);
+ } else {
+ otherMethods.addElement(method);
+ }
+ } else if(name.startsWith("set") && isVoid) {
+ if(params.length == 1) {
+ addToPropertyHash(name,method,SET);
+ } else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) {
+ addToPropertyHash(name,method,SET_I);
+ } else {
+ otherMethods.addElement(method);
+ }
+ } else if(name.startsWith("add")
+ && isVoid
+ && params.length == 1
+ && java.util.EventListener.class.isAssignableFrom(params[0])
+ && name.substring(3).equals(ClassHelper.getTruncatedClassName(params[0]))) {
+ addToListenerHash(name,method,ADD);
+ } else if(name.startsWith("remove")
+ && isVoid
+ && params.length == 1
+ && java.util.EventListener.class.isAssignableFrom(params[0])
+ && name.substring(6).equals(ClassHelper.getTruncatedClassName(params[0]))) {
+ addToListenerHash(name,method,REMOVE);
+ } else {
+ otherMethods.addElement(method);
+ }
+ }
+ }
+
+ public void addMethods(Method[] m) {
+ for(int i=0;i<m.length;i++) {
+ addMethod(m[i]);
+ }
+ }
+
+ public BeanInfoEmbryo getBeanInfoEmbryo() {
+ BeanInfoEmbryo b = new BeanInfoEmbryo();
+ findXXX(b,IS);
+ findXXXInt(b,GET_I);
+ findXXXInt(b,SET_I);
+ findXXX(b,GET);
+ findXXX(b,SET);
+ findAddRemovePairs(b);
+ findRemainingMethods(b,propertyMethods);
+ findRemainingMethods(b,listenerMethods);
+ for(int i=0;i<otherMethods.size();i++) {
+ b.addMethod(new MethodDescriptor((Method)otherMethods.elementAt(i)));
+ }
+ return b;
+ }
+
+ public BeanInfo getBeanInfo() {
+ return getBeanInfoEmbryo().getBeanInfo();
+ }
+
+
+ void findAddRemovePairs(BeanInfoEmbryo b) {
+ try {
+ Enumeration listenerEnum = listenerMethods.keys();
+ Vector toRemove = new Vector();
+ while(listenerEnum.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)listenerEnum.nextElement();
+ Method[] m = (Method[])listenerMethods.get(k);
+ if(m[ADD] != null && m[REMOVE] != null) {
+ EventSetDescriptor e = new EventSetDescriptor(Introspector.decapitalize(k.getName()),
+ k.getType(), k.getType().getMethods(),
+ m[ADD],m[REMOVE]);
+ e.setUnicast(ArrayHelper.contains(m[ADD].getExceptionTypes(),java.util.TooManyListenersException.class));
+ b.addEvent(e);
+ toRemove.addElement(k);
+ }
+ }
+
+ for(int i=0;i<toRemove.size();i++) {
+ listenerMethods.remove(toRemove.elementAt(i));
+ }
+
+ } catch(IntrospectionException e) {
+ System.err.println("Uhoh, Introspection failed in findAddRemovePairs()");
+ }
+ }
+
+ void findRemainingMethods(BeanInfoEmbryo b, Hashtable methodHash) {
+ Enumeration enum = methodHash.elements();
+ while(enum.hasMoreElements()) {
+ Method[] m = (Method[])enum.nextElement();
+ for(int i=0;i<m.length;i++) {
+ if(m[i] != null) {
+ b.addMethod(new MethodDescriptor(m[i]));
+ }
+ }
+ }
+ }
+
+ void findXXX(BeanInfoEmbryo b, int funcType) {
+ try {
+ Enumeration keys = propertyMethods.keys();
+ Vector toRemove = new Vector();
+ while(keys.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)keys.nextElement();
+ Method[] m = (Method[])propertyMethods.get(k);
+ if(m[funcType] != null && !b.hasProperty(Introspector.decapitalize(k.getName()))) {
+ PropertyDescriptor p = new PropertyDescriptor(Introspector.decapitalize(k.getName()),
+ m[IS] != null ? m[IS] : m[GET],
+ m[SET]);
+ if(m[SET] != null) {
+ p.setConstrained(ArrayHelper.contains(m[SET].getExceptionTypes(),java.beans.PropertyVetoException.class));
+ }
+ b.addProperty(p);
+ toRemove.addElement(k);
+ }
+ }
+
+ for(int i=0;i<toRemove.size();i++) {
+ propertyMethods.remove(toRemove.elementAt(i));
+ }
+
+ } catch(IntrospectionException e) {
+ System.err.println("Uhoh, Introspection failed in findXXX()");
+ }
+ }
+
+ void findXXXInt(BeanInfoEmbryo b, int funcType) {
+ try {
+ Enumeration keys = propertyMethods.keys();
+ Vector toRemove = new Vector();
+ while(keys.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)keys.nextElement();
+ Method[] m = (Method[])propertyMethods.get(k);
+ if(m[funcType] != null && !b.hasProperty(Introspector.decapitalize(k.getName()))) {
+ boolean constrained;
+ if(m[SET_I] != null) {
+ constrained = ArrayHelper.contains(m[SET_I].getExceptionTypes(),java.beans.PropertyVetoException.class);
+ } else {
+ constrained = false;
+ }
+
+ /** Find out if there is an array type get or set **/
+ Class arrayType = Array.newInstance(k.getType(),0).getClass();
+ DoubleKey findSetArray = new DoubleKey(arrayType,k.getName());
+ Method[] m2 = (Method[])propertyMethods.get(findSetArray);
+ IndexedPropertyDescriptor p;
+ if(m2 == null) {
+ p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()),
+ null,null,
+ m[GET_I],m[SET_I]);
+ } else {
+ if(constrained && m2[SET] != null) {
+ constrained = ArrayHelper.contains(m2[SET].getExceptionTypes(),java.beans.PropertyVetoException.class);
+ }
+ p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()),
+ m[GET],m[SET],
+ m[GET_I],m[SET_I]);
+ toRemove.addElement(findSetArray);
+ }
+ p.setConstrained(constrained);
+ b.addProperty(p);
+ toRemove.addElement(k);
+ }
+ }
+
+ for(int i=0;i<toRemove.size();i++) {
+ propertyMethods.remove(toRemove.elementAt(i));
+ }
+ } catch(IntrospectionException e) {
+ System.err.println("Uhoh, reflection screwed up in findXXXInt");
+ }
+ }
+
+ static final int IS=0;
+ static final int GET_I=1;
+ static final int SET_I=2;
+ static final int GET=3;
+ static final int SET=4;
+
+ static final int ADD=0;
+ static final int REMOVE=1;
+
+ void addToPropertyHash(String name, Method method, int funcType) {
+ String newName;
+ Class type;
+
+ switch(funcType) {
+ case IS:
+ type = java.lang.Boolean.TYPE;
+ newName = name.substring(2);
+ break;
+ case GET_I:
+ type = method.getReturnType();
+ newName = name.substring(3);
+ break;
+ case SET_I:
+ type = method.getParameterTypes()[1];
+ newName = name.substring(3);
+ break;
+ case GET:
+ type = method.getReturnType();
+ newName = name.substring(3);
+ break;
+ case SET:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(3);
+ break;
+ default:
+ return;
+ }
+ newName = capitalize(newName);
+
+ DoubleKey k = new DoubleKey(type,newName);
+ Method[] methods = (Method[])propertyMethods.get(k);
+ if(methods == null) {
+ methods = new Method[5];
+ propertyMethods.put(k,methods);
+ }
+ methods[funcType] = method;
+ }
+
+
+ void addToListenerHash(String name, Method method, int funcType) {
+ String newName;
+ Class type;
+
+ switch(funcType) {
+ case ADD:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(3);
+ break;
+ case REMOVE:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(6);
+ break;
+ default:
+ return;
+ }
+ newName = capitalize(newName);
+
+ DoubleKey k = new DoubleKey(type,newName);
+ Method[] methods = (Method[])listenerMethods.get(k);
+ if(methods == null) {
+ methods = new Method[2];
+ listenerMethods.put(k,methods);
+ }
+ methods[funcType] = method;
+ }
+
+ static String capitalize(String name) {
+ try {
+ if(Character.isUpperCase(name.charAt(0))) {
+ return name;
+ } else {
+ char[] c = name.toCharArray();
+ c[0] = Character.toLowerCase(c[0]);
+ return new String(c);
+ }
+ } catch(StringIndexOutOfBoundsException E) {
+ return name;
+ } catch(NullPointerException E) {
+ return null;
+ }
+ }
+}
+
+class DoubleKey {
+ Class type;
+ String name;
+
+ DoubleKey(Class type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ Class getType() {
+ return type;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ public boolean equals(Object o) {
+ if(o instanceof DoubleKey) {
+ DoubleKey d = (DoubleKey)o;
+ return d.type.equals(type) && d.name.equals(name);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return type.hashCode() ^ name.hashCode();
+ }
+}