From a72dd30956328e029e63032fe6febef6a292f2d4 Mon Sep 17 00:00:00 2001 From: Yash Siwach Date: Wed, 12 Aug 2026 22:23:24 +0530 Subject: [PATCH] Use 4-argument Property constructor in ReflectivePropertyAccessor Closes gh-37123 Signed-off-by: Yash Siwach --- .../spel/support/ReflectivePropertyAccessor.java | 6 +++--- .../expression/spel/PropertyAccessTests.java | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index 0b8fb34abc0c..d41967a44f0a 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -149,7 +149,7 @@ public boolean canRead(EvaluationContext context, @Nullable Object target, Strin if (method != null) { // Treat it like a property... // The readerCache will only contain gettable properties (let's not worry about setters for now). - Property property = new Property(type, method, null); + Property property = new Property(type, method, null, name); TypeDescriptor typeDescriptor = new TypeDescriptor(property); Method methodToInvoke = ClassUtils.getPubliclyAccessibleMethodIfPossible(method, type); this.readerCache.put(cacheKey, new InvokerPair(methodToInvoke, typeDescriptor)); @@ -193,7 +193,7 @@ public TypedValue read(EvaluationContext context, @Nullable Object target, Strin if (method != null) { // Treat it like a property... // The readerCache will only contain gettable properties (let's not worry about setters for now). - Property property = new Property(type, method, null); + Property property = new Property(type, method, null, name); TypeDescriptor typeDescriptor = new TypeDescriptor(property); methodToInvoke = ClassUtils.getPubliclyAccessibleMethodIfPossible(method, type); invoker = new InvokerPair(methodToInvoke, typeDescriptor); @@ -251,7 +251,7 @@ public boolean canWrite(EvaluationContext context, @Nullable Object target, Stri Method method = findSetterForProperty(name, type, target); if (method != null) { // Treat it like a property - Property property = new Property(type, null, method); + Property property = new Property(type, null, method, name); TypeDescriptor typeDescriptor = new TypeDescriptor(property); method = ClassUtils.getPubliclyAccessibleMethodIfPossible(method, type); this.writerCache.put(cacheKey, method); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java index 2209f56cd095..1c31dcbd4efa 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java @@ -312,6 +312,21 @@ void propertyAccessWithArrayIndexOutOfBounds() { .extracting(SpelEvaluationException::getMessageCode).isEqualTo(SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS); } + @Test + void propertyAccessorUtilizesKnownPropertyName() { + StandardEvaluationContext context = new StandardEvaluationContext(new Inventor("Nikola Tesla")); + Expression expression = parser.parseExpression("name"); + + // This triggers ReflectivePropertyAccessor getter resolution and caching (reads) + Object value = expression.getValue(context); + assertThat(value).isEqualTo("Nikola Tesla"); + + // This triggers ReflectivePropertyAccessor setter resolution and caching (writes) + assertThat(expression.isWritable(context)).isTrue(); + expression.setValue(context, "New Name"); + assertThat(expression.getValue(context)).isEqualTo("New Name"); + } + private ThrowableTypeAssert assertThatSpelEvaluationException() { return assertThatExceptionOfType(SpelEvaluationException.class);