@@ -71,6 +71,9 @@ private enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT}
71
71
@ Nullable
72
72
private IndexedType indexedType ;
73
73
74
+ @ Nullable
75
+ private volatile String arrayTypeDescriptor ;
76
+
74
77
// These fields are used when the indexer is being used as a property read accessor.
75
78
// If the name and target type match these cached values then the cachedReadAccessor
76
79
// is used to read the property. If they do not match, the correct accessor is
@@ -212,7 +215,7 @@ else if (target instanceof Collection<?> collection) {
212
215
@ Override
213
216
public boolean isCompilable () {
214
217
if (this .indexedType == IndexedType .ARRAY ) {
215
- return (this .exitTypeDescriptor != null );
218
+ return (this .exitTypeDescriptor != null && this . arrayTypeDescriptor != null );
216
219
}
217
220
SpelNodeImpl index = this .children [0 ];
218
221
if (this .indexedType == IndexedType .LIST ) {
@@ -233,6 +236,7 @@ else if (this.indexedType == IndexedType.OBJECT) {
233
236
234
237
@ Override
235
238
public void generateCode (MethodVisitor mv , CodeFlow cf ) {
239
+ String exitTypeDescriptor = this .exitTypeDescriptor ;
236
240
String descriptor = cf .lastDescriptor ();
237
241
if (descriptor == null ) {
238
242
// Stack is empty, should use context object
@@ -242,48 +246,19 @@ public void generateCode(MethodVisitor mv, CodeFlow cf) {
242
246
SpelNodeImpl index = this .children [0 ];
243
247
244
248
if (this .indexedType == IndexedType .ARRAY ) {
245
- String exitTypeDescriptor = this .exitTypeDescriptor ;
246
- Assert .state (exitTypeDescriptor != null , "Array not compilable without descriptor" );
247
- int insn = switch (exitTypeDescriptor ) {
248
- case "D" -> {
249
- mv .visitTypeInsn (CHECKCAST , "[D" );
250
- yield DALOAD ;
251
- }
252
- case "F" -> {
253
- mv .visitTypeInsn (CHECKCAST , "[F" );
254
- yield FALOAD ;
255
- }
256
- case "J" -> {
257
- mv .visitTypeInsn (CHECKCAST , "[J" );
258
- yield LALOAD ;
259
- }
260
- case "I" -> {
261
- mv .visitTypeInsn (CHECKCAST , "[I" );
262
- yield IALOAD ;
263
- }
264
- case "S" -> {
265
- mv .visitTypeInsn (CHECKCAST , "[S" );
266
- yield SALOAD ;
267
- }
268
- case "B" -> {
269
- mv .visitTypeInsn (CHECKCAST , "[B" );
270
- // byte and boolean arrays are both loaded via BALOAD
271
- yield BALOAD ;
272
- }
273
- case "Z" -> {
274
- mv .visitTypeInsn (CHECKCAST , "[Z" );
275
- // byte and boolean arrays are both loaded via BALOAD
276
- yield BALOAD ;
277
- }
278
- case "C" -> {
279
- mv .visitTypeInsn (CHECKCAST , "[C" );
280
- yield CALOAD ;
281
- }
282
- default -> {
283
- mv .visitTypeInsn (CHECKCAST , "[" + exitTypeDescriptor +
284
- (CodeFlow .isPrimitiveArray (exitTypeDescriptor ) ? "" : ";" ));
285
- yield AALOAD ;
286
- }
249
+ String arrayTypeDescriptor = this .arrayTypeDescriptor ;
250
+ Assert .state (exitTypeDescriptor != null && arrayTypeDescriptor != null ,
251
+ "Array not compilable without descriptors" );
252
+ CodeFlow .insertCheckCast (mv , arrayTypeDescriptor );
253
+ int insn = switch (arrayTypeDescriptor ) {
254
+ case "[D" -> DALOAD ;
255
+ case "[F" -> FALOAD ;
256
+ case "[J" -> LALOAD ;
257
+ case "[I" -> IALOAD ;
258
+ case "[S" -> SALOAD ;
259
+ case "[B" , "[Z" -> BALOAD ; // byte[] & boolean[] are both loaded via BALOAD
260
+ case "[C" -> CALOAD ;
261
+ default -> AALOAD ;
287
262
};
288
263
289
264
cf .enterCompilationScope ();
@@ -329,7 +304,7 @@ else if (this.indexedType == IndexedType.OBJECT) {
329
304
compilablePropertyAccessor .generateCode (propertyName , mv , cf );
330
305
}
331
306
332
- cf .pushDescriptor (this . exitTypeDescriptor );
307
+ cf .pushDescriptor (exitTypeDescriptor );
333
308
}
334
309
335
310
@ Override
@@ -394,55 +369,64 @@ private Object accessArrayElement(Object ctx, int idx) throws SpelEvaluationExce
394
369
boolean [] array = (boolean []) ctx ;
395
370
checkAccess (array .length , idx );
396
371
this .exitTypeDescriptor = "Z" ;
372
+ this .arrayTypeDescriptor = "[Z" ;
397
373
return array [idx ];
398
374
}
399
375
else if (arrayComponentType == byte .class ) {
400
376
byte [] array = (byte []) ctx ;
401
377
checkAccess (array .length , idx );
402
378
this .exitTypeDescriptor = "B" ;
379
+ this .arrayTypeDescriptor = "[B" ;
403
380
return array [idx ];
404
381
}
405
382
else if (arrayComponentType == char .class ) {
406
383
char [] array = (char []) ctx ;
407
384
checkAccess (array .length , idx );
408
385
this .exitTypeDescriptor = "C" ;
386
+ this .arrayTypeDescriptor = "[C" ;
409
387
return array [idx ];
410
388
}
411
389
else if (arrayComponentType == double .class ) {
412
390
double [] array = (double []) ctx ;
413
391
checkAccess (array .length , idx );
414
392
this .exitTypeDescriptor = "D" ;
393
+ this .arrayTypeDescriptor = "[D" ;
415
394
return array [idx ];
416
395
}
417
396
else if (arrayComponentType == float .class ) {
418
397
float [] array = (float []) ctx ;
419
398
checkAccess (array .length , idx );
420
399
this .exitTypeDescriptor = "F" ;
400
+ this .arrayTypeDescriptor = "[F" ;
421
401
return array [idx ];
422
402
}
423
403
else if (arrayComponentType == int .class ) {
424
404
int [] array = (int []) ctx ;
425
405
checkAccess (array .length , idx );
426
406
this .exitTypeDescriptor = "I" ;
407
+ this .arrayTypeDescriptor = "[I" ;
427
408
return array [idx ];
428
409
}
429
410
else if (arrayComponentType == long .class ) {
430
411
long [] array = (long []) ctx ;
431
412
checkAccess (array .length , idx );
432
413
this .exitTypeDescriptor = "J" ;
414
+ this .arrayTypeDescriptor = "[J" ;
433
415
return array [idx ];
434
416
}
435
417
else if (arrayComponentType == short .class ) {
436
418
short [] array = (short []) ctx ;
437
419
checkAccess (array .length , idx );
438
420
this .exitTypeDescriptor = "S" ;
421
+ this .arrayTypeDescriptor = "[S" ;
439
422
return array [idx ];
440
423
}
441
424
else {
442
425
Object [] array = (Object []) ctx ;
443
426
checkAccess (array .length , idx );
444
427
Object retValue = array [idx ];
445
428
this .exitTypeDescriptor = CodeFlow .toDescriptor (arrayComponentType );
429
+ this .arrayTypeDescriptor = CodeFlow .toDescriptor (array .getClass ());
446
430
return retValue ;
447
431
}
448
432
}
0 commit comments