001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003: package jodd.bean;
004:
005: import jodd.util.ReflectUtil;
006:
007: import java.lang.reflect.Array;
008: import java.lang.reflect.Field;
009: import java.lang.reflect.Method;
010: import java.lang.reflect.Type;
011: import java.util.List;
012:
013: /**
014: * Various bean property utilities that makes writings of {@link BeanUtil} classes easy.
015: */
016: public class BeanUtilUtil {
017:
018: // ---------------------------------------------------------------- accessors
019:
020: /**
021: * Invokes <code>setXxx()</code> method with appropriate conversion if available.
022: * It is assumed that all provided arguments are valid.
023: */
024: protected static void invokeSetter(Object bean, Method m,
025: Object value) {
026: try {
027: Class[] paramTypes = m.getParameterTypes();
028: value = ReflectUtil.castType(value, paramTypes[0]);
029: m.invoke(bean, value);
030: } catch (Exception ex) {
031: throw new BeanException("Unable to invoke setter '"
032: + bean.getClass().getSimpleName() + '#'
033: + m.getName() + "()'", ex);
034: }
035: }
036:
037: /**
038: * Invokes <code>getXxx()</code> method of specified bean.
039: * It is assumed that all provided arguments are valid.
040: */
041: protected static Object invokeGetter(Object bean, Method m) {
042: try {
043: return m.invoke(bean);
044: } catch (Exception ex) {
045: throw new BeanException("Unable to invoke getter '"
046: + bean.getClass().getSimpleName() + '#'
047: + m.getName() + "()'", ex);
048: }
049: }
050:
051: /**
052: * Sets field value.
053: */
054: protected static void setField(Object bean, Field f, Object value) {
055: try {
056: Class type = f.getType();
057: value = ReflectUtil.castType(value, type);
058: f.set(bean, value);
059: } catch (Exception iaex) {
060: throw new BeanException("Unable to set field '"
061: + bean.getClass().getSimpleName() + '#'
062: + f.getName() + '\'', iaex);
063: }
064: }
065:
066: /**
067: * Return value of a field.
068: */
069: protected static Object getField(Object bean, Field f) {
070: try {
071: return f.get(bean);
072: } catch (Exception iaex) {
073: throw new BeanException("Unable to get field '"
074: + bean.getClass().getSimpleName() + '#'
075: + f.getName() + '\'', iaex);
076: }
077: }
078:
079: // ---------------------------------------------------------------- forced
080:
081: /**
082: * Returns the element of an array forced. If value is <code>null</code>, it will be instantiated.
083: * If not the last part of indexed bean property, array will be expanded to the index if necessary.
084: */
085: protected static Object arrayForcedGet(BeanProperty bp,
086: Object array, int index) {
087: Class componentType = array.getClass().getComponentType();
088: if (bp.last == false) {
089: array = ensureArraySize(bp, array, componentType, index);
090: }
091: Object value = Array.get(array, index);
092: if (value == null) {
093: try {
094: value = ReflectUtil.newInstance(componentType);
095: } catch (Exception ex) {
096: throw new BeanException(
097: "Unable to create array element '" + bp.name
098: + '[' + index + "]'.", bp, ex);
099: }
100: Array.set(array, index, value);
101: }
102: return value;
103: }
104:
105: /**
106: * Sets the array element forced. If index is greater then arrays length, array will be expanded to the index.
107: * If speed is critical, it is better to allocate an array with proper size before using this method.
108: */
109: protected static void arrayForcedSet(BeanProperty bp, Object array,
110: int index, Object value) {
111: Class componentType = array.getClass().getComponentType();
112: array = ensureArraySize(bp, array, componentType, index);
113: value = ReflectUtil.castType(value, componentType);
114: Array.set(array, index, value);
115: }
116:
117: protected static Object ensureArraySize(BeanProperty bp,
118: Object array, Class componentType, int index) {
119: int len = Array.getLength(array);
120: if (index >= len) {
121: Object newArray = Array.newInstance(componentType,
122: index + 1);
123: System.arraycopy(array, 0, newArray, 0, len);
124: Method setter = bp.cd.getBeanSetter(bp.name, true);
125: if (setter != null) {
126: invokeSetter(bp.bean, setter, newArray);
127: } else {
128: Field field = bp.cd.getField(bp.name, true);
129: if (field == null) {
130: throw new BeanException(
131: "Unable to find setter or field named as '"
132: + bp.name + '\'', bp);
133: }
134: setField(bp.bean, field, newArray);
135: }
136: array = newArray;
137: }
138: return array;
139: }
140:
141: @SuppressWarnings({"unchecked"})
142: protected static void ensureListSize(List list, int size) {
143: int len = list.size();
144: while (size >= len) {
145: list.add(null);
146: len++;
147: }
148: }
149:
150: // ---------------------------------------------------------------- index
151:
152: /**
153: * Extract index string from non-nested property name.
154: * If index is found, it is stripped from bean property name.
155: * If no index is found, it returns null.
156: */
157: protected static String extractIndex(BeanProperty bp) {
158: String name = bp.name;
159: int lastNdx = name.length() - 1;
160: if (name.charAt(lastNdx) == ']') {
161: int leftBracketNdx = name.lastIndexOf('[');
162: if (leftBracketNdx != -1) {
163: bp.name = name.substring(0, leftBracketNdx);
164: return name.substring(leftBracketNdx + 1, lastNdx);
165: }
166: }
167: return null;
168: }
169:
170: protected static int parseInt(String indexString, BeanProperty bp) {
171: try {
172: return Integer.parseInt(indexString);
173: } catch (NumberFormatException nfex) {
174: throw new BeanException("Provided index '" + indexString
175: + "' is not a number.", bp, nfex);
176: }
177: }
178:
179: // ---------------------------------------------------------------- create property
180:
181: /**
182: * Creates new instance for current property name through its setter.
183: * It uses default constructor!
184: */
185: protected static Object createBeanProperty(BeanProperty bp) {
186: Method setter = bp.cd.getBeanSetter(bp.name, true);
187: Field field = null;
188: Class type;
189: if (setter != null) {
190: type = setter.getParameterTypes()[0];
191: } else {
192: field = bp.cd.getField(bp.name, true);
193: if (field == null) {
194: return null;
195: }
196: type = field.getType();
197: }
198: Object newInstance;
199: try {
200: newInstance = ReflectUtil.newInstance(type);
201: } catch (Exception ex) {
202: throw new BeanException("Unable to create '" + bp.name
203: + "' through its setter.", bp);
204: }
205: if (setter != null) {
206: invokeSetter(bp.bean, setter, newInstance);
207: } else {
208: setField(bp.bean, field, newInstance);
209: }
210: return newInstance;
211: }
212:
213: // ---------------------------------------------------------------- generic
214:
215: /**
216: * Extracts generic parameter types.
217: */
218: protected static Class extracticGenericType(BeanProperty bp,
219: int index) {
220: Type type;
221: if (bp.field != null) {
222: type = bp.field.getGenericType();
223: } else if (bp.method != null) {
224: type = bp.method.getGenericReturnType();
225: } else {
226: return null;
227: }
228: return ReflectUtil.getComponentType(type, index);
229: }
230:
231: }
|