@@ -266,198 +266,212 @@ public void setPropertyValue(PropertyValue pv) throws BeansException {
266
266
}
267
267
}
268
268
269
- @ SuppressWarnings ("unchecked" )
270
269
protected void setPropertyValue (PropertyTokenHolder tokens , PropertyValue pv ) throws BeansException {
271
- String propertyName = tokens .canonicalName ;
272
- String actualName = tokens .actualName ;
273
-
274
270
if (tokens .keys != null ) {
275
- // Apply indexes and map keys: fetch value for all keys but the last one.
276
- PropertyTokenHolder getterTokens = new PropertyTokenHolder ();
277
- getterTokens .canonicalName = tokens .canonicalName ;
278
- getterTokens .actualName = tokens .actualName ;
279
- getterTokens .keys = new String [tokens .keys .length - 1 ];
280
- System .arraycopy (tokens .keys , 0 , getterTokens .keys , 0 , tokens .keys .length - 1 );
281
- Object propValue ;
271
+ processKeyedProperty (tokens , pv );
272
+ }
273
+ else {
274
+ processLocalProperty (tokens , pv );
275
+ }
276
+ }
277
+
278
+ @ SuppressWarnings ("unchecked" )
279
+ private void processKeyedProperty (PropertyTokenHolder tokens , PropertyValue pv ) {
280
+ Object propValue = getPropertyHoldingValue (tokens );
281
+ String lastKey = tokens .keys [tokens .keys .length - 1 ];
282
+
283
+ if (propValue .getClass ().isArray ()) {
284
+ PropertyHandler ph = getLocalPropertyHandler (tokens .actualName );
285
+ Class <?> requiredType = propValue .getClass ().getComponentType ();
286
+ int arrayIndex = Integer .parseInt (lastKey );
287
+ Object oldValue = null ;
282
288
try {
283
- propValue = getPropertyValue (getterTokens );
284
- }
285
- catch (NotReadablePropertyException ex ) {
286
- throw new NotWritablePropertyException (getRootClass (), this .nestedPath + propertyName ,
287
- "Cannot access indexed value in property referenced " +
288
- "in indexed property path '" + propertyName + "'" , ex );
289
- }
290
- // Set value for last key.
291
- String key = tokens .keys [tokens .keys .length - 1 ];
292
- if (propValue == null ) {
293
- // null map value case
294
- if (isAutoGrowNestedPaths ()) {
295
- // TODO: cleanup, this is pretty hacky
296
- int lastKeyIndex = tokens .canonicalName .lastIndexOf ('[' );
297
- getterTokens .canonicalName = tokens .canonicalName .substring (0 , lastKeyIndex );
298
- propValue = setDefaultValue (getterTokens );
289
+ if (isExtractOldValueForEditor () && arrayIndex < Array .getLength (propValue )) {
290
+ oldValue = Array .get (propValue , arrayIndex );
299
291
}
300
- else {
301
- throw new NullValueInNestedPathException (getRootClass (), this .nestedPath + propertyName ,
302
- "Cannot access indexed value in property referenced " +
303
- "in indexed property path '" + propertyName + "': returned null" );
292
+ Object convertedValue = convertIfNecessary (tokens .canonicalName , oldValue , pv .getValue (),
293
+ requiredType , ph .nested (tokens .keys .length ));
294
+ int length = Array .getLength (propValue );
295
+ if (arrayIndex >= length && arrayIndex < this .autoGrowCollectionLimit ) {
296
+ Class <?> componentType = propValue .getClass ().getComponentType ();
297
+ Object newArray = Array .newInstance (componentType , arrayIndex + 1 );
298
+ System .arraycopy (propValue , 0 , newArray , 0 , length );
299
+ setPropertyValue (tokens .actualName , newArray );
300
+ propValue = getPropertyValue (tokens .actualName );
304
301
}
302
+ Array .set (propValue , arrayIndex , convertedValue );
305
303
}
306
- if (propValue .getClass ().isArray ()) {
307
- PropertyHandler ph = getLocalPropertyHandler (actualName );
308
- Class <?> requiredType = propValue .getClass ().getComponentType ();
309
- int arrayIndex = Integer .parseInt (key );
310
- Object oldValue = null ;
311
- try {
312
- if (isExtractOldValueForEditor () && arrayIndex < Array .getLength (propValue )) {
313
- oldValue = Array .get (propValue , arrayIndex );
304
+ catch (IndexOutOfBoundsException ex ) {
305
+ throw new InvalidPropertyException (getRootClass (), this .nestedPath + tokens .canonicalName ,
306
+ "Invalid array index in property path '" + tokens .canonicalName + "'" , ex );
307
+ }
308
+ }
309
+
310
+ else if (propValue instanceof List ) {
311
+ PropertyHandler ph = getPropertyHandler (tokens .actualName );
312
+ Class <?> requiredType = ph .getCollectionType (tokens .keys .length );
313
+ List <Object > list = (List <Object >) propValue ;
314
+ int index = Integer .parseInt (lastKey );
315
+ Object oldValue = null ;
316
+ if (isExtractOldValueForEditor () && index < list .size ()) {
317
+ oldValue = list .get (index );
318
+ }
319
+ Object convertedValue = convertIfNecessary (tokens .canonicalName , oldValue , pv .getValue (),
320
+ requiredType , ph .nested (tokens .keys .length ));
321
+ int size = list .size ();
322
+ if (index >= size && index < this .autoGrowCollectionLimit ) {
323
+ for (int i = size ; i < index ; i ++) {
324
+ try {
325
+ list .add (null );
314
326
}
315
- Object convertedValue = convertIfNecessary (propertyName , oldValue , pv .getValue (),
316
- requiredType , ph .nested (tokens .keys .length ));
317
- int length = Array .getLength (propValue );
318
- if (arrayIndex >= length && arrayIndex < this .autoGrowCollectionLimit ) {
319
- Class <?> componentType = propValue .getClass ().getComponentType ();
320
- Object newArray = Array .newInstance (componentType , arrayIndex + 1 );
321
- System .arraycopy (propValue , 0 , newArray , 0 , length );
322
- setPropertyValue (actualName , newArray );
323
- propValue = getPropertyValue (actualName );
327
+ catch (NullPointerException ex ) {
328
+ throw new InvalidPropertyException (getRootClass (), this .nestedPath + tokens .canonicalName ,
329
+ "Cannot set element with index " + index + " in List of size " +
330
+ size + ", accessed using property path '" + tokens .canonicalName +
331
+ "': List does not support filling up gaps with null elements" );
324
332
}
325
- Array .set (propValue , arrayIndex , convertedValue );
326
- }
327
- catch (IndexOutOfBoundsException ex ) {
328
- throw new InvalidPropertyException (getRootClass (), this .nestedPath + propertyName ,
329
- "Invalid array index in property path '" + propertyName + "'" , ex );
330
333
}
334
+ list .add (convertedValue );
331
335
}
332
- else if (propValue instanceof List ) {
333
- PropertyHandler ph = getPropertyHandler (actualName );
334
- Class <?> requiredType = ph .getCollectionType (tokens .keys .length );
335
- List <Object > list = (List <Object >) propValue ;
336
- int index = Integer .parseInt (key );
337
- Object oldValue = null ;
338
- if (isExtractOldValueForEditor () && index < list .size ()) {
339
- oldValue = list .get (index );
340
- }
341
- Object convertedValue = convertIfNecessary (propertyName , oldValue , pv .getValue (),
342
- requiredType , ph .nested (tokens .keys .length ));
343
- int size = list .size ();
344
- if (index >= size && index < this .autoGrowCollectionLimit ) {
345
- for (int i = size ; i < index ; i ++) {
346
- try {
347
- list .add (null );
348
- }
349
- catch (NullPointerException ex ) {
350
- throw new InvalidPropertyException (getRootClass (), this .nestedPath + propertyName ,
351
- "Cannot set element with index " + index + " in List of size " +
352
- size + ", accessed using property path '" + propertyName +
353
- "': List does not support filling up gaps with null elements" );
354
- }
355
- }
356
- list .add (convertedValue );
336
+ else {
337
+ try {
338
+ list .set (index , convertedValue );
357
339
}
358
- else {
359
- try {
360
- list .set (index , convertedValue );
361
- }
362
- catch (IndexOutOfBoundsException ex ) {
363
- throw new InvalidPropertyException (getRootClass (), this .nestedPath + propertyName ,
364
- "Invalid list index in property path '" + propertyName + "'" , ex );
365
- }
340
+ catch (IndexOutOfBoundsException ex ) {
341
+ throw new InvalidPropertyException (getRootClass (), this .nestedPath + tokens .canonicalName ,
342
+ "Invalid list index in property path '" + tokens .canonicalName + "'" , ex );
366
343
}
367
344
}
368
- else if (propValue instanceof Map ) {
369
- PropertyHandler ph = getLocalPropertyHandler (actualName );
370
- Class <?> mapKeyType = ph .getMapKeyType (tokens .keys .length );
371
- Class <?> mapValueType = ph .getMapValueType (tokens .keys .length );
372
- Map <Object , Object > map = (Map <Object , Object >) propValue ;
373
- // IMPORTANT: Do not pass full property name in here - property editors
374
- // must not kick in for map keys but rather only for map values.
375
- TypeDescriptor typeDescriptor = TypeDescriptor .valueOf (mapKeyType );
376
- Object convertedMapKey = convertIfNecessary (null , null , key , mapKeyType , typeDescriptor );
377
- Object oldValue = null ;
378
- if (isExtractOldValueForEditor ()) {
379
- oldValue = map .get (convertedMapKey );
345
+ }
346
+
347
+ else if (propValue instanceof Map ) {
348
+ PropertyHandler ph = getLocalPropertyHandler (tokens .actualName );
349
+ Class <?> mapKeyType = ph .getMapKeyType (tokens .keys .length );
350
+ Class <?> mapValueType = ph .getMapValueType (tokens .keys .length );
351
+ Map <Object , Object > map = (Map <Object , Object >) propValue ;
352
+ // IMPORTANT: Do not pass full property name in here - property editors
353
+ // must not kick in for map keys but rather only for map values.
354
+ TypeDescriptor typeDescriptor = TypeDescriptor .valueOf (mapKeyType );
355
+ Object convertedMapKey = convertIfNecessary (null , null , lastKey , mapKeyType , typeDescriptor );
356
+ Object oldValue = null ;
357
+ if (isExtractOldValueForEditor ()) {
358
+ oldValue = map .get (convertedMapKey );
359
+ }
360
+ // Pass full property name and old value in here, since we want full
361
+ // conversion ability for map values.
362
+ Object convertedMapValue = convertIfNecessary (tokens .canonicalName , oldValue , pv .getValue (),
363
+ mapValueType , ph .nested (tokens .keys .length ));
364
+ map .put (convertedMapKey , convertedMapValue );
365
+ }
366
+
367
+ else {
368
+ throw new InvalidPropertyException (getRootClass (), this .nestedPath + tokens .canonicalName ,
369
+ "Property referenced in indexed property path '" + tokens .canonicalName +
370
+ "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]" );
371
+ }
372
+ }
373
+
374
+ private Object getPropertyHoldingValue (PropertyTokenHolder tokens ) {
375
+ // Apply indexes and map keys: fetch value for all keys but the last one.
376
+ PropertyTokenHolder getterTokens = new PropertyTokenHolder ();
377
+ getterTokens .canonicalName = tokens .canonicalName ;
378
+ getterTokens .actualName = tokens .actualName ;
379
+ getterTokens .keys = new String [tokens .keys .length - 1 ];
380
+ System .arraycopy (tokens .keys , 0 , getterTokens .keys , 0 , tokens .keys .length - 1 );
381
+
382
+ Object propValue ;
383
+ try {
384
+ propValue = getPropertyValue (getterTokens );
385
+ }
386
+ catch (NotReadablePropertyException ex ) {
387
+ throw new NotWritablePropertyException (getRootClass (), this .nestedPath + tokens .canonicalName ,
388
+ "Cannot access indexed value in property referenced " +
389
+ "in indexed property path '" + tokens .canonicalName + "'" , ex );
390
+ }
391
+
392
+ if (propValue == null ) {
393
+ // null map value case
394
+ if (isAutoGrowNestedPaths ()) {
395
+ int lastKeyIndex = tokens .canonicalName .lastIndexOf ('[' );
396
+ getterTokens .canonicalName = tokens .canonicalName .substring (0 , lastKeyIndex );
397
+ propValue = setDefaultValue (getterTokens );
398
+ }
399
+ else {
400
+ throw new NullValueInNestedPathException (getRootClass (), this .nestedPath + tokens .canonicalName ,
401
+ "Cannot access indexed value in property referenced " +
402
+ "in indexed property path '" + tokens .canonicalName + "': returned null" );
403
+ }
404
+ }
405
+ return propValue ;
406
+ }
407
+
408
+ private void processLocalProperty (PropertyTokenHolder tokens , PropertyValue pv ) {
409
+ PropertyHandler ph = getLocalPropertyHandler (tokens .actualName );
410
+ if (ph == null || !ph .isWritable ()) {
411
+ if (pv .isOptional ()) {
412
+ if (logger .isDebugEnabled ()) {
413
+ logger .debug ("Ignoring optional value for property '" + tokens .actualName +
414
+ "' - property not found on bean class [" + getRootClass ().getName () + "]" );
380
415
}
381
- // Pass full property name and old value in here, since we want full
382
- // conversion ability for map values.
383
- Object convertedMapValue = convertIfNecessary (propertyName , oldValue , pv .getValue (),
384
- mapValueType , ph .nested (tokens .keys .length ));
385
- map .put (convertedMapKey , convertedMapValue );
416
+ return ;
386
417
}
387
418
else {
388
- throw new InvalidPropertyException (getRootClass (), this .nestedPath + propertyName ,
389
- "Property referenced in indexed property path '" + propertyName +
390
- "' is neither an array nor a List nor a Map; returned value was [" + propValue + "]" );
419
+ throw createNotWritablePropertyException (tokens .canonicalName );
391
420
}
392
421
}
393
422
394
- else {
395
- PropertyHandler ph = getLocalPropertyHandler (actualName );
396
- if (ph == null || !ph .isWritable ()) {
397
- if (pv .isOptional ()) {
398
- if (logger .isDebugEnabled ()) {
399
- logger .debug ("Ignoring optional value for property '" + actualName +
400
- "' - property not found on bean class [" + getRootClass ().getName () + "]" );
401
- }
402
- return ;
423
+ Object oldValue = null ;
424
+ try {
425
+ Object originalValue = pv .getValue ();
426
+ Object valueToApply = originalValue ;
427
+ if (!Boolean .FALSE .equals (pv .conversionNecessary )) {
428
+ if (pv .isConverted ()) {
429
+ valueToApply = pv .getConvertedValue ();
403
430
}
404
431
else {
405
- throw createNotWritablePropertyException (propertyName );
406
- }
407
- }
408
- Object oldValue = null ;
409
- try {
410
- Object originalValue = pv .getValue ();
411
- Object valueToApply = originalValue ;
412
- if (!Boolean .FALSE .equals (pv .conversionNecessary )) {
413
- if (pv .isConverted ()) {
414
- valueToApply = pv .getConvertedValue ();
415
- }
416
- else {
417
- if (isExtractOldValueForEditor () && ph .isReadable ()) {
418
- try {
419
- oldValue = ph .getValue ();
432
+ if (isExtractOldValueForEditor () && ph .isReadable ()) {
433
+ try {
434
+ oldValue = ph .getValue ();
435
+ }
436
+ catch (Exception ex ) {
437
+ if (ex instanceof PrivilegedActionException ) {
438
+ ex = ((PrivilegedActionException ) ex ).getException ();
420
439
}
421
- catch (Exception ex ) {
422
- if (ex instanceof PrivilegedActionException ) {
423
- ex = ((PrivilegedActionException ) ex ).getException ();
424
- }
425
- if (logger .isDebugEnabled ()) {
426
- logger .debug ("Could not read previous value of property '" +
427
- this .nestedPath + propertyName + "'" , ex );
428
- }
440
+ if (logger .isDebugEnabled ()) {
441
+ logger .debug ("Could not read previous value of property '" +
442
+ this .nestedPath + tokens .canonicalName + "'" , ex );
429
443
}
430
444
}
431
- valueToApply = convertForProperty (
432
- propertyName , oldValue , originalValue , ph .toTypeDescriptor ());
433
445
}
434
- pv .getOriginalPropertyValue ().conversionNecessary = (valueToApply != originalValue );
446
+ valueToApply = convertForProperty (
447
+ tokens .canonicalName , oldValue , originalValue , ph .toTypeDescriptor ());
435
448
}
436
- ph . setValue ( this . wrappedObject , valueToApply );
449
+ pv . getOriginalPropertyValue (). conversionNecessary = ( valueToApply != originalValue );
437
450
}
438
- catch (TypeMismatchException ex ) {
439
- throw ex ;
451
+ ph .setValue (this .wrappedObject , valueToApply );
452
+ }
453
+ catch (TypeMismatchException ex ) {
454
+ throw ex ;
455
+ }
456
+ catch (InvocationTargetException ex ) {
457
+ PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent (
458
+ this .rootObject , this .nestedPath + tokens .canonicalName , oldValue , pv .getValue ());
459
+ if (ex .getTargetException () instanceof ClassCastException ) {
460
+ throw new TypeMismatchException (propertyChangeEvent , ph .getPropertyType (), ex .getTargetException ());
440
461
}
441
- catch (InvocationTargetException ex ) {
442
- PropertyChangeEvent propertyChangeEvent =
443
- new PropertyChangeEvent (this .rootObject , this .nestedPath + propertyName , oldValue , pv .getValue ());
444
- if (ex .getTargetException () instanceof ClassCastException ) {
445
- throw new TypeMismatchException (propertyChangeEvent , ph .getPropertyType (), ex .getTargetException ());
446
- }
447
- else {
448
- Throwable cause = ex .getTargetException ();
449
- if (cause instanceof UndeclaredThrowableException ) {
450
- // May happen e.g. with Groovy-generated methods
451
- cause = cause .getCause ();
452
- }
453
- throw new MethodInvocationException (propertyChangeEvent , cause );
462
+ else {
463
+ Throwable cause = ex .getTargetException ();
464
+ if (cause instanceof UndeclaredThrowableException ) {
465
+ // May happen e.g. with Groovy-generated methods
466
+ cause = cause .getCause ();
454
467
}
468
+ throw new MethodInvocationException (propertyChangeEvent , cause );
455
469
}
456
- catch ( Exception ex ) {
457
- PropertyChangeEvent pce =
458
- new PropertyChangeEvent ( this . rootObject , this . nestedPath + propertyName , oldValue , pv . getValue ());
459
- throw new MethodInvocationException ( pce , ex );
460
- }
470
+ }
471
+ catch ( Exception ex ) {
472
+ PropertyChangeEvent pce = new PropertyChangeEvent (
473
+ this . rootObject , this . nestedPath + tokens . canonicalName , oldValue , pv . getValue () );
474
+ throw new MethodInvocationException ( pce , ex );
461
475
}
462
476
}
463
477
@@ -958,9 +972,6 @@ public String toString() {
958
972
}
959
973
960
974
961
- /**
962
- * Handle a given property.
963
- */
964
975
protected abstract static class PropertyHandler {
965
976
966
977
private final Class <?> propertyType ;
0 commit comments