Commit fbddd18f by Robert Schuster Committed by Michael Koch

Complete 1.4 support

2004-11-18  Robert Schuster <address@bogus.example.com>

	Complete 1.4 support
	* java/beans/PropertyDescriptor.java:
	(setReadMethod): New method
	(setWriteMethod): New method
	(equals): Implemented (1.4)
	(checkMethods): operates on arguments now (private)

From-SVN: r90876
parent bb30f5c0
2004-11-18 Robert Schuster <address@bogus.example.com>
Complete 1.4 support
* java/beans/PropertyDescriptor.java:
(setReadMethod): New method
(setWriteMethod): New method
(equals): Implemented (1.4)
(checkMethods): operates on arguments now (private)
2004-11-18 Mattias Rehnberg <Mattias.Rehnberg@home.se> 2004-11-18 Mattias Rehnberg <Mattias.Rehnberg@home.se>
* java/net/Inet6Address.java (getHostAddress): Fix textual * java/net/Inet6Address.java (getHostAddress): Fix textual
......
/* java.beans.PropertyDescriptor /* java.beans.PropertyDescriptor
Copyright (C) 1998, 2001 Free Software Foundation, Inc. Copyright (C) 1998, 2001, 2004 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -35,7 +35,6 @@ this exception to your version of the library, but you are not ...@@ -35,7 +35,6 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */ exception statement from your version. */
package java.beans; package java.beans;
import java.lang.reflect.Method; import java.lang.reflect.Method;
...@@ -58,11 +57,13 @@ import java.lang.reflect.Method; ...@@ -58,11 +57,13 @@ import java.lang.reflect.Method;
** </OL> ** </OL>
** **
** @author John Keiser ** @author John Keiser
** @since JDK1.1 ** @author Robert Schuster <thebohemian@gmx.net>
** @version 1.1.0, 26 Jul 1998 ** @since 1.1
** @status updated to 1.4
**/ **/
public class PropertyDescriptor extends FeatureDescriptor { public class PropertyDescriptor extends FeatureDescriptor
{
Class propertyType; Class propertyType;
Method getMethod; Method getMethod;
Method setMethod; Method setMethod;
...@@ -71,7 +72,8 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -71,7 +72,8 @@ public class PropertyDescriptor extends FeatureDescriptor {
boolean bound; boolean bound;
boolean constrained; boolean constrained;
PropertyDescriptor(String name) { PropertyDescriptor(String name)
{
setName(name); setName(name);
} }
...@@ -84,6 +86,10 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -84,6 +86,10 @@ public class PropertyDescriptor extends FeatureDescriptor {
** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its ** <CODE>&lt;beanClass&gt;</CODE>, where &lt;name&gt; has its
** first letter capitalized by the constructor.<P> ** first letter capitalized by the constructor.<P>
** **
** Note that using this constructor the given property must be read- <strong>and</strong>
** writeable. If the implementation does not both, a read and a write method, an
** <code>IntrospectionException</code> is thrown.
**
** <B>Implementation note:</B> If there is both are both isXXX and ** <B>Implementation note:</B> If there is both are both isXXX and
** getXXX methods, the former is used in preference to the latter. ** getXXX methods, the former is used in preference to the latter.
** We do not check that an isXXX method returns a boolean. In both ** We do not check that an isXXX method returns a boolean. In both
...@@ -100,19 +106,27 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -100,19 +106,27 @@ public class PropertyDescriptor extends FeatureDescriptor {
throws IntrospectionException throws IntrospectionException
{ {
setName(name); setName(name);
if (name.length() == 0) { if (name.length() == 0)
{
throw new IntrospectionException("empty property name"); throw new IntrospectionException("empty property name");
} }
String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1); String caps = Character.toUpperCase(name.charAt(0)) + name.substring(1);
findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps); findMethods(beanClass, "is" + caps, "get" + caps, "set" + caps);
if (getMethod == null) {
throw new IntrospectionException("Cannot find an is" + caps + if (getMethod == null)
" or get" + caps + " method"); {
throw new IntrospectionException(
"Cannot find a is" + caps + " or get" + caps + " method");
} }
if (setMethod == null) {
throw new IntrospectionException("Cannot find a " + caps + " method"); if (setMethod == null)
{
throw new IntrospectionException(
"Cannot find a " + caps + " method");
} }
checkMethods();
// finally check the methods compatibility
checkMethods(getMethod, setMethod);
} }
/** Create a new PropertyDescriptor by introspection. /** Create a new PropertyDescriptor by introspection.
...@@ -137,79 +151,142 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -137,79 +151,142 @@ public class PropertyDescriptor extends FeatureDescriptor {
** starting with a lowercase letter (e.g. fooManChu ** starting with a lowercase letter (e.g. fooManChu
** instead of FooManChu). ** instead of FooManChu).
** @param beanClass the class the get and set methods live in. ** @param beanClass the class the get and set methods live in.
** @param getMethodName the name of the get method. ** @param getMethodName the name of the get method or <code>null</code> if the property is write-only.
** @param setMethodName the name of the set method. ** @param setMethodName the name of the set method or <code>null</code> if the property is read-only.
** @exception IntrospectionException if the methods are not found ** @exception IntrospectionException if the methods are not found
** or invalid. ** or invalid.
**/ **/
public PropertyDescriptor(String name, Class beanClass, public PropertyDescriptor(
String getMethodName, String setMethodName) String name,
Class beanClass,
String getMethodName,
String setMethodName)
throws IntrospectionException throws IntrospectionException
{ {
setName(name); setName(name);
findMethods(beanClass, getMethodName, null, setMethodName); findMethods(beanClass, getMethodName, null, setMethodName);
if (getMethod == null && getMethodName != null) {
throw new IntrospectionException("Cannot find a getter method called " + if (getMethod == null && getMethodName != null)
getMethodName); {
throw new IntrospectionException(
"Cannot find a getter method called " + getMethodName);
} }
if (setMethod == null && setMethodName != null) {
throw new IntrospectionException("Cannot find a setter method called " + if (setMethod == null && setMethodName != null)
setMethodName); {
throw new IntrospectionException(
"Cannot find a setter method called " + setMethodName);
} }
checkMethods();
checkMethods(getMethod, setMethod);
} }
/** Create a new PropertyDescriptor using explicit Methods. /** Create a new PropertyDescriptor using explicit Methods.
** Note that the methods will be checked for conformance to standard ** Note that the methods will be checked for conformance to standard
** Property method rules, as described above at the top of this class. ** Property method rules, as described above at the top of this class.
**<br>
** It is possible to call this method with both <code>Method</code> arguments
** being <code>null</code>. In such a case the property type is <code>null</code>.
** **
** @param name the programmatic name of the property, usually ** @param name the programmatic name of the property, usually
** starting with a lowercase letter (e.g. fooManChu ** starting with a lowercase letter (e.g. fooManChu
** instead of FooManChu). ** instead of FooManChu).
** @param getMethod the get method. ** @param readMethod the read method or <code>null</code> if the property is write-only.
** @param setMethod the set method. ** @param writeMethod the write method or <code>null</code> if the property is read-only.
** @exception IntrospectionException if the methods are not found ** @exception IntrospectionException if the methods are not found
** or invalid. ** or invalid.
**/ **/
public PropertyDescriptor(String name, Method getMethod, Method setMethod) public PropertyDescriptor(
String name,
Method readMethod,
Method writeMethod)
throws IntrospectionException throws IntrospectionException
{ {
setName(name); setName(name);
this.getMethod = getMethod; getMethod = readMethod;
this.setMethod = setMethod; setMethod = writeMethod;
if (getMethod != null) {
if (getMethod != null)
{
this.propertyType = getMethod.getReturnType(); this.propertyType = getMethod.getReturnType();
} }
else if (setMethod != null) { else if (setMethod != null)
{
this.propertyType = setMethod.getParameterTypes()[0]; this.propertyType = setMethod.getParameterTypes()[0];
} }
checkMethods();
checkMethods(getMethod, setMethod);
} }
/** Get the property type. /** Get the property type.
** This is the type the get method returns and the set method ** This is the type the get method returns and the set method
** takes in. ** takes in.
**/ **/
public Class getPropertyType() { public Class getPropertyType()
{
return propertyType; return propertyType;
} }
/** Get the get method. Why they call it readMethod here and /** Get the get method. Why they call it readMethod here and
** get everywhere else is beyond me. ** get everywhere else is beyond me.
**/ **/
public Method getReadMethod() { public Method getReadMethod()
{
return getMethod; return getMethod;
} }
/** Sets the read method.<br/>
* The read method is used to retrieve the value of a property. A legal
* read method must have no arguments. Its return type must not be
* <code>void</code>. If this methods succeeds the property type
* is adjusted to the return type of the read method.<br/>
* <br/>
* It is legal to set the read and the write method to <code>null</code>
* or provide method which have been declared in distinct classes.
*
* @param readMethod The new method to be used or <code>null</code>.
* @throws IntrospectionException If the given method is invalid.
* @since 1.2
*/
public void setReadMethod(Method readMethod) throws IntrospectionException
{
checkMethods(readMethod, setMethod);
getMethod = readMethod;
}
/** Get the set method. Why they call it writeMethod here and /** Get the set method. Why they call it writeMethod here and
** set everywhere else is beyond me. ** set everywhere else is beyond me.
**/ **/
public Method getWriteMethod() { public Method getWriteMethod()
{
return setMethod; return setMethod;
} }
/** Sets the write method.<br/>
* The write method is used to set the value of a property. A legal write method
* must have a single argument which can be assigned to the property. If no
* read method exists the property type changes to the argument type of the
* write method.<br/>
* <br/>
* It is legal to set the read and the write method to <code>null</code>
* or provide method which have been declared in distinct classes.
*
* @param writeMethod The new method to be used or <code>null</code>.
* @throws IntrospectionException If the given method is invalid.
* @since 1.2
*/
public void setWriteMethod(Method writeMethod)
throws IntrospectionException
{
propertyType = checkMethods(getMethod, writeMethod);
setMethod = writeMethod;
}
/** Get whether the property is bound. Defaults to false. **/ /** Get whether the property is bound. Defaults to false. **/
public boolean isBound() { public boolean isBound()
{
return bound; return bound;
} }
...@@ -224,12 +301,14 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -224,12 +301,14 @@ public class PropertyDescriptor extends FeatureDescriptor {
** after the value has changed. ** after the value has changed.
** @param bound whether the property is bound or not. ** @param bound whether the property is bound or not.
**/ **/
public void setBound(boolean bound) { public void setBound(boolean bound)
{
this.bound = bound; this.bound = bound;
} }
/** Get whether the property is constrained. Defaults to false. **/ /** Get whether the property is constrained. Defaults to false. **/
public boolean isConstrained() { public boolean isConstrained()
{
return constrained; return constrained;
} }
...@@ -254,12 +333,14 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -254,12 +333,14 @@ public class PropertyDescriptor extends FeatureDescriptor {
** </OL> ** </OL>
** @param constrained whether the property is constrained or not. ** @param constrained whether the property is constrained or not.
**/ **/
public void setConstrained(boolean constrained) { public void setConstrained(boolean constrained)
{
this.constrained = constrained; this.constrained = constrained;
} }
/** Get the PropertyEditor class. Defaults to null. **/ /** Get the PropertyEditor class. Defaults to null. **/
public Class getPropertyEditorClass() { public Class getPropertyEditorClass()
{
return propertyEditorClass; return propertyEditorClass;
} }
...@@ -269,59 +350,78 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -269,59 +350,78 @@ public class PropertyDescriptor extends FeatureDescriptor {
** @param propertyEditorClass the PropertyEditor class for this ** @param propertyEditorClass the PropertyEditor class for this
** class to use. ** class to use.
**/ **/
public void setPropertyEditorClass(Class propertyEditorClass) { public void setPropertyEditorClass(Class propertyEditorClass)
{
this.propertyEditorClass = propertyEditorClass; this.propertyEditorClass = propertyEditorClass;
} }
private void findMethods(Class beanClass, String getMethodName1, private void findMethods(
String getMethodName2, String setMethodName) Class beanClass,
String getMethodName1,
String getMethodName2,
String setMethodName)
throws IntrospectionException throws IntrospectionException
{ {
try { try
{
// Try the first get method name // Try the first get method name
if (getMethodName1 != null) { if (getMethodName1 != null)
try { {
getMethod = beanClass.getMethod(getMethodName1, new Class[0]); try
} {
catch (NoSuchMethodException e) { getMethod =
beanClass.getMethod(getMethodName1, new Class[0]);
} }
catch (NoSuchMethodException e)
{}
} }
// Fall back to the second get method name // Fall back to the second get method name
if (getMethod == null && getMethodName2 != null) { if (getMethod == null && getMethodName2 != null)
try { {
getMethod = beanClass.getMethod(getMethodName2, new Class[0]); try
} {
catch (NoSuchMethodException e) { getMethod =
beanClass.getMethod(getMethodName2, new Class[0]);
} }
catch (NoSuchMethodException e)
{}
} }
// Try the set method name // Try the set method name
if (setMethodName != null) { if (setMethodName != null)
if (getMethod != null) { {
if (getMethod != null)
{
// If there is a get method, use its return type to help // If there is a get method, use its return type to help
// select the corresponding set method. // select the corresponding set method.
Class propertyType = getMethod.getReturnType(); Class propertyType = getMethod.getReturnType();
if (propertyType == Void.TYPE) { if (propertyType == Void.TYPE)
String msg = "The property's read method has return type 'void'"; {
String msg =
"The property's read method has return type 'void'";
throw new IntrospectionException(msg); throw new IntrospectionException(msg);
} }
Class[] setArgs = new Class[]{propertyType}; Class[] setArgs = new Class[] { propertyType };
try { try
{
setMethod = beanClass.getMethod(setMethodName, setArgs); setMethod = beanClass.getMethod(setMethodName, setArgs);
} }
catch (NoSuchMethodException e) { catch (NoSuchMethodException e)
} {}
} }
else if (getMethodName1 == null && getMethodName2 == null) { else if (getMethodName1 == null && getMethodName2 == null)
{
// If this is a write-only property, choose the first set method // If this is a write-only property, choose the first set method
// with the required name, one parameter and return type 'void' // with the required name, one parameter and return type 'void'
Method[] methods = beanClass.getMethods(); Method[] methods = beanClass.getMethods();
for (int i = 0; i < methods.length; i++) { for (int i = 0; i < methods.length; i++)
if (methods[i].getName().equals(setMethodName) && {
methods[i].getParameterTypes().length == 1 && if (methods[i].getName().equals(setMethodName)
methods[i].getReturnType() == Void.TYPE) { && methods[i].getParameterTypes().length == 1
&& methods[i].getReturnType() == Void.TYPE)
{
setMethod = methods[i]; setMethod = methods[i];
break; break;
} }
...@@ -329,46 +429,165 @@ public class PropertyDescriptor extends FeatureDescriptor { ...@@ -329,46 +429,165 @@ public class PropertyDescriptor extends FeatureDescriptor {
} }
} }
} }
catch (SecurityException e) { catch (SecurityException e)
{
// FIXME -- shouldn't we just allow SecurityException to propagate? // FIXME -- shouldn't we just allow SecurityException to propagate?
String msg = "SecurityException thrown on attempt to access methods."; String msg =
"SecurityException thrown on attempt to access methods.";
throw new IntrospectionException(msg); throw new IntrospectionException(msg);
} }
} }
private void checkMethods() /** Checks whether the given <code>Method</code> instances are legal read and
* write methods. The following requirements must be met:<br/>
* <ul>
* <li>the read method must not have an argument</li>
* <li>the read method must have a non void return type</li>
* <li>the read method may not exist</li>
* <li>the write method must have a single argument</li>
* <li>the property type and the read method's return type must be assignable from the
* write method's argument type</li>
* <li>the write method may not exist</li>
* <ul>
* While checking the methods a common new property type is calculated. If the method
* succeeds this property type is returned.<br/>
* <br/>
* For compatibility this has to be noted:<br/>
* The two methods are allowed to be defined in two distinct classes and may both be null.
*
* @param readMethod The new read method to check.
* @param writeMethod The new write method to check.
* @return The common property type of the two method.
* @throws IntrospectionException If any of the above requirements are not met.
*/
private Class checkMethods(Method readMethod, Method writeMethod)
throws IntrospectionException throws IntrospectionException
{ {
if (getMethod != null) { Class newPropertyType = propertyType;
if (getMethod.getParameterTypes().length > 0) {
throw new IntrospectionException("get method has parameters"); // a valid read method has zero arguments and a non-void return type.
if (readMethod != null)
{
if (readMethod.getParameterTypes().length > 0)
{
throw new IntrospectionException("read method has unexpected parameters");
} }
this.propertyType = getMethod.getReturnType();
if (propertyType == Void.TYPE) { newPropertyType = readMethod.getReturnType();
throw new IntrospectionException("get method has void return type");
if (newPropertyType == Void.TYPE)
{
throw new IntrospectionException("read method return type is void");
} }
} }
if (setMethod != null) {
if (setMethod.getParameterTypes().length != 1) { // a valid write method has one argument which can be assigned to the property
String msg = "set method does not have exactly one parameter"; if (writeMethod != null)
{
if (writeMethod.getParameterTypes().length != 1)
{
String msg = "write method does not have exactly one parameter";
throw new IntrospectionException(msg); throw new IntrospectionException(msg);
} }
if (getMethod == null) {
propertyType = setMethod.getParameterTypes()[0]; if (readMethod == null)
{
// changes the property type if there is no read method
newPropertyType = writeMethod.getParameterTypes()[0];
} }
else { else
if (!propertyType.equals(setMethod.getParameterTypes()[0])) { {
String msg = "set and get methods do not share the same type"; // checks whether the write method can be assigned to the return type of the read
throw new IntrospectionException(msg); // method (if this is not the case, the methods are not compatible)
// note: newPropertyType may be null if no methods or method names have been
// delivered in the constructor.
if (newPropertyType != null
&& !newPropertyType.isAssignableFrom(
writeMethod.getParameterTypes()[0]))
{
// note: newPropertyType is the same as readMethod.getReturnType() at this point
throw new IntrospectionException("read and write method are not compatible");
} }
if ((!getMethod.getDeclaringClass().
isAssignableFrom(setMethod.getDeclaringClass())) && /* note: the check whether both method are defined in related classes makes sense but is not
(!setMethod.getDeclaringClass(). * done in the JDK.
isAssignableFrom(getMethod.getDeclaringClass()))) { * I leave this code here in case someone at Sun decides to add that functionality in later versions (rschuster)
String msg = "set and get methods are not in the same class."; if ((!readMethod
.getDeclaringClass()
.isAssignableFrom(writeMethod.getDeclaringClass()))
&& (!writeMethod
.getDeclaringClass()
.isAssignableFrom(readMethod.getDeclaringClass())))
{
String msg =
"set and get methods are not in the same class.";
throw new IntrospectionException(msg); throw new IntrospectionException(msg);
} }
*/
} }
} }
return newPropertyType;
} }
/** Compares this <code>PropertyDescriptor</code> against the
* given object.
* Two PropertyDescriptors are equals if
* <ul>
* <li>the read methods are equal</li>
* <li>the write methods are equal</li>
* <li>the property types are equals</li>
* <li>the property editor classes are equal</li>
* <li>the flags (constrained and bound) are equal</li>
* </ul>
* @return Whether both objects are equal according to the rules given above.
* @since 1.4
*/
public boolean equals(Object o)
{
if (o instanceof PropertyDescriptor)
{
PropertyDescriptor that = (PropertyDescriptor) o;
// compares the property types and checks the case where both are null
boolean samePropertyType =
(propertyType == null)
? that.propertyType == null
: propertyType.equals(that.propertyType);
// compares the property editor classes and checks the case where both are null
boolean samePropertyEditorClass =
(propertyEditorClass == null)
? that.propertyEditorClass == null
: propertyEditorClass.equals(that.propertyEditorClass);
// compares the flags for equality
boolean sameFlags =
bound == that.bound && constrained == that.constrained;
// compares the read methods and checks the case where both are null
boolean sameReadMethod =
(getMethod == null)
? that.getMethod == null
: getMethod.equals(that.getMethod);
boolean sameWriteMethod =
(setMethod == null)
? that.setMethod == null
: setMethod.equals(that.setMethod);
return samePropertyType
&& sameFlags
&& sameReadMethod
&& sameWriteMethod
&& samePropertyEditorClass;
}
else
{
return false;
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment