Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]
    1   /*
    2    * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.beans;
   27   
   28   import java.lang.ref.Reference;
   29   
   30   import java.lang.reflect.Method;
   31   
   32   /**
   33    * An IndexedPropertyDescriptor describes a property that acts like an
   34    * array and has an indexed read and/or indexed write method to access
   35    * specific elements of the array.
   36    * <p>
   37    * An indexed property may also provide simple non-indexed read and write
   38    * methods.  If these are present, they read and write arrays of the type
   39    * returned by the indexed read method.
   40    */
   41   
   42   public class IndexedPropertyDescriptor extends PropertyDescriptor {
   43   
   44       private Reference<Class> indexedPropertyTypeRef;
   45       private Reference<Method> indexedReadMethodRef;
   46       private Reference<Method> indexedWriteMethodRef;
   47   
   48       private String indexedReadMethodName;
   49       private String indexedWriteMethodName;
   50   
   51       /**
   52        * This constructor constructs an IndexedPropertyDescriptor for a property
   53        * that follows the standard Java conventions by having getFoo and setFoo
   54        * accessor methods, for both indexed access and array access.
   55        * <p>
   56        * Thus if the argument name is "fred", it will assume that there
   57        * is an indexed reader method "getFred", a non-indexed (array) reader
   58        * method also called "getFred", an indexed writer method "setFred",
   59        * and finally a non-indexed writer method "setFred".
   60        *
   61        * @param propertyName The programmatic name of the property.
   62        * @param beanClass The Class object for the target bean.
   63        * @exception IntrospectionException if an exception occurs during
   64        *              introspection.
   65        */
   66       public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)
   67                   throws IntrospectionException {
   68           this(propertyName, beanClass,
   69                Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),
   70                Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName),
   71                Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),
   72                Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
   73       }
   74   
   75       /**
   76        * This constructor takes the name of a simple property, and method
   77        * names for reading and writing the property, both indexed
   78        * and non-indexed.
   79        *
   80        * @param propertyName The programmatic name of the property.
   81        * @param beanClass  The Class object for the target bean.
   82        * @param readMethodName The name of the method used for reading the property
   83        *           values as an array.  May be null if the property is write-only
   84        *           or must be indexed.
   85        * @param writeMethodName The name of the method used for writing the property
   86        *           values as an array.  May be null if the property is read-only
   87        *           or must be indexed.
   88        * @param indexedReadMethodName The name of the method used for reading
   89        *          an indexed property value.
   90        *          May be null if the property is write-only.
   91        * @param indexedWriteMethodName The name of the method used for writing
   92        *          an indexed property value.
   93        *          May be null if the property is read-only.
   94        * @exception IntrospectionException if an exception occurs during
   95        *              introspection.
   96        */
   97       public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,
   98                   String readMethodName, String writeMethodName,
   99                   String indexedReadMethodName, String indexedWriteMethodName)
  100                   throws IntrospectionException {
  101           super(propertyName, beanClass, readMethodName, writeMethodName);
  102   
  103           this.indexedReadMethodName = indexedReadMethodName;
  104           if (indexedReadMethodName != null && getIndexedReadMethod() == null) {
  105               throw new IntrospectionException("Method not found: " + indexedReadMethodName);
  106           }
  107   
  108           this.indexedWriteMethodName = indexedWriteMethodName;
  109           if (indexedWriteMethodName != null && getIndexedWriteMethod() == null) {
  110               throw new IntrospectionException("Method not found: " + indexedWriteMethodName);
  111           }
  112           // Implemented only for type checking.
  113           findIndexedPropertyType(getIndexedReadMethod(), getIndexedWriteMethod());
  114       }
  115   
  116       /**
  117        * This constructor takes the name of a simple property, and Method
  118        * objects for reading and writing the property.
  119        *
  120        * @param propertyName The programmatic name of the pro
  121   perty.
  122        * @param readMethod The method used for reading the property values as an array.
  123        *          May be null if the property is write-only or must be indexed.
  124        * @param writeMethod The method used for writing the property values as an array.
  125        *          May be null if the property is read-only or must be indexed.
  126        * @param indexedReadMethod The method used for reading an indexed property value.
  127        *          May be null if the property is write-only.
  128        * @param indexedWriteMethod The method used for writing an indexed property value.
  129        *          May be null if the property is read-only.
  130        * @exception IntrospectionException if an exception occurs during
  131        *              introspection.
  132        */
  133       public IndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod,
  134                                               Method indexedReadMethod, Method indexedWriteMethod)
  135                   throws IntrospectionException {
  136           super(propertyName, readMethod, writeMethod);
  137   
  138           setIndexedReadMethod0(indexedReadMethod);
  139           setIndexedWriteMethod0(indexedWriteMethod);
  140   
  141           // Type checking
  142           setIndexedPropertyType(findIndexedPropertyType(indexedReadMethod, indexedWriteMethod));
  143       }
  144   
  145       /**
  146        * Creates <code>PropertyDescriptor</code> for the specified bean
  147        * with the specified name and methods to read/write the property value.
  148        *
  149        * @param bean          the type of the target bean
  150        * @param base          the base name of the property (the rest of the method name)
  151        * @param read          the method used for reading the property value
  152        * @param write         the method used for writing the property value
  153        * @param readIndexed   the method used for reading an indexed property value
  154        * @param writeIndexed  the method used for writing an indexed property value
  155        * @exception IntrospectionException if an exception occurs during introspection
  156        *
  157        * @since 1.7
  158        */
  159       IndexedPropertyDescriptor(Class<?> bean, String base, Method read, Method write, Method readIndexed, Method writeIndexed) throws IntrospectionException {
  160           super(bean, base, read, write);
  161   
  162           setIndexedReadMethod0(readIndexed);
  163           setIndexedWriteMethod0(writeIndexed);
  164   
  165           // Type checking
  166           setIndexedPropertyType(findIndexedPropertyType(readIndexed, writeIndexed));
  167       }
  168   
  169       /**
  170        * Gets the method that should be used to read an indexed
  171        * property value.
  172        *
  173        * @return The method that should be used to read an indexed
  174        * property value.
  175        * May return null if the property isn't indexed or is write-only.
  176        */
  177       public synchronized Method getIndexedReadMethod() {
  178           Method indexedReadMethod = getIndexedReadMethod0();
  179           if (indexedReadMethod == null) {
  180               Class cls = getClass0();
  181               if (cls == null ||
  182                   (indexedReadMethodName == null && indexedReadMethodRef == null)) {
  183                   // the Indexed readMethod was explicitly set to null.
  184                   return null;
  185               }
  186               if (indexedReadMethodName == null) {
  187                   Class type = getIndexedPropertyType0();
  188                   if (type == boolean.class || type == null) {
  189                       indexedReadMethodName = Introspector.IS_PREFIX + getBaseName();
  190                   } else {
  191                       indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
  192                   }
  193               }
  194   
  195               Class[] args = { int.class };
  196   
  197               indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName,
  198                                                           1, args);
  199               if (indexedReadMethod == null) {
  200                   // no "is" method, so look for a "get" method.
  201                   indexedReadMethodName = Introspector.GET_PREFIX + getBaseName();
  202                   indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName,
  203                                                               1, args);
  204               }
  205               setIndexedReadMethod0(indexedReadMethod);
  206           }
  207           return indexedReadMethod;
  208       }
  209   
  210       /**
  211        * Sets the method that should be used to read an indexed property value.
  212        *
  213        * @param readMethod The new indexed read method.
  214        */
  215       public synchronized void setIndexedReadMethod(Method readMethod)
  216           throws IntrospectionException {
  217   
  218           // the indexed property type is set by the reader.
  219           setIndexedPropertyType(findIndexedPropertyType(readMethod,
  220                                                          getIndexedWriteMethod0()));
  221           setIndexedReadMethod0(readMethod);
  222       }
  223   
  224       private void setIndexedReadMethod0(Method readMethod) {
  225           if (readMethod == null) {
  226               indexedReadMethodName = null;
  227               indexedReadMethodRef = null;
  228               return;
  229           }
  230           setClass0(readMethod.getDeclaringClass());
  231   
  232           indexedReadMethodName = readMethod.getName();
  233           this.indexedReadMethodRef = getSoftReference(readMethod);
  234           setTransient(readMethod.getAnnotation(Transient.class));
  235       }
  236   
  237   
  238       /**
  239        * Gets the method that should be used to write an indexed property value.
  240        *
  241        * @return The method that should be used to write an indexed
  242        * property value.
  243        * May return null if the property isn't indexed or is read-only.
  244        */
  245       public synchronized Method getIndexedWriteMethod() {
  246           Method indexedWriteMethod = getIndexedWriteMethod0();
  247           if (indexedWriteMethod == null) {
  248               Class cls = getClass0();
  249               if (cls == null ||
  250                   (indexedWriteMethodName == null && indexedWriteMethodRef == null)) {
  251                   // the Indexed writeMethod was explicitly set to null.
  252                   return null;
  253               }
  254   
  255               // We need the indexed type to ensure that we get the correct method.
  256               // Cannot use the getIndexedPropertyType method since that could
  257               // result in an infinite loop.
  258               Class type = getIndexedPropertyType0();
  259               if (type == null) {
  260                   try {
  261                       type = findIndexedPropertyType(getIndexedReadMethod(), null);
  262                       setIndexedPropertyType(type);
  263                   } catch (IntrospectionException ex) {
  264                       // Set iprop type to be the classic type
  265                       Class propType = getPropertyType();
  266                       if (propType.isArray()) {
  267                           type = propType.getComponentType();
  268                       }
  269                   }
  270               }
  271   
  272               if (indexedWriteMethodName == null) {
  273                   indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName();
  274               }
  275               indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName,
  276                            2, (type == null) ? null : new Class[] { int.class, type });
  277               setIndexedWriteMethod0(indexedWriteMethod);
  278           }
  279           return indexedWriteMethod;
  280       }
  281   
  282       /**
  283        * Sets the method that should be used to write an indexed property value.
  284        *
  285        * @param writeMethod The new indexed write method.
  286        */
  287       public synchronized void setIndexedWriteMethod(Method writeMethod)
  288           throws IntrospectionException {
  289   
  290           // If the indexed property type has not been set, then set it.
  291           Class type = findIndexedPropertyType(getIndexedReadMethod(),
  292                                                writeMethod);
  293           setIndexedPropertyType(type);
  294           setIndexedWriteMethod0(writeMethod);
  295       }
  296   
  297       private void setIndexedWriteMethod0(Method writeMethod) {
  298           if (writeMethod == null) {
  299               indexedWriteMethodName = null;
  300               indexedWriteMethodRef = null;
  301               return;
  302           }
  303           setClass0(writeMethod.getDeclaringClass());
  304   
  305           indexedWriteMethodName = writeMethod.getName();
  306           this.indexedWriteMethodRef = getSoftReference(writeMethod);
  307           setTransient(writeMethod.getAnnotation(Transient.class));
  308       }
  309   
  310       /**
  311        * Gets the <code>Class</code> object of the indexed properties' type.
  312        * The returned <code>Class</code> may describe a primitive type such as <code>int</code>.
  313        *
  314        * @return The <code>Class</code> for the indexed properties' type; may return <code>null</code>
  315        *         if the type cannot be determined.
  316        */
  317       public synchronized Class<?> getIndexedPropertyType() {
  318           Class type = getIndexedPropertyType0();
  319           if (type == null) {
  320               try {
  321                   type = findIndexedPropertyType(getIndexedReadMethod(),
  322                                                  getIndexedWriteMethod());
  323                   setIndexedPropertyType(type);
  324               } catch (IntrospectionException ex) {
  325                   // fall
  326               }
  327           }
  328           return type;
  329       }
  330   
  331       // Private methods which set get/set the Reference objects
  332   
  333       private void setIndexedPropertyType(Class type) {
  334           this.indexedPropertyTypeRef = getWeakReference(type);
  335       }
  336   
  337       private Class getIndexedPropertyType0() {
  338           return (this.indexedPropertyTypeRef != null)
  339                   ? this.indexedPropertyTypeRef.get()
  340                   : null;
  341       }
  342   
  343       private Method getIndexedReadMethod0() {
  344           return (this.indexedReadMethodRef != null)
  345                   ? this.indexedReadMethodRef.get()
  346                   : null;
  347       }
  348   
  349       private Method getIndexedWriteMethod0() {
  350           return (this.indexedWriteMethodRef != null)
  351                   ? this.indexedWriteMethodRef.get()
  352                   : null;
  353       }
  354   
  355       private Class findIndexedPropertyType(Method indexedReadMethod,
  356                                             Method indexedWriteMethod)
  357           throws IntrospectionException {
  358           Class indexedPropertyType = null;
  359   
  360           if (indexedReadMethod != null) {
  361               Class params[] = getParameterTypes(getClass0(), indexedReadMethod);
  362               if (params.length != 1) {
  363                   throw new IntrospectionException("bad indexed read method arg count");
  364               }
  365               if (params[0] != Integer.TYPE) {
  366                   throw new IntrospectionException("non int index to indexed read method");
  367               }
  368               indexedPropertyType = getReturnType(getClass0(), indexedReadMethod);
  369               if (indexedPropertyType == Void.TYPE) {
  370                   throw new IntrospectionException("indexed read method returns void");
  371               }
  372           }
  373           if (indexedWriteMethod != null) {
  374               Class params[] = getParameterTypes(getClass0(), indexedWriteMethod);
  375               if (params.length != 2) {
  376                   throw new IntrospectionException("bad indexed write method arg count");
  377               }
  378               if (params[0] != Integer.TYPE) {
  379                   throw new IntrospectionException("non int index to indexed write method");
  380               }
  381               if (indexedPropertyType != null && indexedPropertyType != params[1]) {
  382                   throw new IntrospectionException(
  383                                                    "type mismatch between indexed read and indexed write methods: "
  384                                                    + getName());
  385               }
  386               indexedPropertyType = params[1];
  387           }
  388           Class propertyType = getPropertyType();
  389           if (propertyType != null && (!propertyType.isArray() ||
  390                                        propertyType.getComponentType() != indexedPropertyType)) {
  391               throw new IntrospectionException("type mismatch between indexed and non-indexed methods: "
  392                                                + getName());
  393           }
  394           return indexedPropertyType;
  395       }
  396   
  397       /**
  398        * Compares this <code>PropertyDescriptor</code> against the specified object.
  399        * Returns true if the objects are the same. Two <code>PropertyDescriptor</code>s
  400        * are the same if the read, write, property types, property editor and
  401        * flags  are equivalent.
  402        *
  403        * @since 1.4
  404        */
  405       public boolean equals(Object obj) {
  406           // Note: This would be identical to PropertyDescriptor but they don't
  407           // share the same fields.
  408           if (this == obj) {
  409               return true;
  410           }
  411   
  412           if (obj != null && obj instanceof IndexedPropertyDescriptor) {
  413               IndexedPropertyDescriptor other = (IndexedPropertyDescriptor)obj;
  414               Method otherIndexedReadMethod = other.getIndexedReadMethod();
  415               Method otherIndexedWriteMethod = other.getIndexedWriteMethod();
  416   
  417               if (!compareMethods(getIndexedReadMethod(), otherIndexedReadMethod)) {
  418                   return false;
  419               }
  420   
  421               if (!compareMethods(getIndexedWriteMethod(), otherIndexedWriteMethod)) {
  422                   return false;
  423               }
  424   
  425               if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
  426                   return false;
  427               }
  428               return super.equals(obj);
  429           }
  430           return false;
  431       }
  432   
  433       /**
  434        * Package-private constructor.
  435        * Merge two property descriptors.  Where they conflict, give the
  436        * second argument (y) priority over the first argumnnt (x).
  437        *
  438        * @param x  The first (lower priority) PropertyDescriptor
  439        * @param y  The second (higher priority) PropertyDescriptor
  440        */
  441   
  442       IndexedPropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
  443           super(x,y);
  444           if (x instanceof IndexedPropertyDescriptor) {
  445               IndexedPropertyDescriptor ix = (IndexedPropertyDescriptor)x;
  446               try {
  447                   Method xr = ix.getIndexedReadMethod();
  448                   if (xr != null) {
  449                       setIndexedReadMethod(xr);
  450                   }
  451   
  452                   Method xw = ix.getIndexedWriteMethod();
  453                   if (xw != null) {
  454                       setIndexedWriteMethod(xw);
  455                   }
  456               } catch (IntrospectionException ex) {
  457                   // Should not happen
  458                   throw new AssertionError(ex);
  459               }
  460           }
  461           if (y instanceof IndexedPropertyDescriptor) {
  462               IndexedPropertyDescriptor iy = (IndexedPropertyDescriptor)y;
  463               try {
  464                   Method yr = iy.getIndexedReadMethod();
  465                   if (yr != null && yr.getDeclaringClass() == getClass0()) {
  466                       setIndexedReadMethod(yr);
  467                   }
  468   
  469                   Method yw = iy.getIndexedWriteMethod();
  470                   if (yw != null && yw.getDeclaringClass() == getClass0()) {
  471                       setIndexedWriteMethod(yw);
  472                   }
  473               } catch (IntrospectionException ex) {
  474                   // Should not happen
  475                   throw new AssertionError(ex);
  476               }
  477           }
  478       }
  479   
  480       /*
  481        * Package-private dup constructor
  482        * This must isolate the new object from any changes to the old object.
  483        */
  484       IndexedPropertyDescriptor(IndexedPropertyDescriptor old) {
  485           super(old);
  486           indexedReadMethodRef = old.indexedReadMethodRef;
  487           indexedWriteMethodRef = old.indexedWriteMethodRef;
  488           indexedPropertyTypeRef = old.indexedPropertyTypeRef;
  489           indexedWriteMethodName = old.indexedWriteMethodName;
  490           indexedReadMethodName = old.indexedReadMethodName;
  491       }
  492   
  493       /**
  494        * Returns a hash code value for the object.
  495        * See {@link java.lang.Object#hashCode} for a complete description.
  496        *
  497        * @return a hash code value for this object.
  498        * @since 1.5
  499        */
  500       public int hashCode() {
  501           int result = super.hashCode();
  502   
  503           result = 37 * result + ((indexedWriteMethodName == null) ? 0 :
  504                                   indexedWriteMethodName.hashCode());
  505           result = 37 * result + ((indexedReadMethodName == null) ? 0 :
  506                                   indexedReadMethodName.hashCode());
  507           result = 37 * result + ((getIndexedPropertyType() == null) ? 0 :
  508                                   getIndexedPropertyType().hashCode());
  509   
  510           return result;
  511       }
  512   
  513       /*
  514       public String toString() {
  515           String message = super.toString();
  516   
  517           message += ", indexedType=";
  518           message += getIndexedPropertyType();
  519   
  520           message += ", indexedWriteMethod=";
  521           message += indexedWriteMethodName;
  522   
  523           message += ", indexedReadMethod=";
  524           message += indexedReadMethodName;
  525   
  526           return message;
  527       }
  528       */
  529   }

Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]