home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / beans / PropertyDescriptor.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  10.6 KB  |  330 lines

  1. /*
  2.  * @(#)PropertyDescriptor.java    1.44 98/03/18
  3.  *
  4.  * Copyright 1996, 1997 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.beans;
  16.  
  17. import java.lang.reflect.*;
  18.  
  19. /**
  20.  * A PropertyDescriptor describes one property that a Java Bean
  21.  * exports via a pair of accessor methods.
  22.  */
  23.  
  24. public class PropertyDescriptor extends FeatureDescriptor {
  25.  
  26.     /**
  27.      * Constructs a PropertyDescriptor for a property that follows
  28.      * the standard Java convention by having getFoo and setFoo 
  29.      * accessor methods.  Thus if the argument name is "fred", it will
  30.      * assume that the writer method is "setFred" and the writer method 
  31.      * is "getFred" (or "isFred" for a boolean property).  Note that the
  32.      * property name should start with a lower case character, which will
  33.      * be capitalized in the method names.
  34.      *
  35.      * @param propertyName The programmatic name of the property.
  36.      * @param beanClass The Class object for the target bean.  For
  37.      *        example sun.beans.OurButton.class.
  38.      * @exception IntrospectionException if an exception occurs during
  39.      *              introspection.
  40.      */
  41.     public PropertyDescriptor(String propertyName, Class beanClass)
  42.         throws IntrospectionException {
  43.     if (propertyName == null || propertyName.length() == 0) {
  44.         throw new IntrospectionException("bad property name");
  45.     }
  46.     setName(propertyName);
  47.     String base = capitalize(propertyName);
  48.     writeMethod = Introspector.findMethod(beanClass, "set" + base, 1);
  49.     // If it's a boolean property check for an "isFoo" first.
  50.     if (writeMethod.getParameterTypes()[0] == Boolean.TYPE) {
  51.         try {
  52.         readMethod = Introspector.findMethod(beanClass, "is" + base, 0);
  53.         } catch (Exception ex) {
  54.         }
  55.     }
  56.     if (readMethod == null) {
  57.         readMethod = Introspector.findMethod(beanClass, "get" + base, 0);
  58.     }
  59.     findPropertyType();
  60.     }
  61.  
  62.     /**
  63.      * This constructor takes the name of a simple property, and method
  64.      * names for reading and writing the property.
  65.      *
  66.      * @param propertyName The programmatic name of the property.
  67.      * @param beanClass The Class object for the target bean.  For
  68.      *        example sun.beans.OurButton.class.
  69.      * @param getterName The name of the method used for reading the property
  70.      *         value.  May be null if the property is write-only.
  71.      * @param setterName The name of the method used for writing the property
  72.      *         value.  May be null if the property is read-only.
  73.      * @exception IntrospectionException if an exception occurs during
  74.      *              introspection.
  75.      */
  76.     public PropertyDescriptor(String propertyName, Class beanClass,
  77.         String getterName, String setterName)
  78.         throws IntrospectionException {
  79.     if (propertyName == null || propertyName.length() == 0) {
  80.         throw new IntrospectionException("bad property name");
  81.     }
  82.     setName(propertyName);
  83.     readMethod = Introspector.findMethod(beanClass, getterName, 0);
  84.     writeMethod = Introspector.findMethod(beanClass, setterName, 1);
  85.     findPropertyType();
  86.     }
  87.  
  88.     /**
  89.      * This constructor takes the name of a simple property, and Method
  90.      * objects for reading and writing the property.
  91.      *
  92.      * @param propertyName The programmatic name of the property.
  93.      * @param getter The method used for reading the property value.
  94.      *        May be null if the property is write-only.
  95.      * @param setter The method used for writing the property value.  
  96.      *        May be null if the property is read-only.
  97.      * @exception IntrospectionException if an exception occurs during
  98.      *              introspection.
  99.      */
  100.     public PropertyDescriptor(String propertyName, Method getter, Method setter)
  101.         throws IntrospectionException {
  102.     if (propertyName == null || propertyName.length() == 0) {
  103.         throw new IntrospectionException("bad property name");
  104.     }
  105.     setName(propertyName);
  106.     readMethod = getter;
  107.     writeMethod = setter;
  108.     findPropertyType(); 
  109.     }
  110.     
  111.     /**
  112.      * @return The Java type info for the property.  Note that
  113.      * the "Class" object may describe a built-in Java type such as "int".
  114.      * The result may be "null" if this is an indexed property that
  115.      * does not support non-indexed access.
  116.      * <p>
  117.      * This is the type that will be returned by the ReadMethod.
  118.      */
  119.     public Class getPropertyType() {
  120.     return propertyType;
  121.     }
  122.  
  123.     /**
  124.      * @return The method that should be used to read the property value.
  125.      * May return null if the property can't be read.
  126.      */
  127.     public Method getReadMethod() {
  128.     return readMethod;
  129.     }
  130.  
  131.     /**
  132.      * Set the method that should be used to read the property value.
  133.      * @param getter The new getter method.
  134.      */
  135.     public void setReadMethod(Method getter) 
  136.                 throws IntrospectionException {
  137.     readMethod = getter;
  138.     findPropertyType(); 
  139.     }
  140.  
  141.     /**
  142.      * @return The method that should be used to write the property value.
  143.      * May return null if the property can't be written.
  144.      */
  145.     public Method getWriteMethod() {
  146.     return writeMethod;
  147.     }
  148.  
  149.     /**
  150.      * Set the method that should be used to write the property value.
  151.      * @param setter The new setter method.
  152.      */
  153.     public void setWriteMethod(Method setter)
  154.                 throws IntrospectionException {
  155.     writeMethod = setter;
  156.     findPropertyType(); 
  157.     }
  158.  
  159.     /**
  160.      * Updates to "bound" properties will cause a "PropertyChange" event to
  161.      * get fired when the property is changed.
  162.      *
  163.      * @return True if this is a bound property.
  164.      */
  165.     public boolean isBound() {
  166.     return bound;
  167.     }
  168.  
  169.     /**
  170.      * Updates to "bound" properties will cause a "PropertyChange" event to 
  171.      * get fired when the property is changed.
  172.      *
  173.      * @param bound True if this is a bound property.
  174.      */
  175.     public void setBound(boolean bound) {
  176.     this.bound = bound;
  177.     }
  178.  
  179.     /**
  180.      * Attempted updates to "Constrained" properties will cause a "VetoableChange"
  181.      * event to get fired when the property is changed.
  182.      *
  183.      * @return True if this is a constrained property.
  184.      */
  185.     public boolean isConstrained() {
  186.     return constrained;
  187.     }
  188.  
  189.     /**
  190.      * Attempted updates to "Constrained" properties will cause a "VetoableChange"
  191.      * event to get fired when the property is changed.
  192.      *
  193.      * @param constrained True if this is a constrained property.
  194.      */
  195.     public void setConstrained(boolean constrained) {
  196.     this.constrained = constrained;
  197.     }
  198.  
  199.  
  200.     /**
  201.      * Normally PropertyEditors will be found using the PropertyEditorManager.
  202.      * However if for some reason you want to associate a particular
  203.      * PropertyEditor with a given property, then you can do it with
  204.      * this method.
  205.      * @param propertyEditorClass  The Class for the desired PropertyEditor.
  206.      */
  207.     public void setPropertyEditorClass(Class propertyEditorClass) {
  208.     this.propertyEditorClass = propertyEditorClass;
  209.     }
  210.  
  211.     /**
  212.      * @return Any explicit PropertyEditor Class that has been registered
  213.      *        for this property.  Normally this will return "null",
  214.      *        indicating that no special editor has been registered,
  215.      *        so the PropertyEditorManager should be used to locate
  216.      *        a suitable PropertyEditor.
  217.      */
  218.     public Class getPropertyEditorClass() {
  219.     return propertyEditorClass;
  220.     }
  221.  
  222.     /*
  223.      * Package-private constructor.
  224.      * Merge two property descriptors.  Where they conflict, give the
  225.      * second argument (y) priority over the first argument (x).
  226.      * @param x  The first (lower priority) PropertyDescriptor
  227.      * @param y  The second (higher priority) PropertyDescriptor
  228.      */
  229.  
  230.     PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
  231.     super(x,y);
  232.  
  233.     // Figure out the merged read method.
  234.     Method xr = x.readMethod;
  235.     Method yr = y.readMethod;
  236.     readMethod = xr;
  237.     // Normally give priority to y's readMethod.
  238.     if (yr != null) {
  239.         readMethod = yr;
  240.     }
  241.     // However, if both x and y reference read methods in the same class,
  242.     // give priority to a boolean "is" method over a boolean "get" method.
  243.     if (xr != null && yr != null &&
  244.            xr.getDeclaringClass() == yr.getDeclaringClass() &&
  245.            xr.getReturnType() == boolean.class &&
  246.            yr.getReturnType() == boolean.class && 
  247.            xr.getName().indexOf("is") == 0 &&
  248.            yr.getName().indexOf("get") == 0) {
  249.         readMethod = xr;
  250.     }
  251.  
  252.     writeMethod = x.writeMethod;
  253.     if (y.writeMethod != null) {
  254.         writeMethod = y.writeMethod;
  255.     }
  256.  
  257.     propertyEditorClass = x.propertyEditorClass;
  258.     if (y.propertyEditorClass != null) {
  259.         propertyEditorClass = y.propertyEditorClass;
  260.     }
  261.  
  262.     bound = x.bound | y.bound;
  263.     constrained = x.constrained | y.constrained;
  264.     try {
  265.         findPropertyType();
  266.     } catch (IntrospectionException ex) {
  267.         // Given we're merging two valid PDs, this "should never happen".
  268.         throw new Error("PropertyDescriptor: internal error while merging PDs");
  269.     }
  270.     }
  271.  
  272.     /*
  273.      * Package-private dup constructor.
  274.      * This must isolate the new object from any changes to the old object.
  275.      */
  276.     PropertyDescriptor(PropertyDescriptor old) {
  277.     super(old);
  278.     readMethod = old.readMethod;;
  279.     writeMethod = old.writeMethod;
  280.     propertyEditorClass = old.propertyEditorClass;
  281.     bound = old.bound;
  282.     constrained = old.constrained;
  283.     propertyType = old.propertyType;
  284.     }
  285.  
  286.     private void findPropertyType() throws IntrospectionException {
  287.     try {
  288.         propertyType = null;
  289.         if (readMethod != null) {
  290.         if (readMethod.getParameterTypes().length != 0) {
  291.             throw new IntrospectionException("bad read method arg count");
  292.         }
  293.         propertyType = readMethod.getReturnType();
  294.         if (propertyType == Void.TYPE) {
  295.             throw new IntrospectionException("read method " + 
  296.                     readMethod.getName() + " returns void");
  297.         }
  298.         }
  299.         if (writeMethod != null) {
  300.         Class params[] = writeMethod.getParameterTypes();
  301.         if (params.length != 1) {
  302.             throw new IntrospectionException("bad write method arg count");
  303.         }
  304.         if (propertyType != null && propertyType != params[0]) {
  305.             throw new IntrospectionException("type mismatch between read and write methods");
  306.         }
  307.         propertyType = params[0];
  308.         }
  309.     } catch (IntrospectionException ex) {
  310.         throw ex;
  311.     }
  312.     }
  313.  
  314.     static String capitalize(String s) {
  315.     if (s.length() == 0) {
  316.          return s;
  317.     }
  318.     char chars[] = s.toCharArray();
  319.     chars[0] = Character.toUpperCase(chars[0]);
  320.     return new String(chars);
  321.     }
  322.  
  323.     private Class propertyType;
  324.     private Method readMethod;
  325.     private Method writeMethod;
  326.     private boolean bound;
  327.     private boolean constrained;
  328.     private Class propertyEditorClass;
  329. }
  330.