From bcf9f21ecc17687ce285fa2e1e62b2ed1dfab614 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 14 Jul 2017 15:18:05 +0200 Subject: [PATCH] PropertyOrFieldReference checks cached PropertyAccessor against current EvaluationContext Issue: SPR-15769 --- .../spel/ast/PropertyOrFieldReference.java | 34 +++++++----- .../expression/spel/PropertyAccessTests.java | 55 ++++++++++++++++++- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index e2ca2f2312..cbc74a9459 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -172,14 +172,16 @@ public class PropertyOrFieldReference extends SpelNodeImpl { PropertyAccessor accessorToUse = this.cachedReadAccessor; if (accessorToUse != null) { - try { - return accessorToUse.read(evalContext, contextObject.getValue(), name); - } - catch (Exception ex) { - // This is OK - it may have gone stale due to a class change, - // let's try to get a new one and call it before giving up... - this.cachedReadAccessor = null; + if (evalContext.getPropertyAccessors().contains(accessorToUse)) { + try { + return accessorToUse.read(evalContext, contextObject.getValue(), name); + } + catch (Exception ex) { + // This is OK - it may have gone stale due to a class change, + // let's try to get a new one and call it before giving up... + } } + this.cachedReadAccessor = null; } List accessorsToTry = @@ -225,15 +227,17 @@ public class PropertyOrFieldReference extends SpelNodeImpl { PropertyAccessor accessorToUse = this.cachedWriteAccessor; if (accessorToUse != null) { - try { - accessorToUse.write(evalContext, contextObject.getValue(), name, newValue); - return; - } - catch (Exception ex) { - // This is OK - it may have gone stale due to a class change, - // let's try to get a new one and call it before giving up... - this.cachedWriteAccessor = null; + if (evalContext.getPropertyAccessors().contains(accessorToUse)) { + try { + accessorToUse.write(evalContext, contextObject.getValue(), name, newValue); + return; + } + catch (Exception ex) { + // This is OK - it may have gone stale due to a class change, + // let's try to get a new one and call it before giving up... + } } + this.cachedWriteAccessor = null; } List accessorsToTry = 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 f585b8cb58..ac06f7d362 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,9 @@ package org.springframework.expression.spel; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import org.junit.Test; @@ -34,12 +36,11 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import static org.junit.Assert.*; -///CLOVER:OFF - /** * Tests accessing of properties. * * @author Andy Clement + * @author Juergen Hoeller */ public class PropertyAccessTests extends AbstractExpressionTests { @@ -167,6 +168,20 @@ public class PropertyAccessTests extends AbstractExpressionTests { assertEquals(value, "java.lang.String"); } + @Test + public void shouldAlwaysUsePropertyAccessorFromEvaluationContext() { + SpelExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression("name"); + + StandardEvaluationContext context = new StandardEvaluationContext(); + context.addPropertyAccessor(new ConfigurablePropertyAccessor(Collections.singletonMap("name", "Ollie"))); + assertEquals("Ollie", expression.getValue(context)); + + context = new StandardEvaluationContext(); + context.addPropertyAccessor(new ConfigurablePropertyAccessor(Collections.singletonMap("name", "Jens"))); + assertEquals("Jens", expression.getValue(context)); + } + // This can resolve the property 'flibbles' on any String (very useful...) private static class StringyPropertyAccessor implements PropertyAccessor { @@ -216,4 +231,38 @@ public class PropertyAccessTests extends AbstractExpressionTests { } } + + private static class ConfigurablePropertyAccessor implements PropertyAccessor { + + private final Map values; + + public ConfigurablePropertyAccessor(Map values) { + this.values = values; + } + + @Override + public Class[] getSpecificTargetClasses() { + return null; + } + + @Override + public boolean canRead(EvaluationContext context, Object target, String name) { + return true; + } + + @Override + public TypedValue read(EvaluationContext context, Object target, String name) { + return new TypedValue(this.values.get(name)); + } + + @Override + public boolean canWrite(EvaluationContext context, Object target, String name) { + return false; + } + + @Override + public void write(EvaluationContext context, Object target, String name, Object newValue) { + } + } + }