JSP EvalTag resolves "@myBeanName" references in expressions against the WebApplicationContext (SPR-7312); for consistency, expressions in an ApplicationContext support the same syntax against the local BeanFactory

This commit is contained in:
Juergen Hoeller 2010-07-12 19:36:26 +00:00
parent d1d5e2d52a
commit 263fabb0fc
6 changed files with 86 additions and 18 deletions

View File

@ -0,0 +1,51 @@
/*
* Copyright 2002-2010 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.expression;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.expression.AccessException;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.util.Assert;
/**
* EL bean resolver that operates against a Spring
* {@link org.springframework.beans.factory.BeanFactory}.
*
* @author Juergen Hoeller
* @since 3.0.4
*/
public class BeanFactoryResolver implements BeanResolver {
private final BeanFactory beanFactory;
public BeanFactoryResolver(BeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
try {
return this.beanFactory.getBean(beanName);
}
catch (BeansException ex) {
throw new AccessException("Could not resolve bean reference against BeanFactory", ex);
}
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 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.
@ -126,6 +126,7 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver {
sec.addPropertyAccessor(new BeanExpressionContextAccessor()); sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor()); sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor()); sec.addPropertyAccessor(new MapAccessor());
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader())); sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
ConversionService conversionService = evalContext.getBeanFactory().getConversionService(); ConversionService conversionService = evalContext.getBeanFactory().getConversionService();
if (conversionService != null) { if (conversionService != null) {

View File

@ -17,20 +17,22 @@
package org.springframework.expression; package org.springframework.expression;
/** /**
* A bean resolver can be registered with the evaluation context and will * A bean resolver can be registered with the evaluation context
* and will kick in for <code>@myBeanName</code> still expressions.
*
* @author Andy Clement * @author Andy Clement
* @since 3.0.3 * @since 3.0.3
*/ */
public interface BeanResolver { public interface BeanResolver {
/** /**
* Lookup the named bean and return it. * Look up the named bean and return it.
* @param context the current evaluation context * @param context the current evaluation context
* @param beanname the name of the bean to lookup * @param beanName the name of the bean to lookup
* @return a object representing the bean * @return an object representing the bean
* @throws AccessException if there is an unexpected problem resolving the named bean * @throws AccessException if there is an unexpected problem resolving the named bean
*/ */
Object resolve(EvaluationContext context, String beanname) throws AccessException; Object resolve(EvaluationContext context, String beanName) throws AccessException;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 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.
@ -33,7 +33,8 @@ import java.util.List;
public interface EvaluationContext { public interface EvaluationContext {
/** /**
* @return the default root context object against which unqualified properties/methods/etc should be resolved. This can be overridden when evaluating an expression. * @return the default root context object against which unqualified properties/methods/etc
* should be resolved. This can be overridden when evaluating an expression.
*/ */
TypedValue getRootObject(); TypedValue getRootObject();
@ -68,13 +69,13 @@ public interface EvaluationContext {
TypeComparator getTypeComparator(); TypeComparator getTypeComparator();
/** /**
* @return an operator overloader that may support mathematical operations between more than the standard set of * @return an operator overloader that may support mathematical operations
* types * between more than the standard set of types
*/ */
OperatorOverloader getOperatorOverloader(); OperatorOverloader getOperatorOverloader();
/** /**
* @return a bean resolver that can lookup named beans * @return a bean resolver that can look up beans by name
*/ */
BeanResolver getBeanResolver(); BeanResolver getBeanResolver();

View File

@ -21,6 +21,7 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext; import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.VariableResolver; import javax.servlet.jsp.el.VariableResolver;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
@ -59,12 +60,6 @@ public class EvalTag extends HtmlEscapingAwareTag {
private boolean javaScriptEscape = false; private boolean javaScriptEscape = false;
@Override
public void setPageContext(PageContext pageContext) {
super.setPageContext(pageContext);
this.evaluationContext = createEvaluationContext(pageContext);
}
/** /**
* Set the expression to evaluate. * Set the expression to evaluate.
*/ */
@ -105,6 +100,9 @@ public class EvalTag extends HtmlEscapingAwareTag {
@Override @Override
public int doEndTag() throws JspException { public int doEndTag() throws JspException {
if (this.evaluationContext == null) {
this.evaluationContext = createEvaluationContext(pageContext);
}
if (this.var == null) { if (this.var == null) {
try { try {
String result = this.expression.getValue(this.evaluationContext, String.class); String result = this.expression.getValue(this.evaluationContext, String.class);
@ -123,10 +121,10 @@ public class EvalTag extends HtmlEscapingAwareTag {
return EVAL_PAGE; return EVAL_PAGE;
} }
private EvaluationContext createEvaluationContext(PageContext pageContext) { private EvaluationContext createEvaluationContext(PageContext pageContext) {
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new JspPropertyAccessor(pageContext)); context.addPropertyAccessor(new JspPropertyAccessor(pageContext));
context.setBeanResolver(new BeanFactoryResolver(getRequestContext().getWebApplicationContext()));
ConversionService conversionService = getConversionService(pageContext); ConversionService conversionService = getConversionService(pageContext);
if (conversionService != null) { if (conversionService != null) {
context.setTypeConverter(new StandardTypeConverter(conversionService)); context.setTypeConverter(new StandardTypeConverter(conversionService));

View File

@ -19,11 +19,13 @@ package org.springframework.web.servlet.tags;
import java.math.BigDecimal; import java.math.BigDecimal;
import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.Tag;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.format.annotation.NumberFormat; import org.springframework.format.annotation.NumberFormat;
import org.springframework.format.annotation.NumberFormat.Style; import org.springframework.format.annotation.NumberFormat.Style;
import org.springframework.format.support.FormattingConversionServiceFactoryBean; import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockPageContext; import org.springframework.mock.web.MockPageContext;
import org.springframework.web.servlet.DispatcherServlet;
/** /**
* @author Keith Donald * @author Keith Donald
@ -103,6 +105,19 @@ public class EvalTagTests extends AbstractTagTests {
assertEquals("not the bean object", context.getAttribute("foo")); assertEquals("not the bean object", context.getAttribute("foo"));
} }
public void testAccessUsingBeanSyntax() throws Exception {
GenericApplicationContext wac = (GenericApplicationContext)
context.getRequest().getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
wac.getDefaultListableBeanFactory().registerSingleton("bean2", context.getRequest().getAttribute("bean"));
tag.setExpression("@bean2.bean");
tag.setVar("foo");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("not the bean object", context.getAttribute("foo"));
}
public static class Bean { public static class Bean {