aboutsummaryrefslogtreecommitdiff
path: root/libjava/java
diff options
context:
space:
mode:
authorStephen Crawley <crawley@dstc.edu.au>2003-02-07 20:19:53 +0000
committerMark Wielaard <mark@gcc.gnu.org>2003-02-07 20:19:53 +0000
commitb20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e (patch)
tree5ba867c6dfed9c3a71e924ab93866436f2e9ea98 /libjava/java
parent7bf0a5935361a7af3bf7823d6733c2f691a7529f (diff)
downloadgcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.zip
gcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.tar.gz
gcc-b20fcd47a23ead8ed5ea9ce22c0b4b196380ce8e.tar.bz2
Stephen Crawley <crawley@dstc.edu.au>
* java/beans/PropertyDescriptor.java (PropertyDescriptor(String, Class)): Sanity check getter and setter methods. (PropertyDescriptor(String, Class, String, String)): Likewise. (PropertyDescriptor(String, Method, Method): Factor out getter and setter method sanity checks into new method. (findMethods): Don't do parameter sanity checking of get method here. (checkMethods): New method. 2003-02-07 Stephen Crawley <crawley@dstc.edu.au> * java/beans/PropertyDescriptor.java: Reformat. From-SVN: r62537
Diffstat (limited to 'libjava/java')
-rw-r--r--libjava/java/beans/PropertyDescriptor.java566
1 files changed, 299 insertions, 267 deletions
diff --git a/libjava/java/beans/PropertyDescriptor.java b/libjava/java/beans/PropertyDescriptor.java
index b75cac9..00db416 100644
--- a/libjava/java/beans/PropertyDescriptor.java
+++ b/libjava/java/beans/PropertyDescriptor.java
@@ -65,280 +65,312 @@ import java.lang.reflect.*;
**/
public class PropertyDescriptor extends FeatureDescriptor {
- Class propertyType;
- Method getMethod;
- Method setMethod;
-
- Class propertyEditorClass;
- boolean bound;
- boolean constrained;
-
- PropertyDescriptor(String name) {
- setName(name);
- }
-
- /** Create a new PropertyDescriptor by introspection.
- ** This form of constructor creates the PropertyDescriptor by
- ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>
- ** (or, optionally, if the property is boolean,
- ** <CODE>is&lt;name&gt;()</CODE>) and
- ** <CODE>set&lt;name&gt;()</CODE> in class
- ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
- ** first letter capitalized by the constructor.<P>
- **
- ** <B>Implementation note:</B> If there is a get method (or
- ** boolean isXXX() method), then the return type of that method
- ** is used to find the set method. If there is no get method,
- ** then the set method is searched for exhaustively.<P>
- **
- ** <B>Spec note:</B>
- ** If there is no get method and multiple set methods with
- ** the same name and a single parameter (different type of course),
- ** then an IntrospectionException is thrown. While Sun's spec
- ** does not state this, it can make Bean behavior different on
- ** different systems (since method order is not guaranteed) and as
- ** such, can be treated as a bug in the spec. I am not aware of
- ** whether Sun's implementation catches this.
- **
- ** @param name the programmatic name of the property, usually
- ** starting with a lowercase letter (e.g. fooManChu
- ** instead of FooManChu).
- ** @param beanClass the class the get and set methods live in.
- ** @exception IntrospectionException if the methods are not found or invalid.
- **/
- public PropertyDescriptor(String name, Class beanClass) throws IntrospectionException {
- setName(name);
- String capitalized;
- try {
- capitalized = Character.toUpperCase(name.charAt(0)) + name.substring(1);
- } catch(StringIndexOutOfBoundsException e) {
- capitalized = "";
- }
- findMethods(beanClass, "is" + capitalized, "get" + capitalized, "set" + capitalized);
- }
-
- /** Create a new PropertyDescriptor by introspection.
- ** This form of constructor allows you to specify the
- ** names of the get and set methods to search for.<P>
- **
- ** <B>Implementation note:</B> If there is a get method (or
- ** boolean isXXX() method), then the return type of that method
- ** is used to find the set method. If there is no get method,
- ** then the set method is searched for exhaustively.<P>
- **
- ** <B>Spec note:</B>
- ** If there is no get method and multiple set methods with
- ** the same name and a single parameter (different type of course),
- ** then an IntrospectionException is thrown. While Sun's spec
- ** does not state this, it can make Bean behavior different on
- ** different systems (since method order is not guaranteed) and as
- ** such, can be treated as a bug in the spec. I am not aware of
- ** whether Sun's implementation catches this.
- **
- ** @param name the programmatic name of the property, usually
- ** starting with a lowercase letter (e.g. fooManChu
- ** instead of FooManChu).
- ** @param beanClass the class the get and set methods live in.
- ** @param getMethodName the name of the get method.
- ** @param setMethodName the name of the set method.
- ** @exception IntrospectionException if the methods are not found or invalid.
- **/
- public PropertyDescriptor(String name, Class beanClass, String getMethodName, String setMethodName) throws IntrospectionException {
- setName(name);
- findMethods(beanClass, getMethodName, null, setMethodName);
- }
-
- /** Create a new PropertyDescriptor using explicit Methods.
- ** Note that the methods will be checked for conformance to standard
- ** Property method rules, as described above at the top of this class.
- **
- ** @param name the programmatic name of the property, usually
- ** starting with a lowercase letter (e.g. fooManChu
- ** instead of FooManChu).
- ** @param getMethod the get method.
- ** @param setMethod the set method.
- ** @exception IntrospectionException if the methods are not found or invalid.
- **/
- public PropertyDescriptor(String name, Method getMethod, Method setMethod) throws IntrospectionException {
- setName(name);
- if(getMethod != null && getMethod.getParameterTypes().length > 0) {
- throw new IntrospectionException("get method has parameters");
- }
- if(setMethod != null && setMethod.getParameterTypes().length != 1) {
- throw new IntrospectionException("set method does not have exactly one parameter");
- }
- if(getMethod != null && setMethod != null) {
- if(!getMethod.getReturnType().equals(setMethod.getParameterTypes()[0])) {
- throw new IntrospectionException("set and get methods do not share the same type");
- }
- if(!getMethod.getDeclaringClass().isAssignableFrom(setMethod.getDeclaringClass())
- && !setMethod.getDeclaringClass().isAssignableFrom(getMethod.getDeclaringClass())) {
- throw new IntrospectionException("set and get methods are not in the same class.");
- }
- }
- this.getMethod = getMethod;
- this.setMethod = setMethod;
- if(getMethod != null) {
- this.propertyType = getMethod.getReturnType();
- } else {
- this.propertyType = setMethod.getParameterTypes()[0];
- }
- }
-
- /** Get the property type.
- ** This is the type the get method returns and the set method
- ** takes in.
- **/
- public Class getPropertyType() {
- return propertyType;
- }
-
- /** Get the get method. Why they call it readMethod here and
- ** get everywhere else is beyond me.
- **/
- public Method getReadMethod() {
- return getMethod;
- }
-
- /** Get the set method. Why they call it writeMethod here and
- ** set everywhere else is beyond me.
- **/
- public Method getWriteMethod() {
- return setMethod;
+ Class propertyType;
+ Method getMethod;
+ Method setMethod;
+
+ Class propertyEditorClass;
+ boolean bound;
+ boolean constrained;
+
+ PropertyDescriptor(String name) {
+ setName(name);
+ }
+
+ /** Create a new PropertyDescriptor by introspection.
+ ** This form of constructor creates the PropertyDescriptor by
+ ** looking for a getter method named <CODE>get&lt;name&gt;()</CODE>
+ ** (or, optionally, if the property is boolean,
+ ** <CODE>is&lt;name&gt;()</CODE>) and
+ ** <CODE>set&lt;name&gt;()</CODE> in class
+ ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
+ ** first letter capitalized by the constructor.<P>
+ **
+ ** <B>Implementation note:</B> If there is both are both isXXX and
+ ** getXXX methods, the former is used in preference to the latter.
+ ** We do not check that an isXXX method returns a boolean. In both
+ ** cases, this matches the behaviour of JDK 1.4<P>
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param beanClass the class the get and set methods live in.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(String name, Class beanClass)
+ throws IntrospectionException
+ {
+ setName(name);
+ if (name.length() == 0) {
+ throw new IntrospectionException("empty property name");
+ }
+ String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps);
+ if (getMethod == null) {
+ throw new IntrospectionException("Cannot find an is" + caps +
+ " or get" + caps + " method");
+ }
+ if (setMethod == null) {
+ throw new IntrospectionException("Cannot find a " + caps + " method");
+ }
+ checkMethods();
+ }
+
+ /** Create a new PropertyDescriptor by introspection.
+ ** This form of constructor allows you to specify the
+ ** names of the get and set methods to search for.<P>
+ **
+ ** <B>Implementation note:</B> If there is a get method (or
+ ** boolean isXXX() method), then the return type of that method
+ ** is used to find the set method. If there is no get method,
+ ** then the set method is searched for exhaustively.<P>
+ **
+ ** <B>Spec note:</B>
+ ** If there is no get method and multiple set methods with
+ ** the same name and a single parameter (different type of course),
+ ** then an IntrospectionException is thrown. While Sun's spec
+ ** does not state this, it can make Bean behavior different on
+ ** different systems (since method order is not guaranteed) and as
+ ** such, can be treated as a bug in the spec. I am not aware of
+ ** whether Sun's implementation catches this.
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param beanClass the class the get and set methods live in.
+ ** @param getMethodName the name of the get method.
+ ** @param setMethodName the name of the set method.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(String name, Class beanClass,
+ String getMethodName, String setMethodName)
+ throws IntrospectionException
+ {
+ setName(name);
+ findMethods(beanClass, getMethodName, null, setMethodName);
+ if (getMethod == null && getMethodName != null) {
+ throw new IntrospectionException("Cannot find a getter method called " +
+ getMethodName);
+ }
+ if (setMethod == null && setMethodName != null) {
+ throw new IntrospectionException("Cannot find a setter method called " +
+ setMethodName);
+ }
+ checkMethods();
+ }
+
+ /** Create a new PropertyDescriptor using explicit Methods.
+ ** Note that the methods will be checked for conformance to standard
+ ** Property method rules, as described above at the top of this class.
+ **
+ ** @param name the programmatic name of the property, usually
+ ** starting with a lowercase letter (e.g. fooManChu
+ ** instead of FooManChu).
+ ** @param getMethod the get method.
+ ** @param setMethod the set method.
+ ** @exception IntrospectionException if the methods are not found
+ ** or invalid.
+ **/
+ public PropertyDescriptor(String name, Method getMethod, Method setMethod)
+ throws IntrospectionException
+ {
+ setName(name);
+ this.getMethod = getMethod;
+ this.setMethod = setMethod;
+ if (getMethod != null) {
+ this.propertyType = getMethod.getReturnType();
+ }
+ else if (setMethod != null) {
+ this.propertyType = setMethod.getParameterTypes()[0];
+ }
+ checkMethods();
+ }
+
+ /** Get the property type.
+ ** This is the type the get method returns and the set method
+ ** takes in.
+ **/
+ public Class getPropertyType() {
+ return propertyType;
+ }
+
+ /** Get the get method. Why they call it readMethod here and
+ ** get everywhere else is beyond me.
+ **/
+ public Method getReadMethod() {
+ return getMethod;
+ }
+
+ /** Get the set method. Why they call it writeMethod here and
+ ** set everywhere else is beyond me.
+ **/
+ public Method getWriteMethod() {
+ return setMethod;
+ }
+
+ /** Get whether the property is bound. Defaults to false. **/
+ public boolean isBound() {
+ return bound;
+ }
+
+ /** Set whether the property is bound.
+ ** As long as the the bean implements addPropertyChangeListener() and
+ ** removePropertyChangeListener(), setBound(true) may safely be called.<P>
+ ** If these things are not true, then the behavior of the system
+ ** will be undefined.<P>
+ **
+ ** When a property is bound, its set method is required to fire the
+ ** <CODE>PropertyChangeListener.propertyChange())</CODE> event
+ ** after the value has changed.
+ ** @param bound whether the property is bound or not.
+ **/
+ public void setBound(boolean bound) {
+ this.bound = bound;
+ }
+
+ /** Get whether the property is constrained. Defaults to false. **/
+ public boolean isConstrained() {
+ return constrained;
+ }
+
+ /** Set whether the property is constrained.
+ ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>
+ ** (or subclass thereof) and the bean implements addVetoableChangeListener()
+ ** and removeVetoableChangeListener(), then setConstrained(true) may safely
+ ** be called. Otherwise, the system behavior is undefined.
+ ** <B>Spec note:</B> given those strict parameters, it would be nice if it
+ ** got set automatically by detection, but oh well.<P>
+ ** When a property is constrained, its set method is required to:<P>
+ ** <OL>
+ ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>
+ ** event notifying others of the change and allowing them a chance to
+ ** say it is a bad thing.</LI>
+ ** <LI>If any of the listeners throws a PropertyVetoException, then
+ ** it must fire another vetoableChange() event notifying the others
+ ** of a reversion to the old value (though, of course, the change
+ ** was never made). Then it rethrows the PropertyVetoException and
+ ** exits.</LI>
+ ** <LI>If all has gone well to this point, the value may be changed.</LI>
+ ** </OL>
+ ** @param constrained whether the property is constrained or not.
+ **/
+ public void setConstrained(boolean constrained) {
+ this.constrained = constrained;
+ }
+
+ /** Get the PropertyEditor class. Defaults to null. **/
+ public Class getPropertyEditorClass() {
+ return propertyEditorClass;
+ }
+
+ /** Set the PropertyEditor class. If the class does not implement
+ ** the PropertyEditor interface, you will likely get an exception
+ ** late in the game.
+ ** @param propertyEditorClass the PropertyEditor class for this
+ ** class to use.
+ **/
+ public void setPropertyEditorClass(Class propertyEditorClass) {
+ this.propertyEditorClass = propertyEditorClass;
+ }
+
+ private void findMethods(Class beanClass, String getMethodName1,
+ String getMethodName2, String setMethodName)
+ throws IntrospectionException
+ {
+ try {
+ // Try the first get method name
+ if (getMethodName1 != null) {
+ try {
+ getMethod = beanClass.getMethod(getMethodName1, new Class[0]);
+ }
+ catch (NoSuchMethodException e) {
}
+ }
- /** Get whether the property is bound. Defaults to false. **/
- public boolean isBound() {
- return bound;
+ // Fall back to the second get method name
+ if (getMethod == null && getMethodName2 != null) {
+ try {
+ getMethod = beanClass.getMethod(getMethodName2, new Class[0]);
+ }
+ catch (NoSuchMethodException e) {
}
+ }
- /** Set whether the property is bound.
- ** As long as the the bean implements addPropertyChangeListener() and
- ** removePropertyChangeListener(), setBound(true) may safely be called.<P>
- ** If these things are not true, then the behavior of the system
- ** will be undefined.<P>
- **
- ** When a property is bound, its set method is required to fire the
- ** <CODE>PropertyChangeListener.propertyChange())</CODE> event
- ** after the value has changed.
- ** @param bound whether the property is bound or not.
- **/
- public void setBound(boolean bound) {
- this.bound = bound;
+ // Try the set method name
+ if (setMethodName != null) {
+ if (getMethod != null) {
+ // If there is a get method, use its return type to help
+ // select the corresponding set method.
+ Class propertyType = getMethod.getReturnType();
+ if (propertyType == Void.TYPE) {
+ String msg = "The property's read method has return type 'void'";
+ throw new IntrospectionException(msg);
+ }
+
+ Class[] setArgs = new Class[]{propertyType};
+ try {
+ setMethod = beanClass.getMethod(setMethodName, setArgs);
+ }
+ catch (NoSuchMethodException e) {
+ }
}
-
- /** Get whether the property is constrained. Defaults to false. **/
- public boolean isConstrained() {
- return constrained;
- }
-
- /** Set whether the property is constrained.
- ** If the set method throws <CODE>java.beans.PropertyVetoException</CODE>
- ** (or subclass thereof) and the bean implements addVetoableChangeListener()
- ** and removeVetoableChangeListener(), then setConstrained(true) may safely
- ** be called. Otherwise, the system behavior is undefined.
- ** <B>Spec note:</B> given those strict parameters, it would be nice if it
- ** got set automatically by detection, but oh well.<P>
- ** When a property is constrained, its set method is required to:<P>
- ** <OL>
- ** <LI>Fire the <CODE>VetoableChangeListener.vetoableChange()</CODE>
- ** event notifying others of the change and allowing them a chance to
- ** say it is a bad thing.</LI>
- ** <LI>If any of the listeners throws a PropertyVetoException, then
- ** it must fire another vetoableChange() event notifying the others
- ** of a reversion to the old value (though, of course, the change
- ** was never made). Then it rethrows the PropertyVetoException and
- ** exits.</LI>
- ** <LI>If all has gone well to this point, the value may be changed.</LI>
- ** </OL>
- ** @param constrained whether the property is constrained or not.
- **/
- public void setConstrained(boolean constrained) {
- this.constrained = constrained;
+ else if (getMethodName1 == null && getMethodName2 == null) {
+ // If this is a write-only property, choose the first set method
+ // with the required name, one parameter and return type 'void'
+ Method[] methods = beanClass.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().equals(setMethodName) &&
+ methods[i].getParameterTypes().length == 1 &&
+ methods[i].getReturnType() == Void.TYPE) {
+ setMethod = methods[i];
+ break;
+ }
+ }
}
+ }
+ }
+ catch (SecurityException e) {
+ // FIXME -- shouldn't we just allow SecurityException to propagate?
+ String msg = "SecurityException thrown on attempt to access methods.";
+ throw new IntrospectionException(msg);
+ }
+ }
- /** Get the PropertyEditor class. Defaults to null. **/
- public Class getPropertyEditorClass() {
- return propertyEditorClass;
+ private void checkMethods()
+ throws IntrospectionException
+ {
+ if (getMethod != null) {
+ if (getMethod.getParameterTypes().length > 0) {
+ throw new IntrospectionException("get method has parameters");
+ }
+ this.propertyType = getMethod.getReturnType();
+ if (propertyType == Void.TYPE) {
+ throw new IntrospectionException("get method has void return type");
+ }
+ }
+ if (setMethod != null) {
+ if (setMethod.getParameterTypes().length != 1) {
+ String msg = "set method does not have exactly one parameter";
+ throw new IntrospectionException(msg);
+ }
+ if (getMethod == null) {
+ propertyType = setMethod.getParameterTypes()[0];
+ }
+ else {
+ if (!propertyType.equals(setMethod.getParameterTypes()[0])) {
+ String msg = "set and get methods do not share the same type";
+ throw new IntrospectionException(msg);
}
-
- /** Set the PropertyEditor class. If the class does not implement
- ** the PropertyEditor interface, you will likely get an exception
- ** late in the game.
- ** @param propertyEditorClass the PropertyEditor class for this class to use.
- **/
- public void setPropertyEditorClass(Class propertyEditorClass) {
- this.propertyEditorClass = propertyEditorClass;
- }
-
- private void findMethods(Class beanClass, String getMethodName1, String getMethodName2, String setMethodName) throws IntrospectionException {
- try {
- if(getMethodName1 != null) {
- try {
- getMethod = beanClass.getMethod(getMethodName1, new Class[0]);
- } catch(NoSuchMethodException E) {
- }
- if(getMethodName2 != null) {
- if(getMethod != null && !getMethod.getReturnType().equals(java.lang.Boolean.TYPE)) {
- // If the is() method exists but isn't boolean, we'll just go on and look for
- // an ordinary get() method.
- getMethod = null;
- }
-
- Method getMethod2;
- try {
- getMethod2 = beanClass.getMethod(getMethodName2, new Class[0]);
- } catch(NoSuchMethodException E) {
- getMethod2 = null;
- }
- if(getMethod2 != null) {
- if(getMethod != null) {
- if(!getMethod.getReturnType().equals(getMethod2.getReturnType())) {
- throw new IntrospectionException("Both " + getMethodName1 + " and " + getMethodName2 + " exist, and have contradictory return types.");
- }
- } else {
- getMethod = getMethod2;
- }
- }
- }
- }
-
- if(getMethod != null) {
- propertyType = getMethod.getReturnType();
- if(setMethodName != null) {
- Class[] setArgs = new Class[1];
- setArgs[0] = propertyType;
- try {
- setMethod = beanClass.getMethod(setMethodName, setArgs);
- if(!setMethod.getReturnType().equals(java.lang.Void.TYPE)) {
- throw new IntrospectionException(setMethodName + " has non-void return type");
- }
- } catch(NoSuchMethodException E) {
- }
- }
- } else if(setMethodName != null) {
- Method[] m = beanClass.getMethods();
- for(int i=0;i<m.length;i++) {
- Method current = m[i];
- if(current.getName().equals(setMethodName)
- && current.getParameterTypes().length == 1
- && current.getReturnType().equals(java.lang.Void.TYPE)) {
- if(setMethod != null) {
- throw new IntrospectionException("Multiple, different set methods found that fit the bill!");
- } else {
- setMethod = current;
- propertyType = current.getParameterTypes()[0];
- }
- }
- }
- if(setMethod == null) {
- throw new IntrospectionException("Cannot find get or set methods.");
- }
- } else {
- throw new IntrospectionException("Cannot find get or set methods.");
- }
- } catch(SecurityException E) {
- throw new IntrospectionException("SecurityException thrown on attempt to access methods.");
- }
+ if ((!getMethod.getDeclaringClass().
+ isAssignableFrom(setMethod.getDeclaringClass())) &&
+ (!setMethod.getDeclaringClass().
+ isAssignableFrom(getMethod.getDeclaringClass()))) {
+ String msg = "set and get methods are not in the same class.";
+ throw new IntrospectionException(msg);
}
+ }
+ }
+ }
}