Skip to content

Commit 5bec072

Browse files
committed
Polish SpEL internals
1 parent 8736ca0 commit 5bec072

File tree

3 files changed

+153
-152
lines changed

3 files changed

+153
-152
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java

+144-143
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ private enum IndexedType {ARRAY, LIST, MAP, STRING, OBJECT}
8282
private IndexedType indexedType;
8383

8484
@Nullable
85-
private String originalPrimitiveExitTypeDescriptor;
85+
private volatile String originalPrimitiveExitTypeDescriptor;
8686

8787
@Nullable
8888
private volatile String arrayTypeDescriptor;
@@ -373,131 +373,6 @@ public String toStringAST() {
373373
}
374374

375375

376-
private void setArrayElement(TypeConverter converter, Object ctx, int idx, @Nullable Object newValue,
377-
Class<?> arrayComponentType) throws EvaluationException {
378-
379-
if (arrayComponentType == boolean.class) {
380-
boolean[] array = (boolean[]) ctx;
381-
checkAccess(array.length, idx);
382-
array[idx] = convertValue(converter, newValue, boolean.class);
383-
}
384-
else if (arrayComponentType == byte.class) {
385-
byte[] array = (byte[]) ctx;
386-
checkAccess(array.length, idx);
387-
array[idx] = convertValue(converter, newValue, byte.class);
388-
}
389-
else if (arrayComponentType == char.class) {
390-
char[] array = (char[]) ctx;
391-
checkAccess(array.length, idx);
392-
array[idx] = convertValue(converter, newValue, char.class);
393-
}
394-
else if (arrayComponentType == double.class) {
395-
double[] array = (double[]) ctx;
396-
checkAccess(array.length, idx);
397-
array[idx] = convertValue(converter, newValue, double.class);
398-
}
399-
else if (arrayComponentType == float.class) {
400-
float[] array = (float[]) ctx;
401-
checkAccess(array.length, idx);
402-
array[idx] = convertValue(converter, newValue, float.class);
403-
}
404-
else if (arrayComponentType == int.class) {
405-
int[] array = (int[]) ctx;
406-
checkAccess(array.length, idx);
407-
array[idx] = convertValue(converter, newValue, int.class);
408-
}
409-
else if (arrayComponentType == long.class) {
410-
long[] array = (long[]) ctx;
411-
checkAccess(array.length, idx);
412-
array[idx] = convertValue(converter, newValue, long.class);
413-
}
414-
else if (arrayComponentType == short.class) {
415-
short[] array = (short[]) ctx;
416-
checkAccess(array.length, idx);
417-
array[idx] = convertValue(converter, newValue, short.class);
418-
}
419-
else {
420-
Object[] array = (Object[]) ctx;
421-
checkAccess(array.length, idx);
422-
array[idx] = convertValue(converter, newValue, arrayComponentType);
423-
}
424-
}
425-
426-
private Object accessArrayElement(Object ctx, int idx) throws SpelEvaluationException {
427-
Class<?> arrayComponentType = ctx.getClass().componentType();
428-
if (arrayComponentType == boolean.class) {
429-
boolean[] array = (boolean[]) ctx;
430-
checkAccess(array.length, idx);
431-
setExitTypeDescriptor("Z");
432-
this.arrayTypeDescriptor = "[Z";
433-
return array[idx];
434-
}
435-
else if (arrayComponentType == byte.class) {
436-
byte[] array = (byte[]) ctx;
437-
checkAccess(array.length, idx);
438-
setExitTypeDescriptor("B");
439-
this.arrayTypeDescriptor = "[B";
440-
return array[idx];
441-
}
442-
else if (arrayComponentType == char.class) {
443-
char[] array = (char[]) ctx;
444-
checkAccess(array.length, idx);
445-
setExitTypeDescriptor("C");
446-
this.arrayTypeDescriptor = "[C";
447-
return array[idx];
448-
}
449-
else if (arrayComponentType == double.class) {
450-
double[] array = (double[]) ctx;
451-
checkAccess(array.length, idx);
452-
setExitTypeDescriptor("D");
453-
this.arrayTypeDescriptor = "[D";
454-
return array[idx];
455-
}
456-
else if (arrayComponentType == float.class) {
457-
float[] array = (float[]) ctx;
458-
checkAccess(array.length, idx);
459-
setExitTypeDescriptor("F");
460-
this.arrayTypeDescriptor = "[F";
461-
return array[idx];
462-
}
463-
else if (arrayComponentType == int.class) {
464-
int[] array = (int[]) ctx;
465-
checkAccess(array.length, idx);
466-
setExitTypeDescriptor("I");
467-
this.arrayTypeDescriptor = "[I";
468-
return array[idx];
469-
}
470-
else if (arrayComponentType == long.class) {
471-
long[] array = (long[]) ctx;
472-
checkAccess(array.length, idx);
473-
setExitTypeDescriptor("J");
474-
this.arrayTypeDescriptor = "[J";
475-
return array[idx];
476-
}
477-
else if (arrayComponentType == short.class) {
478-
short[] array = (short[]) ctx;
479-
checkAccess(array.length, idx);
480-
setExitTypeDescriptor("S");
481-
this.arrayTypeDescriptor = "[S";
482-
return array[idx];
483-
}
484-
else {
485-
Object[] array = (Object[]) ctx;
486-
checkAccess(array.length, idx);
487-
Object retValue = array[idx];
488-
setExitTypeDescriptor(CodeFlow.toDescriptor(arrayComponentType));
489-
this.arrayTypeDescriptor = CodeFlow.toDescriptor(array.getClass());
490-
return retValue;
491-
}
492-
}
493-
494-
private void checkAccess(int arrayLength, int index) throws SpelEvaluationException {
495-
if (index >= arrayLength) {
496-
throw new SpelEvaluationException(getStartPosition(), SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS,
497-
arrayLength, index);
498-
}
499-
}
500-
501376
private void setExitTypeDescriptor(String descriptor) {
502377
// If this indexer would return a primitive - and yet it is also marked
503378
// null-safe - then the exit type descriptor must be promoted to the box
@@ -511,16 +386,6 @@ private void setExitTypeDescriptor(String descriptor) {
511386
}
512387
}
513388

514-
@SuppressWarnings("unchecked")
515-
private <T> T convertValue(TypeConverter converter, @Nullable Object value, Class<T> targetType) {
516-
T result = (T) converter.convertValue(
517-
value, TypeDescriptor.forObject(value), TypeDescriptor.valueOf(targetType));
518-
if (result == null) {
519-
throw new IllegalStateException("Null conversion result for index [" + value + "]");
520-
}
521-
return result;
522-
}
523-
524389

525390
private class ArrayIndexingValueRef implements ValueRef {
526391

@@ -541,7 +406,7 @@ private class ArrayIndexingValueRef implements ValueRef {
541406

542407
@Override
543408
public TypedValue getValue() {
544-
Object arrayElement = accessArrayElement(this.array, this.index);
409+
Object arrayElement = getArrayElement(this.array, this.index);
545410
return new TypedValue(arrayElement, this.typeDescriptor.elementTypeDescriptor(arrayElement));
546411
}
547412

@@ -556,6 +421,142 @@ public void setValue(@Nullable Object newValue) {
556421
public boolean isWritable() {
557422
return true;
558423
}
424+
425+
private Object getArrayElement(Object ctx, int idx) throws SpelEvaluationException {
426+
Class<?> arrayComponentType = ctx.getClass().componentType();
427+
if (arrayComponentType == boolean.class) {
428+
boolean[] array = (boolean[]) ctx;
429+
checkAccess(array.length, idx);
430+
setExitTypeDescriptor("Z");
431+
Indexer.this.arrayTypeDescriptor = "[Z";
432+
return array[idx];
433+
}
434+
else if (arrayComponentType == byte.class) {
435+
byte[] array = (byte[]) ctx;
436+
checkAccess(array.length, idx);
437+
setExitTypeDescriptor("B");
438+
Indexer.this.arrayTypeDescriptor = "[B";
439+
return array[idx];
440+
}
441+
else if (arrayComponentType == char.class) {
442+
char[] array = (char[]) ctx;
443+
checkAccess(array.length, idx);
444+
setExitTypeDescriptor("C");
445+
Indexer.this.arrayTypeDescriptor = "[C";
446+
return array[idx];
447+
}
448+
else if (arrayComponentType == double.class) {
449+
double[] array = (double[]) ctx;
450+
checkAccess(array.length, idx);
451+
setExitTypeDescriptor("D");
452+
Indexer.this.arrayTypeDescriptor = "[D";
453+
return array[idx];
454+
}
455+
else if (arrayComponentType == float.class) {
456+
float[] array = (float[]) ctx;
457+
checkAccess(array.length, idx);
458+
setExitTypeDescriptor("F");
459+
Indexer.this.arrayTypeDescriptor = "[F";
460+
return array[idx];
461+
}
462+
else if (arrayComponentType == int.class) {
463+
int[] array = (int[]) ctx;
464+
checkAccess(array.length, idx);
465+
setExitTypeDescriptor("I");
466+
Indexer.this.arrayTypeDescriptor = "[I";
467+
return array[idx];
468+
}
469+
else if (arrayComponentType == long.class) {
470+
long[] array = (long[]) ctx;
471+
checkAccess(array.length, idx);
472+
setExitTypeDescriptor("J");
473+
Indexer.this.arrayTypeDescriptor = "[J";
474+
return array[idx];
475+
}
476+
else if (arrayComponentType == short.class) {
477+
short[] array = (short[]) ctx;
478+
checkAccess(array.length, idx);
479+
setExitTypeDescriptor("S");
480+
Indexer.this.arrayTypeDescriptor = "[S";
481+
return array[idx];
482+
}
483+
else {
484+
Object[] array = (Object[]) ctx;
485+
checkAccess(array.length, idx);
486+
Object retValue = array[idx];
487+
Indexer.this.exitTypeDescriptor = CodeFlow.toDescriptor(arrayComponentType);
488+
Indexer.this.arrayTypeDescriptor = CodeFlow.toDescriptor(array.getClass());
489+
return retValue;
490+
}
491+
}
492+
493+
private void setArrayElement(TypeConverter converter, Object ctx, int idx, @Nullable Object newValue,
494+
Class<?> arrayComponentType) throws EvaluationException {
495+
496+
if (arrayComponentType == boolean.class) {
497+
boolean[] array = (boolean[]) ctx;
498+
checkAccess(array.length, idx);
499+
array[idx] = convertValue(converter, newValue, boolean.class);
500+
}
501+
else if (arrayComponentType == byte.class) {
502+
byte[] array = (byte[]) ctx;
503+
checkAccess(array.length, idx);
504+
array[idx] = convertValue(converter, newValue, byte.class);
505+
}
506+
else if (arrayComponentType == char.class) {
507+
char[] array = (char[]) ctx;
508+
checkAccess(array.length, idx);
509+
array[idx] = convertValue(converter, newValue, char.class);
510+
}
511+
else if (arrayComponentType == double.class) {
512+
double[] array = (double[]) ctx;
513+
checkAccess(array.length, idx);
514+
array[idx] = convertValue(converter, newValue, double.class);
515+
}
516+
else if (arrayComponentType == float.class) {
517+
float[] array = (float[]) ctx;
518+
checkAccess(array.length, idx);
519+
array[idx] = convertValue(converter, newValue, float.class);
520+
}
521+
else if (arrayComponentType == int.class) {
522+
int[] array = (int[]) ctx;
523+
checkAccess(array.length, idx);
524+
array[idx] = convertValue(converter, newValue, int.class);
525+
}
526+
else if (arrayComponentType == long.class) {
527+
long[] array = (long[]) ctx;
528+
checkAccess(array.length, idx);
529+
array[idx] = convertValue(converter, newValue, long.class);
530+
}
531+
else if (arrayComponentType == short.class) {
532+
short[] array = (short[]) ctx;
533+
checkAccess(array.length, idx);
534+
array[idx] = convertValue(converter, newValue, short.class);
535+
}
536+
else {
537+
Object[] array = (Object[]) ctx;
538+
checkAccess(array.length, idx);
539+
array[idx] = convertValue(converter, newValue, arrayComponentType);
540+
}
541+
}
542+
543+
private void checkAccess(int arrayLength, int index) throws SpelEvaluationException {
544+
if (index >= arrayLength) {
545+
throw new SpelEvaluationException(getStartPosition(), SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS,
546+
arrayLength, index);
547+
}
548+
}
549+
550+
@SuppressWarnings("unchecked")
551+
private static <T> T convertValue(TypeConverter converter, @Nullable Object value, Class<T> targetType) {
552+
T result = (T) converter.convertValue(
553+
value, TypeDescriptor.forObject(value), TypeDescriptor.valueOf(targetType));
554+
if (result == null) {
555+
throw new IllegalStateException("Null conversion result for index [" + value + "]");
556+
}
557+
return result;
558+
}
559+
559560
}
560561

561562

@@ -789,20 +790,20 @@ private void growCollectionIfNecessary() {
789790
}
790791
}
791792

793+
@Override
794+
public boolean isWritable() {
795+
return true;
796+
}
797+
792798
@Nullable
793-
private Constructor<?> getDefaultConstructor(Class<?> type) {
799+
private static Constructor<?> getDefaultConstructor(Class<?> type) {
794800
try {
795801
return ReflectionUtils.accessibleConstructor(type);
796802
}
797803
catch (Throwable ex) {
798804
return null;
799805
}
800806
}
801-
802-
@Override
803-
public boolean isWritable() {
804-
return true;
805-
}
806807
}
807808

808809

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
* for reading and possibly also for writing on a target instance.
5858
*
5959
* <p>A property can be referenced through a public getter method (when being read)
60-
* or a public setter method (when being written), and also as a public field.
60+
* or a public setter method (when being written), and also through a public field.
6161
*
6262
* @author Andy Clement
6363
* @author Juergen Hoeller
@@ -87,7 +87,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
8787

8888

8989
/**
90-
* Create a new property accessor for reading as well writing.
90+
* Create a new property accessor for reading as well as writing.
9191
* @see #ReflectivePropertyAccessor(boolean)
9292
*/
9393
public ReflectivePropertyAccessor() {

spring-expression/src/main/java/org/springframework/expression/spel/support/StandardEvaluationContext.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,11 @@ public void registerMethodFilter(Class<?> type, MethodFilter filter) throws Ille
381381
*/
382382
public void applyDelegatesTo(StandardEvaluationContext evaluationContext) {
383383
// Triggers initialization for default delegates
384-
evaluationContext.setConstructorResolvers(new ArrayList<>(this.getConstructorResolvers()));
385-
evaluationContext.setMethodResolvers(new ArrayList<>(this.getMethodResolvers()));
386-
evaluationContext.setPropertyAccessors(new ArrayList<>(this.getPropertyAccessors()));
387-
evaluationContext.setTypeLocator(this.getTypeLocator());
388-
evaluationContext.setTypeConverter(this.getTypeConverter());
384+
evaluationContext.setConstructorResolvers(new ArrayList<>(getConstructorResolvers()));
385+
evaluationContext.setMethodResolvers(new ArrayList<>(getMethodResolvers()));
386+
evaluationContext.setPropertyAccessors(new ArrayList<>(getPropertyAccessors()));
387+
evaluationContext.setTypeLocator(getTypeLocator());
388+
evaluationContext.setTypeConverter(getTypeConverter());
389389

390390
evaluationContext.beanResolver = this.beanResolver;
391391
evaluationContext.operatorOverloader = this.operatorOverloader;
@@ -425,8 +425,8 @@ private List<MethodResolver> initMethodResolvers() {
425425
return resolvers;
426426
}
427427

428-
private static <T> void addBeforeDefault(List<T> resolvers, T resolver) {
429-
resolvers.add(resolvers.size() - 1, resolver);
428+
private static <T> void addBeforeDefault(List<T> list, T element) {
429+
list.add(list.size() - 1, element);
430430
}
431431

432432
}

0 commit comments

Comments
 (0)