Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/beans/IndexedPropertyDescriptor.java
38829 views
/*1* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.beans;2627import java.lang.ref.Reference;28import java.lang.reflect.Method;2930/**31* An IndexedPropertyDescriptor describes a property that acts like an32* array and has an indexed read and/or indexed write method to access33* specific elements of the array.34* <p>35* An indexed property may also provide simple non-indexed read and write36* methods. If these are present, they read and write arrays of the type37* returned by the indexed read method.38*/3940public class IndexedPropertyDescriptor extends PropertyDescriptor {4142private Reference<? extends Class<?>> indexedPropertyTypeRef;43private final MethodRef indexedReadMethodRef = new MethodRef();44private final MethodRef indexedWriteMethodRef = new MethodRef();4546private String indexedReadMethodName;47private String indexedWriteMethodName;4849/**50* This constructor constructs an IndexedPropertyDescriptor for a property51* that follows the standard Java conventions by having getFoo and setFoo52* accessor methods, for both indexed access and array access.53* <p>54* Thus if the argument name is "fred", it will assume that there55* is an indexed reader method "getFred", a non-indexed (array) reader56* method also called "getFred", an indexed writer method "setFred",57* and finally a non-indexed writer method "setFred".58*59* @param propertyName The programmatic name of the property.60* @param beanClass The Class object for the target bean.61* @exception IntrospectionException if an exception occurs during62* introspection.63*/64public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass)65throws IntrospectionException {66this(propertyName, beanClass,67Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),68Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName),69Introspector.GET_PREFIX + NameGenerator.capitalize(propertyName),70Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));71}7273/**74* This constructor takes the name of a simple property, and method75* names for reading and writing the property, both indexed76* and non-indexed.77*78* @param propertyName The programmatic name of the property.79* @param beanClass The Class object for the target bean.80* @param readMethodName The name of the method used for reading the property81* values as an array. May be null if the property is write-only82* or must be indexed.83* @param writeMethodName The name of the method used for writing the property84* values as an array. May be null if the property is read-only85* or must be indexed.86* @param indexedReadMethodName The name of the method used for reading87* an indexed property value.88* May be null if the property is write-only.89* @param indexedWriteMethodName The name of the method used for writing90* an indexed property value.91* May be null if the property is read-only.92* @exception IntrospectionException if an exception occurs during93* introspection.94*/95public IndexedPropertyDescriptor(String propertyName, Class<?> beanClass,96String readMethodName, String writeMethodName,97String indexedReadMethodName, String indexedWriteMethodName)98throws IntrospectionException {99super(propertyName, beanClass, readMethodName, writeMethodName);100101this.indexedReadMethodName = indexedReadMethodName;102if (indexedReadMethodName != null && getIndexedReadMethod() == null) {103throw new IntrospectionException("Method not found: " + indexedReadMethodName);104}105106this.indexedWriteMethodName = indexedWriteMethodName;107if (indexedWriteMethodName != null && getIndexedWriteMethod() == null) {108throw new IntrospectionException("Method not found: " + indexedWriteMethodName);109}110// Implemented only for type checking.111findIndexedPropertyType(getIndexedReadMethod(), getIndexedWriteMethod());112}113114/**115* This constructor takes the name of a simple property, and Method116* objects for reading and writing the property.117*118* @param propertyName The programmatic name of the property.119* @param readMethod The method used for reading the property values as an array.120* May be null if the property is write-only or must be indexed.121* @param writeMethod The method used for writing the property values as an array.122* May be null if the property is read-only or must be indexed.123* @param indexedReadMethod The method used for reading an indexed property value.124* May be null if the property is write-only.125* @param indexedWriteMethod The method used for writing an indexed property value.126* May be null if the property is read-only.127* @exception IntrospectionException if an exception occurs during128* introspection.129*/130public IndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod,131Method indexedReadMethod, Method indexedWriteMethod)132throws IntrospectionException {133super(propertyName, readMethod, writeMethod);134135setIndexedReadMethod0(indexedReadMethod);136setIndexedWriteMethod0(indexedWriteMethod);137138// Type checking139setIndexedPropertyType(findIndexedPropertyType(indexedReadMethod, indexedWriteMethod));140}141142/**143* Creates <code>PropertyDescriptor</code> for the specified bean144* with the specified name and methods to read/write the property value.145*146* @param bean the type of the target bean147* @param base the base name of the property (the rest of the method name)148* @param read the method used for reading the property value149* @param write the method used for writing the property value150* @param readIndexed the method used for reading an indexed property value151* @param writeIndexed the method used for writing an indexed property value152* @exception IntrospectionException if an exception occurs during introspection153*154* @since 1.7155*/156IndexedPropertyDescriptor(Class<?> bean, String base, Method read, Method write, Method readIndexed, Method writeIndexed) throws IntrospectionException {157super(bean, base, read, write);158159setIndexedReadMethod0(readIndexed);160setIndexedWriteMethod0(writeIndexed);161162// Type checking163setIndexedPropertyType(findIndexedPropertyType(readIndexed, writeIndexed));164}165166/**167* Gets the method that should be used to read an indexed168* property value.169*170* @return The method that should be used to read an indexed171* property value.172* May return null if the property isn't indexed or is write-only.173*/174public synchronized Method getIndexedReadMethod() {175Method indexedReadMethod = this.indexedReadMethodRef.get();176if (indexedReadMethod == null) {177Class<?> cls = getClass0();178if (cls == null ||179(indexedReadMethodName == null && !this.indexedReadMethodRef.isSet())) {180// the Indexed readMethod was explicitly set to null.181return null;182}183String nextMethodName = Introspector.GET_PREFIX + getBaseName();184if (indexedReadMethodName == null) {185Class<?> type = getIndexedPropertyType0();186if (type == boolean.class || type == null) {187indexedReadMethodName = Introspector.IS_PREFIX + getBaseName();188} else {189indexedReadMethodName = nextMethodName;190}191}192193Class<?>[] args = { int.class };194indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);195if ((indexedReadMethod == null) && !indexedReadMethodName.equals(nextMethodName)) {196// no "is" method, so look for a "get" method.197indexedReadMethodName = nextMethodName;198indexedReadMethod = Introspector.findMethod(cls, indexedReadMethodName, 1, args);199}200setIndexedReadMethod0(indexedReadMethod);201}202return indexedReadMethod;203}204205/**206* Sets the method that should be used to read an indexed property value.207*208* @param readMethod The new indexed read method.209* @throws IntrospectionException if an exception occurs during210* introspection.211*/212public synchronized void setIndexedReadMethod(Method readMethod)213throws IntrospectionException {214215// the indexed property type is set by the reader.216setIndexedPropertyType(findIndexedPropertyType(readMethod,217this.indexedWriteMethodRef.get()));218setIndexedReadMethod0(readMethod);219}220221private void setIndexedReadMethod0(Method readMethod) {222this.indexedReadMethodRef.set(readMethod);223if (readMethod == null) {224indexedReadMethodName = null;225return;226}227setClass0(readMethod.getDeclaringClass());228229indexedReadMethodName = readMethod.getName();230setTransient(readMethod.getAnnotation(Transient.class));231}232233234/**235* Gets the method that should be used to write an indexed property value.236*237* @return The method that should be used to write an indexed238* property value.239* May return null if the property isn't indexed or is read-only.240*/241public synchronized Method getIndexedWriteMethod() {242Method indexedWriteMethod = this.indexedWriteMethodRef.get();243if (indexedWriteMethod == null) {244Class<?> cls = getClass0();245if (cls == null ||246(indexedWriteMethodName == null && !this.indexedWriteMethodRef.isSet())) {247// the Indexed writeMethod was explicitly set to null.248return null;249}250251// We need the indexed type to ensure that we get the correct method.252// Cannot use the getIndexedPropertyType method since that could253// result in an infinite loop.254Class<?> type = getIndexedPropertyType0();255if (type == null) {256try {257type = findIndexedPropertyType(getIndexedReadMethod(), null);258setIndexedPropertyType(type);259} catch (IntrospectionException ex) {260// Set iprop type to be the classic type261Class<?> propType = getPropertyType();262if (propType.isArray()) {263type = propType.getComponentType();264}265}266}267268if (indexedWriteMethodName == null) {269indexedWriteMethodName = Introspector.SET_PREFIX + getBaseName();270}271272Class<?>[] args = (type == null) ? null : new Class<?>[] { int.class, type };273indexedWriteMethod = Introspector.findMethod(cls, indexedWriteMethodName, 2, args);274if (indexedWriteMethod != null) {275if (!indexedWriteMethod.getReturnType().equals(void.class)) {276indexedWriteMethod = null;277}278}279setIndexedWriteMethod0(indexedWriteMethod);280}281return indexedWriteMethod;282}283284/**285* Sets the method that should be used to write an indexed property value.286*287* @param writeMethod The new indexed write method.288* @throws IntrospectionException if an exception occurs during289* introspection.290*/291public synchronized void setIndexedWriteMethod(Method writeMethod)292throws IntrospectionException {293294// If the indexed property type has not been set, then set it.295Class<?> type = findIndexedPropertyType(getIndexedReadMethod(),296writeMethod);297setIndexedPropertyType(type);298setIndexedWriteMethod0(writeMethod);299}300301private void setIndexedWriteMethod0(Method writeMethod) {302this.indexedWriteMethodRef.set(writeMethod);303if (writeMethod == null) {304indexedWriteMethodName = null;305return;306}307setClass0(writeMethod.getDeclaringClass());308309indexedWriteMethodName = writeMethod.getName();310setTransient(writeMethod.getAnnotation(Transient.class));311}312313/**314* Returns the Java type info for the indexed property.315* Note that the {@code Class} object may describe316* primitive Java types such as {@code int}.317* This type is returned by the indexed read method318* or is used as the parameter type of the indexed write method.319*320* @return the {@code Class} object that represents the Java type info,321* or {@code null} if the type cannot be determined322*/323public synchronized Class<?> getIndexedPropertyType() {324Class<?> type = getIndexedPropertyType0();325if (type == null) {326try {327type = findIndexedPropertyType(getIndexedReadMethod(),328getIndexedWriteMethod());329setIndexedPropertyType(type);330} catch (IntrospectionException ex) {331// fall332}333}334return type;335}336337// Private methods which set get/set the Reference objects338339private void setIndexedPropertyType(Class<?> type) {340this.indexedPropertyTypeRef = getWeakReference(type);341}342343private Class<?> getIndexedPropertyType0() {344return (this.indexedPropertyTypeRef != null)345? this.indexedPropertyTypeRef.get()346: null;347}348349private Class<?> findIndexedPropertyType(Method indexedReadMethod,350Method indexedWriteMethod)351throws IntrospectionException {352Class<?> indexedPropertyType = null;353354if (indexedReadMethod != null) {355Class params[] = getParameterTypes(getClass0(), indexedReadMethod);356if (params.length != 1) {357throw new IntrospectionException("bad indexed read method arg count");358}359if (params[0] != Integer.TYPE) {360throw new IntrospectionException("non int index to indexed read method");361}362indexedPropertyType = getReturnType(getClass0(), indexedReadMethod);363if (indexedPropertyType == Void.TYPE) {364throw new IntrospectionException("indexed read method returns void");365}366}367if (indexedWriteMethod != null) {368Class params[] = getParameterTypes(getClass0(), indexedWriteMethod);369if (params.length != 2) {370throw new IntrospectionException("bad indexed write method arg count");371}372if (params[0] != Integer.TYPE) {373throw new IntrospectionException("non int index to indexed write method");374}375if (indexedPropertyType == null || params[1].isAssignableFrom(indexedPropertyType)) {376indexedPropertyType = params[1];377} else if (!indexedPropertyType.isAssignableFrom(params[1])) {378throw new IntrospectionException(379"type mismatch between indexed read and indexed write methods: "380+ getName());381}382}383Class<?> propertyType = getPropertyType();384if (propertyType != null && (!propertyType.isArray() ||385propertyType.getComponentType() != indexedPropertyType)) {386throw new IntrospectionException("type mismatch between indexed and non-indexed methods: "387+ getName());388}389return indexedPropertyType;390}391392/**393* Compares this <code>PropertyDescriptor</code> against the specified object.394* Returns true if the objects are the same. Two <code>PropertyDescriptor</code>s395* are the same if the read, write, property types, property editor and396* flags are equivalent.397*398* @since 1.4399*/400public boolean equals(Object obj) {401// Note: This would be identical to PropertyDescriptor but they don't402// share the same fields.403if (this == obj) {404return true;405}406407if (obj != null && obj instanceof IndexedPropertyDescriptor) {408IndexedPropertyDescriptor other = (IndexedPropertyDescriptor)obj;409Method otherIndexedReadMethod = other.getIndexedReadMethod();410Method otherIndexedWriteMethod = other.getIndexedWriteMethod();411412if (!compareMethods(getIndexedReadMethod(), otherIndexedReadMethod)) {413return false;414}415416if (!compareMethods(getIndexedWriteMethod(), otherIndexedWriteMethod)) {417return false;418}419420if (getIndexedPropertyType() != other.getIndexedPropertyType()) {421return false;422}423return super.equals(obj);424}425return false;426}427428/**429* Package-private constructor.430* Merge two property descriptors. Where they conflict, give the431* second argument (y) priority over the first argument (x).432*433* @param x The first (lower priority) PropertyDescriptor434* @param y The second (higher priority) PropertyDescriptor435*/436437IndexedPropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {438super(x,y);439Method tr = null;440Method tw = null;441442if (x instanceof IndexedPropertyDescriptor) {443IndexedPropertyDescriptor ix = (IndexedPropertyDescriptor) x;444tr = ix.getIndexedReadMethod();445tw = ix.getIndexedWriteMethod();446}447if (y instanceof IndexedPropertyDescriptor) {448IndexedPropertyDescriptor iy = (IndexedPropertyDescriptor) y;449Method yr = iy.getIndexedReadMethod();450if (isAssignable(tr, yr)) {451tr = yr;452}453454Method yw = iy.getIndexedWriteMethod();455if (isAssignable(tw, yw)) {456tw = yw;457}458}459460try {461if(tr != null) {462setIndexedReadMethod(tr);463}464if(tw != null) {465setIndexedWriteMethod(tw);466}467} catch(IntrospectionException ex) {468// Should not happen469throw new AssertionError(ex);470}471}472473/*474* Package-private dup constructor475* This must isolate the new object from any changes to the old object.476*/477IndexedPropertyDescriptor(IndexedPropertyDescriptor old) {478super(old);479this.indexedReadMethodRef.set(old.indexedReadMethodRef.get());480this.indexedWriteMethodRef.set(old.indexedWriteMethodRef.get());481indexedPropertyTypeRef = old.indexedPropertyTypeRef;482indexedWriteMethodName = old.indexedWriteMethodName;483indexedReadMethodName = old.indexedReadMethodName;484}485486void updateGenericsFor(Class<?> type) {487super.updateGenericsFor(type);488try {489setIndexedPropertyType(findIndexedPropertyType(this.indexedReadMethodRef.get(), this.indexedWriteMethodRef.get()));490}491catch (IntrospectionException exception) {492setIndexedPropertyType(null);493}494}495496/**497* Returns a hash code value for the object.498* See {@link java.lang.Object#hashCode} for a complete description.499*500* @return a hash code value for this object.501* @since 1.5502*/503public int hashCode() {504int result = super.hashCode();505506result = 37 * result + ((indexedWriteMethodName == null) ? 0 :507indexedWriteMethodName.hashCode());508result = 37 * result + ((indexedReadMethodName == null) ? 0 :509indexedReadMethodName.hashCode());510result = 37 * result + ((getIndexedPropertyType() == null) ? 0 :511getIndexedPropertyType().hashCode());512513return result;514}515516void appendTo(StringBuilder sb) {517super.appendTo(sb);518appendTo(sb, "indexedPropertyType", this.indexedPropertyTypeRef);519appendTo(sb, "indexedReadMethod", this.indexedReadMethodRef.get());520appendTo(sb, "indexedWriteMethod", this.indexedWriteMethodRef.get());521}522}523524525