001: package org.vraptor.reflection;
002:
003: import java.lang.reflect.Method;
004: import java.util.Arrays;
005: import java.util.Collection;
006:
007: import org.apache.log4j.Logger;
008: import org.vraptor.LogicRequest;
009: import org.vraptor.annotations.Conversion;
010: import org.vraptor.component.ComponentInstantiationException;
011: import org.vraptor.converter.ConversionException;
012: import org.vraptor.converter.Converter;
013: import org.vraptor.converter.ConverterManager;
014: import org.vraptor.introspector.ReadParameter;
015:
016: /**
017: * JPath setter execution for a specific logiccontext.
018: *
019: * @author Guilherme Silveira
020: */
021: public class JPathExecutor {
022:
023: private static final Logger LOG = Logger
024: .getLogger(JPathExecutor.class);
025:
026: private final ConverterManager manager;
027:
028: private final LogicRequest context;
029:
030: private final Object[] methodParams;
031:
032: private final Object component;
033:
034: public JPathExecutor(ConverterManager converters,
035: LogicRequest logicRequest, Object methodParams[],
036: Object component) {
037: this .manager = converters;
038: this .context = logicRequest;
039: this .methodParams = methodParams;
040: this .component = component;
041: }
042:
043: /**
044: * Tries to set some property in the current object. It uses the path array
045: * to walk in the object graph, the matching field is called field and the
046: * value is either completeValue or arrayValue
047: *
048: * @param object
049: * the object to set the property
050: * @param path
051: * the path to walk
052: * @param completeValue
053: * the completeValue
054: * @param arrayValue
055: * the array value
056: * @param field
057: * the field to use
058: * @throws SettingException
059: * some exception ocurred while trying to set a value
060: * @throws ConversionException
061: * some convesion exception occurred
062: */
063: public void set(String[] path, String completeValue,
064: String[] arrayValue, ReadParameter read)
065: throws SettingException, ConversionException {
066:
067: if (path.length == 1) {
068: try {
069: Object value = convert(completeValue, arrayValue, read
070: .getType(), read.getOverridenConverter());
071: read.set(component, methodParams, value);
072: } catch (ConversionException e) {
073: e.setCategory(path[0]);
074: throw e;
075: }
076: return;
077: }
078:
079: // moves to the first field
080: Object object = read
081: .guaranteeExistence(component, methodParams);
082: if (object == null) {
083: return;
084: }
085:
086: int start = 1, len = path.length;
087:
088: // navigates on the first array, one depth only
089: if (len != 2 && Character.isDigit(path[start].charAt(0))) {
090: SetDealer dealer = SetDealerFactory.getDealer(object);
091: try {
092: int arrayPosition = Integer.parseInt(path[start]);
093: object = dealer.resizeAndSet(object, arrayPosition,
094: read.mightCreate(), read.getGenericType());
095: // calls the setter
096: read.set(component, methodParams, object);
097: // retrieves the specified position
098: object = dealer.getPosition(object, arrayPosition, read
099: .mightCreate());
100: start++;
101: } catch (NumberFormatException e) {
102: throw new SettingException("Invalid array index: "
103: + path[1]);
104: }
105: }
106:
107: if (object == null) {
108: return;
109: }
110:
111: internalSet(path, completeValue, arrayValue, read, object,
112: start);
113: }
114:
115: private void internalSet(String[] path, String completeValue,
116: String[] arrayValue, ReadParameter read, Object object,
117: int start) throws SettingException, ConversionException {
118: try {
119:
120: for (int i = start; i < path.length - 1; i++) {
121:
122: Object currentObject = object;
123:
124: // for each parameter, calls the getter method
125: Method method = ReflectionUtil.findGetter(object
126: .getClass(), path[i]);
127: // if no getter found, forget it!
128: if (method == null) {
129: return;
130: }
131: object = ReflectionUtil.invoke(object, method);
132: Class returnType = method.getReturnType();
133: if (object == null) {
134: if (read.mightCreate()) {
135: try {
136: // my getter returned null... i should instantiate
137: // it
138: if (isCollection(returnType)) {
139: object = ReflectionUtil
140: .instantiateCollection(returnType);
141: } else {
142: object = ReflectionUtil
143: .genericInstantiate(returnType);
144: }
145: // calls the setter
146: ReflectionUtil.invoke(currentObject,
147: ReflectionUtil.findSetter(
148: currentObject, path[i]),
149: object);
150: } catch (ComponentInstantiationException e) {
151: throw new SettingException(e.getMessage(),
152: e);
153: }
154: } else {
155: return;
156: }
157: }
158:
159: // if the next is an array index, use it
160: while (i < path.length
161: && Character.isDigit(path[i + 1].charAt(0))) {
162: try {
163: int arrayPosition = Integer
164: .parseInt(path[i + 1]);
165: SetDealer dealer = SetDealerFactory
166: .getDealer(object);
167: object = dealer.resizeAndSet(object,
168: arrayPosition, read.mightCreate(),
169: method.getGenericReturnType());
170: // calls the setter
171: ReflectionUtil
172: .invoke(currentObject, ReflectionUtil
173: .findSetter(currentObject,
174: path[i]), object);
175: // retrieves the specified position
176: object = dealer.getPosition(object,
177: arrayPosition, read.mightCreate());
178: if (object == null) {
179: return;
180: }
181: } catch (NumberFormatException e) {
182: throw new SettingException(
183: "Invalid array index: " + path[1]);
184: }
185: i++;
186: }
187:
188: }
189:
190: String lastPath = path[path.length - 1];
191:
192: if (Character.isDigit(lastPath.charAt(0))) {
193: // if the last path is an array...
194: SetDealer dealer = SetDealerFactory.getDealer(object);
195: try {
196: int arrayPosition = Integer.parseInt(lastPath);
197: // last level... convert and set array position
198: Object value = convert(completeValue, arrayValue,
199: dealer.getType(read.getGenericType()), read
200: .getOverridenConverter());
201: object = dealer.resizeAndSet(object, arrayPosition,
202: value);
203: // calls the setter
204: read.set(component, methodParams, object);
205: return;
206: } catch (NumberFormatException e) {
207: throw new SettingException("Invalid array index "
208: + path[1]);
209: }
210: }
211:
212: // calls the setter for the last one
213: Method setter = ReflectionUtil.findSetter(object, lastPath);
214: if (setter == null) {
215: return;
216: }
217:
218: if (LOG.isDebugEnabled()) {
219: LOG.debug("ready to use parameter "
220: + Arrays.toString(path));
221: }
222:
223: Conversion annotation = setter
224: .getAnnotation(Conversion.class);
225: Class<? extends Converter> overriden = annotation == null ? null
226: : annotation.value();
227: Object result = convert(completeValue, arrayValue, setter
228: .getParameterTypes()[0], overriden);
229: ReflectionUtil.invoke(object, setter, result);
230:
231: } catch (MethodInvocationException e) {
232: throw new SettingException(e.getMessage(), e);
233: } catch (IllegalArgumentException e) {
234: throw new SettingException(e.getMessage(), e);
235: } catch (SecurityException e) {
236: throw new SettingException(e.getMessage(), e);
237: } catch (ConversionException e) {
238: e.setCategory(path[path.length - 1]);
239: throw e;
240: }
241: }
242:
243: /**
244: * Converts a value either by its type or overriden converter.
245: */
246: private Object convert(String completeValue, String[] arrayValue,
247: Class type, Class<? extends Converter> converter)
248: throws ConversionException {
249: return this .manager.convert(arrayValue, completeValue, type,
250: context, converter);
251: }
252:
253: private boolean isCollection(Class<?> type) {
254: return Collection.class.isAssignableFrom(type);
255: }
256:
257: }
|