/*
 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java.beans;

import java.lang.ref.Reference;
import java.lang.reflect.Method;
import java.util.Map.Entry;

import com.sun.beans.introspect.PropertyInfo;

An IndexedPropertyDescriptor describes a property that acts like an array and has an indexed read and/or indexed write method to access specific elements of the array.

An indexed property may also provide simple non-indexed read and write methods. If these are present, they read and write arrays of the type returned by the indexed read method.

Since:1.1
/** * An IndexedPropertyDescriptor describes a property that acts like an * array and has an indexed read and/or indexed write method to access * specific elements of the array. * <p> * An indexed property may also provide simple non-indexed read and write * methods. If these are present, they read and write arrays of the type * returned by the indexed read method. * * @since 1.1 */
public class IndexedPropertyDescriptor extends PropertyDescriptor { private Reference<? extends Class<?>> indexedPropertyTypeRef; private final MethodRef indexedReadMethodRef = new MethodRef(); private final MethodRef indexedWriteMethodRef = new MethodRef(); private String indexedReadMethodName; private String indexedWriteMethodName;
This constructor constructs an IndexedPropertyDescriptor for a property that follows the standard Java conventions by having getFoo and setFoo accessor methods, for both indexed access and array access.

Thus if the argument name is "fred", it will assume that there is an indexed reader method "getFred", a non-indexed (array) reader method also called "getFred", an indexed writer method "setFred", and finally a non-indexed writer method "setFred".

Params:
  • propertyName – The programmatic name of the property.
  • beanClass – The Class object for the target bean.
Throws:
/** * This constructor constructs an IndexedPropertyDescriptor for a property * that follows the standard Java conventions by having getFoo and setFoo * accessor methods, for both indexed access and array access. * <p> * Thus if the argument name is "fred", it will assume that there * is an indexed reader method "getFred", a non-indexed (array) reader * method also called "getFred", an indexed writer method "setFred", * and finally a non-indexed writer method "setFred". * * @param propertyName The programmatic name of the property. * @param beanClass The Class object for the target bean. * @exception IntrospectionException if an exception occurs during * introspection. */
public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass) throws IntrospectionException { this(propertyName, beanClass, Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName), Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName), Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName), Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName)); }
This constructor takes the name of a simple property, and method names for reading and writing the property, both indexed and non-indexed.
Params:
  • propertyName – The programmatic name of the property.
  • beanClass – The Class object for the target bean.
  • readMethodName – The name of the method used for reading the property values as an array. May be null if the property is write-only or must be indexed.
  • writeMethodName – The name of the method used for writing the property values as an array. May be null if the property is read-only or must be indexed.
  • indexedReadMethodName – The name of the method used for reading an indexed property value. May be null if the property is write-only.
  • indexedWriteMethodName – The name of the method used for writing an indexed property value. May be null if the property is read-only.
Throws:
/** * This constructor takes the name of a simple property, and method * names for reading and writing the property, both indexed * and non-indexed. * * @param propertyName The programmatic name of the property. * @param beanClass The Class object for the target bean. * @param readMethodName The name of the method used for reading the property * values as an array. May be null if the property is write-only * or must be indexed. * @param writeMethodName The name of the method used for writing the property * values as an array. May be null if the property is read-only * or must be indexed. * @param indexedReadMethodName The name of the method used for reading * an indexed property value. * May be null if the property is write-only. * @param indexedWriteMethodName The name of the method used for writing * an indexed property value. * May be null if the property is read-only. * @exception IntrospectionException if an exception occurs during * introspection. */
public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass, String readMethodName, String writeMethodName, String indexedReadMethodName, String indexedWriteMethodName) throws IntrospectionException { super(propertyName, beanClass, readMethodName, writeMethodName); this.indexedReadMethodName = indexedReadMethodName; if (indexedReadMethodName != null && getIndexedReadMethod() == null) { throw new IntrospectionException("Method not found: " + indexedReadMethodName); } this.indexedWriteMethodName = indexedWriteMethodName; if (indexedWriteMethodName != null && getIndexedWriteMethod() == null) { throw new IntrospectionException("Method not found: " + indexedWriteMethodName); } // Implemented only for type checking. findIndexedPropertyType(getIndexedReadMethod(), getIndexedWriteMethod()); }
This constructor takes the name of a simple property, and Method objects for reading and writing the property.
Params:
  • propertyName – The programmatic name of the property.
  • readMethod – The method used for reading the property values as an array. May be null if the property is write-only or must be indexed.
  • writeMethod – The method used for writing the property values as an array. May be null if the property is read-only or must be indexed.
  • indexedReadMethod – The method used for reading an indexed property value. May be null if the property is write-only.
  • indexedWriteMethod – The method used for writing an indexed property value. May be null if the property is read-only.
Throws:
/** * This constructor takes the name of a simple property, and Method * objects for reading and writing the property. * * @param propertyName The programmatic name of the property. * @param readMethod The method used for reading the property values as an array. * May be null if the property is write-only or must be indexed. * @param writeMethod The method used for writing the property values as an array. * May be null if the property is read-only or must be indexed. * @param indexedReadMethod The method used for reading an indexed property value. * May be null if the property is write-only. * @param indexedWriteMethod The method used for writing an indexed property value. * May be null if the property is read-only. * @exception IntrospectionException if an exception occurs during * introspection. */
public IndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { super(propertyName, readMethod, writeMethod); setIndexedReadMethod0(indexedReadMethod); setIndexedWriteMethod0(indexedWriteMethod); // Type checking setIndexedPropertyType(findIndexedPropertyType(indexedReadMethod, indexedWriteMethod)); }
Creates IndexedPropertyDescriptor from the specified property info.
Params:
  • entry – the key-value pair, where the key is the base name of the property (the rest of the method name) and the value is the automatically generated property info
  • bound – the flag indicating whether it is possible to treat this property as a bound property
Since:9
/** * Creates {@code IndexedPropertyDescriptor} from the specified property info. * * @param entry the key-value pair, * where the {@code key} is the base name of the property (the rest of the method name) * and the {@code value} is the automatically generated property info * @param bound the flag indicating whether it is possible to treat this property as a bound property * * @since 9 */
IndexedPropertyDescriptor(Entry<String,PropertyInfo> entry, boolean bound) { super(entry, bound); PropertyInfo info = entry.getValue().getIndexed(); setIndexedReadMethod0(info.getReadMethod()); setIndexedWriteMethod0(info.getWriteMethod()); setIndexedPropertyType(info.getPropertyType()); }
Gets the method that should be used to read an indexed property value.
Returns:The method that should be used to read an indexed property value. May return null if the property isn't indexed or is write-only.
/** * Gets the method that should be used to read an indexed * property value. * * @return The method that should be used to read an indexed * property value. * May return null if the property isn't indexed or is write-only. */
public synchronized Method getIndexedReadMethod() { Method indexedReadMethod = this.indexedReadMethodRef.get(); if (indexedReadMethod == null) { Class<?> cls = getClass0(); if (cls == null || (indexedReadMethodName == null && !this.indexedReadMethodRef.isSet())) { // the Indexed readMethod was explicitly set to null. return null; } String nextMethodName = Introspector.GET_PREFIX + getBaseName(); if (indexedReadMethodName == null) { Class<?> type = getIndexedPropertyType0(); if (type == boolean.class || type == null) { indexedReadMethodName = Introspector.IS_PREFIX + getBaseName(); } else { indexedReadMethodName = nextMethodName; } } Class<?>[] args = { int.class }; indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args); if ((indexedReadMethod == null) && !indexedReadMethodName.equals(nextMethodName)) { // no "is" method, so look for a "get" method. indexedReadMethodName = nextMethodName; indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args); } setIndexedReadMethod0(indexedReadMethod); } return indexedReadMethod; }
Sets the method that should be used to read an indexed property value.
Params:
  • readMethod – The new indexed read method.
Throws:
Since:1.2
/** * Sets the method that should be used to read an indexed property value. * * @param readMethod The new indexed read method. * @throws IntrospectionException if an exception occurs during * introspection. * * @since 1.2 */
public synchronized void setIndexedReadMethod(Method readMethod) throws IntrospectionException { // the indexed property type is set by the reader. setIndexedPropertyType(findIndexedPropertyType(readMethod, this.indexedWriteMethodRef.get())); setIndexedReadMethod0(readMethod); } private void setIndexedReadMethod0(Method readMethod) { this.indexedReadMethodRef.set(readMethod); if (readMethod == null) { indexedReadMethodName = null; return; } setClass0(readMethod.getDeclaringClass()); indexedReadMethodName = readMethod.getName(); setTransient(readMethod.getAnnotation(Transient.class)); }
Gets the method that should be used to write an indexed property value.
Returns:The method that should be used to write an indexed property value. May return null if the property isn't indexed or is read-only.
/** * Gets the method that should be used to write an indexed property value. * * @return The method that should be used to write an indexed * property value. * May return null if the property isn't indexed or is read-only. */
public synchronized Method getIndexedWriteMethod() { Method indexedWriteMethod = this.indexedWriteMethodRef.get(); if (indexedWriteMethod == null) { Class<?> cls = getClass0(); if (cls == null || (indexedWriteMethodName == null && !this.indexedWriteMethodRef.isSet())) { // the Indexed writeMethod was explicitly set to null. return null; } // We need the indexed type to ensure that we get the correct method. // Cannot use the getIndexedPropertyType method since that could // result in an infinite loop. Class<?> type = getIndexedPropertyType0(); if (type == null) { try { type = findIndexedPropertyType(getIndexedReadMethod(), null); setIndexedPropertyType(type); } catch (IntrospectionException ex) { // Set iprop type to be the classic type Class<?> propType = getPropertyType(); if (propType.isArray()) { type = propType.getComponentType(); } } } if (indexedWriteMethodName == null) { indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName(); } Class<?>[] args = (type == null) ? null : new Class<?>[] { int.class, type }; indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName, 2, args); if (indexedWriteMethod != null) { if (!indexedWriteMethod.getReturnType().equals(void.class)) { indexedWriteMethod = null; } } setIndexedWriteMethod0(indexedWriteMethod); } return indexedWriteMethod; }
Sets the method that should be used to write an indexed property value.
Params:
  • writeMethod – The new indexed write method.
Throws:
Since:1.2
/** * Sets the method that should be used to write an indexed property value. * * @param writeMethod The new indexed write method. * @throws IntrospectionException if an exception occurs during * introspection. * * @since 1.2 */
public synchronized void setIndexedWriteMethod(Method writeMethod) throws IntrospectionException { // If the indexed property type has not been set, then set it. Class<?> type = findIndexedPropertyType(getIndexedReadMethod(), writeMethod); setIndexedPropertyType(type); setIndexedWriteMethod0(writeMethod); } private void setIndexedWriteMethod0(Method writeMethod) { this.indexedWriteMethodRef.set(writeMethod); if (writeMethod == null) { indexedWriteMethodName = null; return; } setClass0(writeMethod.getDeclaringClass()); indexedWriteMethodName = writeMethod.getName(); setTransient(writeMethod.getAnnotation(Transient.class)); }
Returns the Java type info for the indexed property. Note that the Class object may describe primitive Java types such as int. This type is returned by the indexed read method or is used as the parameter type of the indexed write method.
Returns:the Class object that represents the Java type info, or null if the type cannot be determined
/** * Returns the Java type info for the indexed property. * Note that the {@code Class} object may describe * primitive Java types such as {@code int}. * This type is returned by the indexed read method * or is used as the parameter type of the indexed write method. * * @return the {@code Class} object that represents the Java type info, * or {@code null} if the type cannot be determined */
public synchronized Class<?> getIndexedPropertyType() { Class<?> type = getIndexedPropertyType0(); if (type == null) { try { type = findIndexedPropertyType(getIndexedReadMethod(), getIndexedWriteMethod()); setIndexedPropertyType(type); } catch (IntrospectionException ex) { // fall } } return type; } // Private methods which set get/set the Reference objects private void setIndexedPropertyType(Class<?> type) { this.indexedPropertyTypeRef = getWeakReference(type); } private Class<?> getIndexedPropertyType0() { return (this.indexedPropertyTypeRef != null) ? this.indexedPropertyTypeRef.get() : null; } private Class<?> findIndexedPropertyType(Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { Class<?> indexedPropertyType = null; if (indexedReadMethod != null) { Class<?>[] params = getParameterTypes(getClass0(), indexedReadMethod); if (params.length != 1) { throw new IntrospectionException("bad indexed read method arg count"); } if (params[0] != Integer.TYPE) { throw new IntrospectionException("non int index to indexed read method"); } indexedPropertyType = getReturnType(getClass0(), indexedReadMethod); if (indexedPropertyType == Void.TYPE) { throw new IntrospectionException("indexed read method returns void"); } } if (indexedWriteMethod != null) { Class<?>[] params = getParameterTypes(getClass0(), indexedWriteMethod); if (params.length != 2) { throw new IntrospectionException("bad indexed write method arg count"); } if (params[0] != Integer.TYPE) { throw new IntrospectionException("non int index to indexed write method"); } if (indexedPropertyType == null || params[1].isAssignableFrom(indexedPropertyType)) { indexedPropertyType = params[1]; } else if (!indexedPropertyType.isAssignableFrom(params[1])) { throw new IntrospectionException( "type mismatch between indexed read and indexed write methods: " + getName()); } } Class<?> propertyType = getPropertyType(); if (propertyType != null && (!propertyType.isArray() || propertyType.getComponentType() != indexedPropertyType)) { throw new IntrospectionException("type mismatch between indexed and non-indexed methods: " + getName()); } return indexedPropertyType; }
Compares this PropertyDescriptor against the specified object. Returns true if the objects are the same. Two PropertyDescriptors are the same if the read, write, property types, property editor and flags are equivalent.
Since:1.4
/** * Compares this {@code PropertyDescriptor} against the specified object. * Returns true if the objects are the same. Two {@code PropertyDescriptor}s * are the same if the read, write, property types, property editor and * flags are equivalent. * * @since 1.4 */
public boolean equals(Object obj) { // Note: This would be identical to PropertyDescriptor but they don't // share the same fields. if (this == obj) { return true; } if (obj != null && obj instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor other = (IndexedPropertyDescriptor)obj; Method otherIndexedReadMethod = other.getIndexedReadMethod(); Method otherIndexedWriteMethod = other.getIndexedWriteMethod(); if (!compareMethods(getIndexedReadMethod(), otherIndexedReadMethod)) { return false; } if (!compareMethods(getIndexedWriteMethod(), otherIndexedWriteMethod)) { return false; } if (getIndexedPropertyType() != other.getIndexedPropertyType()) { return false; } return super.equals(obj); } return false; }
Package-private constructor. Merge two property descriptors. Where they conflict, give the second argument (y) priority over the first argument (x).
Params:
  • x – The first (lower priority) PropertyDescriptor
  • y – The second (higher priority) PropertyDescriptor
/** * Package-private constructor. * Merge two property descriptors. Where they conflict, give the * second argument (y) priority over the first argument (x). * * @param x The first (lower priority) PropertyDescriptor * @param y The second (higher priority) PropertyDescriptor */
IndexedPropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) { super(x,y); Method tr = null; Method tw = null; if (x instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor ix = (IndexedPropertyDescriptor) x; tr = ix.getIndexedReadMethod(); tw = ix.getIndexedWriteMethod(); } if (y instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor iy = (IndexedPropertyDescriptor) y; Method yr = iy.getIndexedReadMethod(); if (isAssignable(tr, yr)) { tr = yr; } Method yw = iy.getIndexedWriteMethod(); if (isAssignable(tw, yw)) { tw = yw; } } try { if(tr != null) { setIndexedReadMethod(tr); } if(tw != null) { setIndexedWriteMethod(tw); } } catch(IntrospectionException ex) { // Should not happen throw new AssertionError(ex); } } /* * Package-private dup constructor * This must isolate the new object from any changes to the old object. */ IndexedPropertyDescriptor(IndexedPropertyDescriptor old) { super(old); this.indexedReadMethodRef.set(old.indexedReadMethodRef.get()); this.indexedWriteMethodRef.set(old.indexedWriteMethodRef.get()); indexedPropertyTypeRef = old.indexedPropertyTypeRef; indexedWriteMethodName = old.indexedWriteMethodName; indexedReadMethodName = old.indexedReadMethodName; } void updateGenericsFor(Class<?> type) { super.updateGenericsFor(type); try { setIndexedPropertyType(findIndexedPropertyType(this.indexedReadMethodRef.get(), this.indexedWriteMethodRef.get())); } catch (IntrospectionException exception) { setIndexedPropertyType(null); } }
Returns a hash code value for the object. See Object.hashCode for a complete description.
Returns:a hash code value for this object.
Since:1.5
/** * Returns a hash code value for the object. * See {@link java.lang.Object#hashCode} for a complete description. * * @return a hash code value for this object. * @since 1.5 */
public int hashCode() { int result = super.hashCode(); result = 37 * result + ((indexedWriteMethodName == null) ? 0 : indexedWriteMethodName.hashCode()); result = 37 * result + ((indexedReadMethodName == null) ? 0 : indexedReadMethodName.hashCode()); result = 37 * result + ((getIndexedPropertyType() == null) ? 0 : getIndexedPropertyType().hashCode()); return result; } void appendTo(StringBuilder sb) { super.appendTo(sb); appendTo(sb, "indexedPropertyType", this.indexedPropertyTypeRef); appendTo(sb, "indexedReadMethod", this.indexedReadMethodRef.get()); appendTo(sb, "indexedWriteMethod", this.indexedWriteMethodRef.get()); } }