Browse Source

Internal adaptation to Deque semantics

pull/1679/head
Juergen Hoeller 8 years ago
parent
commit
d5cabca2f7
  1. 9
      spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java
  2. 8
      spring-context/src/main/java/org/springframework/validation/AbstractErrors.java
  3. 15
      spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java
  4. 104
      spring-expression/src/test/java/org/springframework/expression/spel/ExpressionStateTests.java

9
spring-beans/src/main/java/org/springframework/beans/factory/xml/ParserContext.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ public final class ParserContext {
@Nullable @Nullable
private BeanDefinition containingBeanDefinition; private BeanDefinition containingBeanDefinition;
private final Deque<ComponentDefinition> containingComponents = new ArrayDeque<>(); private final Deque<CompositeComponentDefinition> containingComponents = new ArrayDeque<>();
public ParserContext(XmlReaderContext readerContext, BeanDefinitionParserDelegate delegate) { public ParserContext(XmlReaderContext readerContext, BeanDefinitionParserDelegate delegate) {
@ -96,8 +96,7 @@ public final class ParserContext {
@Nullable @Nullable
public CompositeComponentDefinition getContainingComponent() { public CompositeComponentDefinition getContainingComponent() {
return (!this.containingComponents.isEmpty() ? return this.containingComponents.peek();
(CompositeComponentDefinition) this.containingComponents.getLast() : null);
} }
public void pushContainingComponent(CompositeComponentDefinition containingComponent) { public void pushContainingComponent(CompositeComponentDefinition containingComponent) {
@ -105,7 +104,7 @@ public final class ParserContext {
} }
public CompositeComponentDefinition popContainingComponent() { public CompositeComponentDefinition popContainingComponent() {
return (CompositeComponentDefinition) this.containingComponents.pop(); return this.containingComponents.pop();
} }
public void popAndRegisterContainingComponent() { public void popAndRegisterContainingComponent() {

8
spring-context/src/main/java/org/springframework/validation/AbstractErrors.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,9 +20,9 @@ import java.io.Serializable;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Collections; import java.util.Collections;
import java.util.Deque; import java.util.Deque;
import java.util.EmptyStackException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -62,12 +62,12 @@ public abstract class AbstractErrors implements Errors, Serializable {
} }
@Override @Override
public void popNestedPath() throws IllegalArgumentException { public void popNestedPath() throws IllegalStateException {
try { try {
String formerNestedPath = this.nestedPathStack.pop(); String formerNestedPath = this.nestedPathStack.pop();
doSetNestedPath(formerNestedPath); doSetNestedPath(formerNestedPath);
} }
catch (EmptyStackException ex) { catch (NoSuchElementException ex) {
throw new IllegalStateException("Cannot pop nested path: no nested path on stack"); throw new IllegalStateException("Cannot pop nested path: no nested path on stack");
} }
} }

15
spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
@ -49,6 +50,7 @@ import org.springframework.util.CollectionUtils;
* nodes might need. * nodes might need.
* *
* @author Andy Clement * @author Andy Clement
* @author Juergen Hoeller
* @since 3.0 * @since 3.0
*/ */
public class ExpressionState { public class ExpressionState {
@ -118,7 +120,12 @@ public class ExpressionState {
if (this.contextObjects == null) { if (this.contextObjects == null) {
this.contextObjects = new ArrayDeque<>(); this.contextObjects = new ArrayDeque<>();
} }
this.contextObjects.pop(); try {
this.contextObjects.pop();
}
catch (NoSuchElementException ex) {
throw new IllegalStateException("Cannot pop active context object: stack is empty");
}
} }
public TypedValue getRootContextObject() { public TypedValue getRootContextObject() {
@ -197,9 +204,7 @@ public class ExpressionState {
@Nullable @Nullable
public Object lookupLocalVariable(String name) { public Object lookupLocalVariable(String name) {
int scopeNumber = initVariableScopes().size() - 1; for (VariableScope scope : initVariableScopes()) {
for (int i = scopeNumber; i >= 0; i--) {
VariableScope scope = initVariableScopes().get(i);
if (scope.definesVariable(name)) { if (scope.definesVariable(name)) {
return scope.lookupVariable(name); return scope.lookupVariable(name);
} }

104
spring-expression/src/test/java/org/springframework/expression/spel/ExpressionStateTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,6 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import java.util.EmptyStackException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -36,6 +35,7 @@ import static org.junit.Assert.*;
* Tests for the expression state object - some features are not yet exploited in the language (eg nested scopes) * Tests for the expression state object - some features are not yet exploited in the language (eg nested scopes)
* *
* @author Andy Clement * @author Andy Clement
* @author Juergen Hoeller
*/ */
public class ExpressionStateTests extends AbstractExpressionTests { public class ExpressionStateTests extends AbstractExpressionTests {
@ -43,7 +43,7 @@ public class ExpressionStateTests extends AbstractExpressionTests {
public void testConstruction() { public void testConstruction() {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
ExpressionState state = new ExpressionState(context); ExpressionState state = new ExpressionState(context);
assertEquals(context,state.getEvaluationContext()); assertEquals(context, state.getEvaluationContext());
} }
// Local variables are in variable scopes which come and go during evaluation. Normal variables are // Local variables are in variable scopes which come and go during evaluation. Normal variables are
@ -58,107 +58,107 @@ public class ExpressionStateTests extends AbstractExpressionTests {
state.setLocalVariable("foo",34); state.setLocalVariable("foo",34);
value = state.lookupLocalVariable("foo"); value = state.lookupLocalVariable("foo");
assertEquals(34,value); assertEquals(34, value);
state.setLocalVariable("foo",null); state.setLocalVariable("foo", null);
value = state.lookupLocalVariable("foo"); value = state.lookupLocalVariable("foo");
assertEquals(null,value); assertEquals(null, value);
} }
@Test @Test
public void testVariables() { public void testVariables() {
ExpressionState state = getState(); ExpressionState state = getState();
TypedValue typedValue = state.lookupVariable("foo"); TypedValue typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL,typedValue); assertEquals(TypedValue.NULL, typedValue);
state.setVariable("foo",34); state.setVariable("foo",34);
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals(34,typedValue.getValue()); assertEquals(34, typedValue.getValue());
assertEquals(Integer.class,typedValue.getTypeDescriptor().getType()); assertEquals(Integer.class, typedValue.getTypeDescriptor().getType());
state.setVariable("foo","abc"); state.setVariable("foo","abc");
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals("abc",typedValue.getValue()); assertEquals("abc", typedValue.getValue());
assertEquals(String.class,typedValue.getTypeDescriptor().getType()); assertEquals(String.class, typedValue.getTypeDescriptor().getType());
} }
@Test @Test
public void testNoVariableInteference() { public void testNoVariableInteference() {
ExpressionState state = getState(); ExpressionState state = getState();
TypedValue typedValue = state.lookupVariable("foo"); TypedValue typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL,typedValue); assertEquals(TypedValue.NULL, typedValue);
state.setLocalVariable("foo",34); state.setLocalVariable("foo",34);
typedValue = state.lookupVariable("foo"); typedValue = state.lookupVariable("foo");
assertEquals(TypedValue.NULL,typedValue); assertEquals(TypedValue.NULL, typedValue);
state.setVariable("goo","hello"); state.setVariable("goo", "hello");
assertNull(state.lookupLocalVariable("goo")); assertNull(state.lookupLocalVariable("goo"));
} }
@Test @Test
public void testLocalVariableNestedScopes() { public void testLocalVariableNestedScopes() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(null,state.lookupLocalVariable("foo")); assertEquals(null, state.lookupLocalVariable("foo"));
state.setLocalVariable("foo",12); state.setLocalVariable("foo",12);
assertEquals(12,state.lookupLocalVariable("foo")); assertEquals(12, state.lookupLocalVariable("foo"));
state.enterScope(null); state.enterScope(null);
assertEquals(12,state.lookupLocalVariable("foo")); // found in upper scope assertEquals(12, state.lookupLocalVariable("foo")); // found in upper scope
state.setLocalVariable("foo","abc"); state.setLocalVariable("foo","abc");
assertEquals("abc",state.lookupLocalVariable("foo")); // found in nested scope assertEquals("abc", state.lookupLocalVariable("foo")); // found in nested scope
state.exitScope(); state.exitScope();
assertEquals(12,state.lookupLocalVariable("foo")); // found in nested scope assertEquals(12, state.lookupLocalVariable("foo")); // found in nested scope
} }
@Test @Test
public void testRootContextObject() { public void testRootContextObject() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(Inventor.class,state.getRootContextObject().getValue().getClass()); assertEquals(Inventor.class, state.getRootContextObject().getValue().getClass());
// although the root object is being set on the evaluation context, the value in the 'state' remains what it was when constructed // although the root object is being set on the evaluation context, the value in the 'state' remains what it was when constructed
((StandardEvaluationContext) state.getEvaluationContext()).setRootObject(null); ((StandardEvaluationContext) state.getEvaluationContext()).setRootObject(null);
assertEquals(Inventor.class,state.getRootContextObject().getValue().getClass()); assertEquals(Inventor.class, state.getRootContextObject().getValue().getClass());
// assertEquals(null, state.getRootContextObject().getValue()); // assertEquals(null, state.getRootContextObject().getValue());
state = new ExpressionState(new StandardEvaluationContext()); state = new ExpressionState(new StandardEvaluationContext());
assertEquals(TypedValue.NULL,state.getRootContextObject()); assertEquals(TypedValue.NULL, state.getRootContextObject());
((StandardEvaluationContext)state.getEvaluationContext()).setRootObject(null); ((StandardEvaluationContext) state.getEvaluationContext()).setRootObject(null);
assertEquals(null,state.getRootContextObject().getValue()); assertEquals(null, state.getRootContextObject().getValue());
} }
@Test @Test
public void testActiveContextObject() { public void testActiveContextObject() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue()); assertEquals(state.getRootContextObject().getValue(), state.getActiveContextObject().getValue());
try { try {
state.popActiveContextObject(); state.popActiveContextObject();
fail("stack should be empty..."); fail("stack should be empty...");
} }
catch (EmptyStackException ese) { catch (IllegalStateException ese) {
// success // success
} }
state.pushActiveContextObject(new TypedValue(34)); state.pushActiveContextObject(new TypedValue(34));
assertEquals(34,state.getActiveContextObject().getValue()); assertEquals(34, state.getActiveContextObject().getValue());
state.pushActiveContextObject(new TypedValue("hello")); state.pushActiveContextObject(new TypedValue("hello"));
assertEquals("hello",state.getActiveContextObject().getValue()); assertEquals("hello", state.getActiveContextObject().getValue());
state.popActiveContextObject(); state.popActiveContextObject();
assertEquals(34,state.getActiveContextObject().getValue()); assertEquals(34, state.getActiveContextObject().getValue());
state.popActiveContextObject(); state.popActiveContextObject();
assertEquals(state.getRootContextObject().getValue(),state.getActiveContextObject().getValue()); assertEquals(state.getRootContextObject().getValue(), state.getActiveContextObject().getValue());
state = new ExpressionState(new StandardEvaluationContext()); state = new ExpressionState(new StandardEvaluationContext());
assertEquals(TypedValue.NULL,state.getActiveContextObject()); assertEquals(TypedValue.NULL, state.getActiveContextObject());
} }
@Test @Test
@ -167,14 +167,14 @@ public class ExpressionStateTests extends AbstractExpressionTests {
assertNull(state.lookupLocalVariable("foo")); assertNull(state.lookupLocalVariable("foo"));
state.enterScope("foo",34); state.enterScope("foo",34);
assertEquals(34,state.lookupLocalVariable("foo")); assertEquals(34, state.lookupLocalVariable("foo"));
state.enterScope(null); state.enterScope(null);
state.setLocalVariable("foo",12); state.setLocalVariable("foo", 12);
assertEquals(12,state.lookupLocalVariable("foo")); assertEquals(12, state.lookupLocalVariable("foo"));
state.exitScope(); state.exitScope();
assertEquals(34,state.lookupLocalVariable("foo")); assertEquals(34, state.lookupLocalVariable("foo"));
state.exitScope(); state.exitScope();
assertNull(state.lookupLocalVariable("goo")); assertNull(state.lookupLocalVariable("goo"));
@ -187,8 +187,8 @@ public class ExpressionStateTests extends AbstractExpressionTests {
// supplied should override root on context // supplied should override root on context
ExpressionState state = new ExpressionState(ctx,new TypedValue("i am a string")); ExpressionState state = new ExpressionState(ctx,new TypedValue("i am a string"));
TypedValue stateRoot = state.getRootContextObject(); TypedValue stateRoot = state.getRootContextObject();
assertEquals(String.class,stateRoot.getTypeDescriptor().getType()); assertEquals(String.class, stateRoot.getTypeDescriptor().getType());
assertEquals("i am a string",stateRoot.getValue()); assertEquals("i am a string", stateRoot.getValue());
} }
@Test @Test
@ -198,17 +198,17 @@ public class ExpressionStateTests extends AbstractExpressionTests {
assertNull(state.lookupLocalVariable("goo")); assertNull(state.lookupLocalVariable("goo"));
Map<String,Object> m = new HashMap<>(); Map<String,Object> m = new HashMap<>();
m.put("foo",34); m.put("foo", 34);
m.put("goo","abc"); m.put("goo", "abc");
state.enterScope(m); state.enterScope(m);
assertEquals(34,state.lookupLocalVariable("foo")); assertEquals(34, state.lookupLocalVariable("foo"));
assertEquals("abc",state.lookupLocalVariable("goo")); assertEquals("abc", state.lookupLocalVariable("goo"));
state.enterScope(null); state.enterScope(null);
state.setLocalVariable("foo",12); state.setLocalVariable("foo",12);
assertEquals(12,state.lookupLocalVariable("foo")); assertEquals(12, state.lookupLocalVariable("foo"));
assertEquals("abc",state.lookupLocalVariable("goo")); assertEquals("abc", state.lookupLocalVariable("goo"));
state.exitScope(); state.exitScope();
state.exitScope(); state.exitScope();
@ -217,7 +217,7 @@ public class ExpressionStateTests extends AbstractExpressionTests {
} }
@Test @Test
public void testOperators() throws Exception { public void testOperators() {
ExpressionState state = getState(); ExpressionState state = getState();
try { try {
state.operate(Operation.ADD,1,2); state.operate(Operation.ADD,1,2);
@ -225,7 +225,7 @@ public class ExpressionStateTests extends AbstractExpressionTests {
} }
catch (EvaluationException ee) { catch (EvaluationException ee) {
SpelEvaluationException sEx = (SpelEvaluationException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageCode()); assertEquals(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, sEx.getMessageCode());
} }
try { try {
@ -234,28 +234,28 @@ public class ExpressionStateTests extends AbstractExpressionTests {
} }
catch (EvaluationException ee) { catch (EvaluationException ee) {
SpelEvaluationException sEx = (SpelEvaluationException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES,sEx.getMessageCode()); assertEquals(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, sEx.getMessageCode());
} }
} }
@Test @Test
public void testComparator() { public void testComparator() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getEvaluationContext().getTypeComparator(),state.getTypeComparator()); assertEquals(state.getEvaluationContext().getTypeComparator(), state.getTypeComparator());
} }
@Test @Test
public void testTypeLocator() throws EvaluationException { public void testTypeLocator() throws EvaluationException {
ExpressionState state = getState(); ExpressionState state = getState();
assertNotNull(state.getEvaluationContext().getTypeLocator()); assertNotNull(state.getEvaluationContext().getTypeLocator());
assertEquals(Integer.class,state.findType("java.lang.Integer")); assertEquals(Integer.class, state.findType("java.lang.Integer"));
try { try {
state.findType("someMadeUpName"); state.findType("someMadeUpName");
fail("Should have failed to find it"); fail("Should have failed to find it");
} }
catch (EvaluationException ee) { catch (EvaluationException ee) {
SpelEvaluationException sEx = (SpelEvaluationException)ee; SpelEvaluationException sEx = (SpelEvaluationException)ee;
assertEquals(SpelMessage.TYPE_NOT_FOUND,sEx.getMessageCode()); assertEquals(SpelMessage.TYPE_NOT_FOUND, sEx.getMessageCode());
} }
} }
@ -263,16 +263,16 @@ public class ExpressionStateTests extends AbstractExpressionTests {
public void testTypeConversion() throws EvaluationException { public void testTypeConversion() throws EvaluationException {
ExpressionState state = getState(); ExpressionState state = getState();
String s = (String) state.convertValue(34, TypeDescriptor.valueOf(String.class)); String s = (String) state.convertValue(34, TypeDescriptor.valueOf(String.class));
assertEquals("34",s); assertEquals("34", s);
s = (String)state.convertValue(new TypedValue(34), TypeDescriptor.valueOf(String.class)); s = (String)state.convertValue(new TypedValue(34), TypeDescriptor.valueOf(String.class));
assertEquals("34",s); assertEquals("34", s);
} }
@Test @Test
public void testPropertyAccessors() { public void testPropertyAccessors() {
ExpressionState state = getState(); ExpressionState state = getState();
assertEquals(state.getEvaluationContext().getPropertyAccessors(),state.getPropertyAccessors()); assertEquals(state.getEvaluationContext().getPropertyAccessors(), state.getPropertyAccessors());
} }
/** /**

Loading…
Cancel
Save