From cb9549655c078534db6cd2b7631640e44054e976 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 9 Apr 2016 20:49:22 +0200 Subject: [PATCH] AbstractApplicationContext registers default embedded value resolver Issue: SPR-14140 --- .../config/ConfigurableBeanFactory.java | 9 +++++- .../factory/support/AbstractBeanFactory.java | 7 ++++- .../support/AbstractApplicationContext.java | 13 +++++++++ ...uestHeaderMethodArgumentResolverTests.java | 29 +++++++++++++++---- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java index d04eb15d811..302deec58fa 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 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. @@ -209,6 +209,13 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single */ void addEmbeddedValueResolver(StringValueResolver valueResolver); + /** + * Determine whether an embedded value resolver has been registered with this + * bean factory, to be applied through {@link #resolveEmbeddedValue(String)}. + * @since 4.3 + */ + boolean hasEmbeddedValueResolver(); + /** * Resolve the given embedded value, e.g. an annotation attribute. * @param value the value to resolve diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index d9d80e30b26..638d06ceb16 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -798,6 +798,11 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp this.embeddedValueResolvers.add(valueResolver); } + @Override + public boolean hasEmbeddedValueResolver() { + return !this.embeddedValueResolvers.isEmpty(); + } + @Override public String resolveEmbeddedValue(String value) { String result = value; diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index de9e8c4b8c2..271bbcfaba2 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -78,6 +78,7 @@ import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringValueResolver; /** * Abstract implementation of the {@link org.springframework.context.ApplicationContext} @@ -825,6 +826,18 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } + // Register a default embedded value resolver if no bean post-processor + // (such as a PropertyPlaceholderConfigurer bean) registered any before: + // at this point, primarily for resolution in annotation attribute values. + if (!beanFactory.hasEmbeddedValueResolver()) { + beanFactory.addEmbeddedValueResolver(new StringValueResolver() { + @Override + public String resolveStringValue(String strVal) { + return getEnvironment().resolvePlaceholders(strVal); + } + }); + } + // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java index c8807b61d79..508722aa7ba 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java @@ -51,7 +51,8 @@ public class RequestHeaderMethodArgumentResolverTests { private MethodParameter paramNamedValueStringArray; private MethodParameter paramSystemProperty; private MethodParameter paramContextPath; - private MethodParameter paramResolvedName; + private MethodParameter paramResolvedNameWithExpression; + private MethodParameter paramResolvedNameWithPlaceholder; private MethodParameter paramNamedValueMap; private MockHttpServletRequest servletRequest; @@ -71,8 +72,9 @@ public class RequestHeaderMethodArgumentResolverTests { paramNamedValueStringArray = new SynthesizingMethodParameter(method, 1); paramSystemProperty = new SynthesizingMethodParameter(method, 2); paramContextPath = new SynthesizingMethodParameter(method, 3); - paramResolvedName = new SynthesizingMethodParameter(method, 4); - paramNamedValueMap = new SynthesizingMethodParameter(method, 5); + paramResolvedNameWithExpression = new SynthesizingMethodParameter(method, 4); + paramResolvedNameWithPlaceholder = new SynthesizingMethodParameter(method, 5); + paramNamedValueMap = new SynthesizingMethodParameter(method, 6); servletRequest = new MockHttpServletRequest(); webRequest = new ServletWebRequest(servletRequest, new MockHttpServletResponse()); @@ -135,13 +137,29 @@ public class RequestHeaderMethodArgumentResolverTests { } @Test - public void resolveNameFromSystemProperty() throws Exception { + public void resolveNameFromSystemPropertyThroughExpression() throws Exception { String expected = "foo"; servletRequest.addHeader("bar", expected); System.setProperty("systemProperty", "bar"); try { - Object result = resolver.resolveArgument(paramResolvedName, null, webRequest, null); + Object result = resolver.resolveArgument(paramResolvedNameWithExpression, null, webRequest, null); + assertTrue(result instanceof String); + assertEquals("Invalid result", expected, result); + } + finally { + System.clearProperty("systemProperty"); + } + } + + @Test + public void resolveNameFromSystemPropertyThroughPlaceholder() throws Exception { + String expected = "foo"; + servletRequest.addHeader("bar", expected); + + System.setProperty("systemProperty", "bar"); + try { + Object result = resolver.resolveArgument(paramResolvedNameWithPlaceholder, null, webRequest, null); assertTrue(result instanceof String); assertEquals("Invalid result", expected, result); } @@ -171,6 +189,7 @@ public class RequestHeaderMethodArgumentResolverTests { @RequestHeader(name = "name", defaultValue="#{systemProperties.systemProperty}") String param3, @RequestHeader(name = "name", defaultValue="#{request.contextPath}") String param4, @RequestHeader("#{systemProperties.systemProperty}") String param5, + @RequestHeader("${systemProperty}") String param6, @RequestHeader("name") Map unsupported) { }