001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.beans;
019:
020: import java.lang.reflect.Method;
021:
022: import org.apache.harmony.beans.BeansUtils;
023: import org.apache.harmony.beans.internal.nls.Messages;
024:
025: public class IndexedPropertyDescriptor extends PropertyDescriptor {
026:
027: private Class<?> indexedPropertyType;
028:
029: private Method indexedGetter;
030:
031: private Method indexedSetter;
032:
033: /**
034: * Constructs a new instance of <code>IndexedPropertyDescriptor</code>.
035: *
036: * @param propertyName
037: * the specified indexed property's name.
038: * @param beanClass
039: * the bean class
040: * @param getterName
041: * the name of the array getter
042: * @param setterName
043: * the name of the array setter
044: * @param indexedGetterName
045: * the name of the indexed getter.
046: * @param indexedSetterName
047: * the name of the indexed setter.
048: * @throws IntrospectionException
049: */
050: public IndexedPropertyDescriptor(String propertyName,
051: Class<?> beanClass, String getterName, String setterName,
052: String indexedGetterName, String indexedSetterName)
053: throws IntrospectionException {
054: super (propertyName, beanClass, getterName, setterName);
055: setIndexedByName(beanClass, indexedGetterName,
056: indexedSetterName);
057: }
058:
059: private void setIndexedByName(Class<?> beanClass,
060: String indexedGetterName, String indexedSetterName)
061: throws IntrospectionException {
062:
063: String theIndexedGetterName = indexedGetterName;
064: if (theIndexedGetterName == null) {
065: if (indexedSetterName != null) {
066: setIndexedWriteMethod(beanClass, indexedSetterName);
067: }
068: } else {
069: if (theIndexedGetterName.length() == 0) {
070: theIndexedGetterName = "get" + name; //$NON-NLS-1$
071: }
072: setIndexedReadMethod(beanClass, theIndexedGetterName);
073: if (indexedSetterName != null) {
074: setIndexedWriteMethod(beanClass, indexedSetterName,
075: indexedPropertyType);
076: }
077: }
078:
079: if (!isCompatible()) {
080: // beans.57=Property type is incompatible with the indexed property type
081: throw new IntrospectionException(Messages
082: .getString("beans.57")); //$NON-NLS-1$
083: }
084: }
085:
086: private boolean isCompatible() {
087: Class<?> propertyType = getPropertyType();
088:
089: if (propertyType == null) {
090: return true;
091: }
092: Class<?> componentTypeOfProperty = propertyType
093: .getComponentType();
094: if (componentTypeOfProperty == null) {
095: return false;
096: }
097: if (indexedPropertyType == null) {
098: return false;
099: }
100:
101: return componentTypeOfProperty.getName().equals(
102: indexedPropertyType.getName());
103: }
104:
105: /**
106: * Constructs a new instance of <code>IndexedPropertyDescriptor</code>.
107: *
108: * @param propertyName
109: * the specified indexed property's name.
110: * @param getter
111: * the array getter
112: * @param setter
113: * the array setter
114: * @param indexedGetter
115: * the indexed getter
116: * @param indexedSetter
117: * the indexed setter
118: * @throws IntrospectionException
119: */
120: public IndexedPropertyDescriptor(String propertyName,
121: Method getter, Method setter, Method indexedGetter,
122: Method indexedSetter) throws IntrospectionException {
123: super (propertyName, getter, setter);
124: if (indexedGetter != null) {
125: internalSetIndexedReadMethod(indexedGetter);
126: internalSetIndexedWriteMethod(indexedSetter, true);
127: } else {
128: internalSetIndexedWriteMethod(indexedSetter, true);
129: internalSetIndexedReadMethod(indexedGetter);
130: }
131:
132: if (!isCompatible()) {
133: // beans.57=Property type is incompatible with the indexed property type
134: throw new IntrospectionException(Messages
135: .getString("beans.57")); //$NON-NLS-1$
136: }
137: }
138:
139: /**
140: * Constructs a new instance of <code>IndexedPropertyDescriptor</code>.
141: *
142: * @param propertyName
143: * the specified indexed property's name.
144: * @param beanClass
145: * the bean class.
146: * @throws IntrospectionException
147: */
148: public IndexedPropertyDescriptor(String propertyName,
149: Class<?> beanClass) throws IntrospectionException {
150: super (propertyName, beanClass);
151: setIndexedByName(beanClass, "get" //$NON-NLS-1$
152: .concat(initialUpperCase(propertyName)), "set" //$NON-NLS-1$
153: .concat(initialUpperCase(propertyName)));
154: }
155:
156: /**
157: * Sets the indexed getter as the specified method.
158: *
159: * @param indexedGetter
160: * the specified indexed getter.
161: * @throws IntrospectionException
162: */
163: public void setIndexedReadMethod(Method indexedGetter)
164: throws IntrospectionException {
165: this .internalSetIndexedReadMethod(indexedGetter);
166: }
167:
168: /**
169: * Sets the indexed setter as the specified method.
170: *
171: * @param indexedSetter
172: * the specified indexed setter.
173: * @throws IntrospectionException
174: */
175: public void setIndexedWriteMethod(Method indexedSetter)
176: throws IntrospectionException {
177: this .internalSetIndexedWriteMethod(indexedSetter, false);
178: }
179:
180: /**
181: * Obtains the indexed setter.
182: *
183: * @return the indexed setter.
184: */
185: public Method getIndexedWriteMethod() {
186: return indexedSetter;
187: }
188:
189: /**
190: * Obtains the indexed getter.
191: *
192: * @return the indexed getter.
193: */
194: public Method getIndexedReadMethod() {
195: return indexedGetter;
196: }
197:
198: /**
199: * Determines if this <code>IndexedPropertyDescriptor</code> is equal to
200: * the specified object. Two <code>IndexedPropertyDescriptor</code> s are
201: * equal if the reader, indexed reader, writer, indexed writer, property
202: * types, indexed property type, property editor and flags are equal.
203: *
204: * @param obj
205: * @return true if this indexed property descriptor is equal to the
206: * specified object.
207: */
208: @Override
209: public boolean equals(Object obj) {
210: if (!(obj instanceof IndexedPropertyDescriptor)) {
211: return false;
212: }
213:
214: IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
215:
216: return (super .equals(other)
217: && (indexedPropertyType == null ? other.indexedPropertyType == null
218: : indexedPropertyType
219: .equals(other.indexedPropertyType))
220: && (indexedGetter == null ? other.indexedGetter == null
221: : indexedGetter.equals(other.indexedGetter)) && (indexedSetter == null ? other.indexedSetter == null
222: : indexedSetter.equals(other.indexedSetter)));
223: }
224:
225: /**
226: * HashCode of the IndexedPropertyDescriptor
227: */
228: @Override
229: public int hashCode() {
230: return super .hashCode()
231: + BeansUtils.getHashCode(indexedPropertyType)
232: + BeansUtils.getHashCode(indexedGetter)
233: + BeansUtils.getHashCode(indexedSetter);
234: }
235:
236: /**
237: * Obtains the Class object of the indexed property type.
238: *
239: * @return the Class object of the indexed property type.
240: */
241: public Class<?> getIndexedPropertyType() {
242: return indexedPropertyType;
243: }
244:
245: private void setIndexedReadMethod(Class<?> beanClass,
246: String indexedGetterName) throws IntrospectionException {
247: Method getter;
248: try {
249: getter = beanClass.getMethod(indexedGetterName,
250: new Class[] { Integer.TYPE });
251: } catch (NoSuchMethodException exception) {
252: // beans.58=No such indexed read method
253: throw new IntrospectionException(Messages
254: .getString("beans.58")); //$NON-NLS-1$
255: } catch (SecurityException exception) {
256: // beans.59=Security violation accessing indexed read method
257: throw new IntrospectionException(Messages
258: .getString("beans.59")); //$NON-NLS-1$
259: }
260: internalSetIndexedReadMethod(getter);
261: }
262:
263: private void internalSetIndexedReadMethod(Method indexGetter)
264: throws IntrospectionException {
265: // Clearing the indexed read method.
266: if (indexGetter == null) {
267: if (indexedSetter == null) {
268: if (getPropertyType() != null) {
269: // beans.5A=Indexed method is not compatible with non indexed method
270: throw new IntrospectionException(Messages
271: .getString("beans.5A")); //$NON-NLS-1$
272: }
273: indexedPropertyType = null;
274: }
275: this .indexedGetter = null;
276: return;
277: }
278: // Validate the indexed getter.
279: if ((indexGetter.getParameterTypes().length != 1)
280: || (indexGetter.getParameterTypes()[0] != Integer.TYPE)) {
281: // beans.5B=Indexed read method must take a single int argument
282: throw new IntrospectionException(Messages
283: .getString("beans.5B")); //$NON-NLS-1$
284: }
285: Class<?> indexedReadType = indexGetter.getReturnType();
286: if (indexedReadType == Void.TYPE) {
287: // beans.5B=Indexed read method must take a single int argument
288: throw new IntrospectionException(Messages
289: .getString("beans.5B")); //$NON-NLS-1$
290: } else if (indexedSetter != null
291: && indexGetter.getReturnType() != indexedSetter
292: .getParameterTypes()[1]) {
293: // beans.5A=Indexed read method is not compatible with indexed write method
294: throw new IntrospectionException(Messages
295: .getString("beans.5A")); //$NON-NLS-1$
296: }
297:
298: // Set the indexed property type if not already set, confirm validity if
299: // it is.
300: if (this .indexedGetter == null) {
301: indexedPropertyType = indexedReadType;
302: } else {
303: if (indexedPropertyType != indexedReadType) {
304: // beans.5A=Indexed read method is not compatible with indexed write method
305: throw new IntrospectionException(Messages
306: .getString("beans.5A")); //$NON-NLS-1$
307: }
308: }
309:
310: // Set the indexed getter
311: this .indexedGetter = indexGetter;
312: }
313:
314: private void setIndexedWriteMethod(Class<?> beanClass,
315: String indexedSetterName) throws IntrospectionException {
316: Method setter = null;
317: try {
318: setter = beanClass.getMethod(indexedSetterName,
319: new Class[] { Integer.TYPE,
320: getPropertyType().getComponentType() });
321: } catch (SecurityException e) {
322: // beans.5C=Security violation accessing indexed write method
323: throw new IntrospectionException(Messages
324: .getString("beans.5C")); //$NON-NLS-1$
325: } catch (NoSuchMethodException e) {
326: // beans.5D=No such indexed write method
327: throw new IntrospectionException(Messages
328: .getString("beans.5D")); //$NON-NLS-1$
329: }
330: internalSetIndexedWriteMethod(setter, true);
331: }
332:
333: private void setIndexedWriteMethod(Class<?> beanClass,
334: String indexedSetterName, Class<?> argType)
335: throws IntrospectionException {
336: try {
337: Method setter = beanClass.getMethod(indexedSetterName,
338: new Class[] { Integer.TYPE, argType });
339: internalSetIndexedWriteMethod(setter, true);
340: } catch (NoSuchMethodException exception) {
341: // beans.5D=No such indexed write method
342: throw new IntrospectionException(Messages
343: .getString("beans.5D")); //$NON-NLS-1$
344: } catch (SecurityException exception) {
345: // beans.5C=Security violation accessing indexed write method
346: throw new IntrospectionException(Messages
347: .getString("beans.5C")); //$NON-NLS-1$
348: }
349: }
350:
351: private void internalSetIndexedWriteMethod(Method indexSetter,
352: boolean initialize) throws IntrospectionException {
353: // Clearing the indexed write method.
354: if (indexSetter == null) {
355: if (indexedGetter == null) {
356: if (getPropertyType() != null) {
357: // beans.5E=Indexed method is not compatible with non indexed method
358: throw new IntrospectionException(Messages
359: .getString("beans.5E")); //$NON-NLS-1$
360: }
361: indexedPropertyType = null;
362: }
363: this .indexedSetter = null;
364: return;
365: }
366:
367: // Validate the indexed write method.
368: Class[] indexedSetterArgs = indexSetter.getParameterTypes();
369: if (indexedSetterArgs.length != 2) {
370: // beans.5F=Indexed write method must take two arguments
371: throw new IntrospectionException(Messages
372: .getString("beans.5F")); //$NON-NLS-1$
373: }
374: if (indexedSetterArgs[0] != Integer.TYPE) {
375: // beans.60=Indexed write method must take an int as its first argument
376: throw new IntrospectionException(Messages
377: .getString("beans.60")); //$NON-NLS-1$
378: }
379:
380: // Set the indexed property type if not already set, confirm validity if
381: // it is.
382: Class<?> indexedWriteType = indexedSetterArgs[1];
383: if (initialize && indexedGetter == null) {
384: indexedPropertyType = indexedWriteType;
385: } else {
386: if (indexedPropertyType != indexedWriteType) {
387: // beans.61=Indexed write method is not compatible with indexed read method
388: throw new IntrospectionException(Messages
389: .getString("beans.61")); //$NON-NLS-1$
390: }
391: }
392:
393: // Set the indexed write method.
394: this .indexedSetter = indexSetter;
395: }
396:
397: private static String initialUpperCase(String string) {
398: if (Character.isUpperCase(string.charAt(0))) {
399: return string;
400: }
401:
402: String initial = string.substring(0, 1).toUpperCase();
403: return initial.concat(string.substring(1));
404: }
405: }
|