123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /* java.beans.PropertyDescriptor
- Copyright (C) 1998, 2001 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU Classpath 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 for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- 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
- exception statement from your version. */
- package java.beans;
- import java.util.*;
- import java.lang.reflect.*;
- /**
- ** PropertyDescriptor describes information about a JavaBean property,
- ** by which we mean a property that has been exposed via a pair of
- ** get and set methods. (There may be no get method, which means
- ** the property is write-only, or no set method, which means the
- ** the property is read-only.)<P>
- **
- ** The constraints put on get and set methods are:<P>
- ** <OL>
- ** <LI>A get method must have signature
- ** <CODE><propertyType> <getMethodName>()</CODE></LI>
- ** <LI>A set method must have signature
- ** <CODE>void <setMethodName>(<propertyType>)</CODE></LI>
- ** <LI>Either method type may throw any exception.</LI>
- ** <LI>Both methods must be public.</LI>
- ** </OL>
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 26 Jul 1998
- **/
- 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<name>()</CODE>
- ** (or, optionally, if the property is boolean,
- ** <CODE>is<name>()</CODE>) and
- ** <CODE>set<name>()</CODE> in class
- ** <CODE><beanClass></CODE>, where <name> 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) {
- }
- }
- // Fall back to the second get method name
- if (getMethod == null && getMethodName2 != null) {
- try {
- getMethod = beanClass.getMethod(getMethodName2, new Class[0]);
- }
- catch (NoSuchMethodException e) {
- }
- }
- // 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) {
- }
- }
- 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);
- }
- }
- 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);
- }
- 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);
- }
- }
- }
- }
- }
|