Use ServletWrappingController for jolokia instead of Servlet

We get more control over the handling and in particular the registration
of the endpoint this way. It was practically impossible to disable the
AgentServlet bean when in a parent context of the management server
because of lifecyce issues - you don't know that the user wants a
separate management server until too late.

This approach also makes it possible to test with spring-test MVC
support.
This commit is contained in:
Dave Syer 2013-12-19 14:27:36 +00:00
parent 210e1f3a6b
commit fa507005cd
15 changed files with 240 additions and 109 deletions

View File

@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint;
@ -85,8 +86,14 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
private ApplicationContext applicationContext;
@Autowired(required = false)
private ManagementServerProperties managementServerProperties = new ManagementServerProperties();
@Autowired
private ManagementServerProperties managementServerProperties;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Bean
@ConditionalOnMissingBean
@ -98,12 +105,6 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
return mapping;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.applicationContext) {
@ -114,18 +115,23 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
}
}
@Bean
public Filter applicationContextIdFilter(ApplicationContext context) {
final String id = context.getId();
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("X-Application-Context", id);
filterChain.doFilter(request, response);
}
};
// Put Servlets and Filters in their own nested class so they don't force early
// instantiation of ManagementServerProperties.
@Configuration
protected static class ApplicationContextFilterConfiguration {
@Bean
public Filter applicationContextIdFilter(ApplicationContext context) {
final String id = context.getId();
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("X-Application-Context", id);
filterChain.doFilter(request, response);
}
};
}
}
@Bean
@ -181,11 +187,11 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
childContext.refresh();
}
private enum ManagementServerPort {
protected static enum ManagementServerPort {
DISABLE, SAME, DIFFERENT;
public static ManagementServerPort get(ApplicationContext beanFactory) {
public static ManagementServerPort get(BeanFactory beanFactory) {
ServerProperties serverProperties;
try {
@ -208,7 +214,7 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
return DISABLE;
}
if (!(beanFactory instanceof WebApplicationContext)) {
// Current context is no a a webapp
// Current context is not a webapp
return DIFFERENT;
}
return managementServerProperties.getPort() == null

View File

@ -17,23 +17,20 @@
package org.springframework.boot.actuate.autoconfigure;
import java.util.Map;
import java.util.Properties;
import org.jolokia.http.AgentServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@ -54,11 +51,11 @@ import org.springframework.core.env.Environment;
* supported configuration parameters.
*
* @author Christian Dupuis
* @author Dave Syer
*/
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ AgentServlet.class })
@ConditionalOnBean(EmbeddedServletContainerFactory.class)
@AutoConfigureBefore(ManagementSecurityAutoConfiguration.class)
@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)
@ConditionalOnExpression("${endpoints.jolokia.enabled:true}")
@ -66,40 +63,28 @@ public class JolokiaAutoConfiguration {
private RelaxedPropertyResolver environment;
@Autowired
private ManagementServerProperties management;
@Autowired
public void setEnvironment(Environment environment) {
this.environment = new RelaxedPropertyResolver(environment);
}
@Bean
@ConditionalOnMissingBean({ AgentServlet.class })
public AgentServlet jolokiaServlet() {
return new AgentServlet();
}
@Bean
public ServletRegistrationBean jolokiaServletRegistration(AgentServlet servlet) {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet,
this.management.getContextPath() + jolokiaEndpoint().getPath() + "/*");
addInitParameters(registrationBean);
return registrationBean;
}
@Bean
@ConditionalOnMissingBean
public JolokiaMvcEndpoint jolokiaEndpoint() {
return new JolokiaMvcEndpoint();
JolokiaMvcEndpoint endpoint = new JolokiaMvcEndpoint();
endpoint.setInitParameters(getInitParameters());
return endpoint;
}
protected void addInitParameters(ServletRegistrationBean registrationBean) {
private Properties getInitParameters() {
Properties properties = new Properties();
Map<String, Object> configParameters = this.environment
.getSubProperties("jolokia.config.");
for (Map.Entry<String, Object> configParameter : configParameters.entrySet()) {
registrationBean.addInitParameter(configParameter.getKey(), configParameter
.getValue().toString());
properties.setProperty(configParameter.getKey(), configParameter.getValue()
.toString());
}
return properties;
}
}

View File

@ -16,11 +16,26 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.jolokia.http.AgentServlet;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ServletWrappingController;
/**
* {@link Endpoint} implementation to register the Jolokia infrastructure with the Boot
@ -29,7 +44,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Christian Dupuis
*/
@ConfigurationProperties(name = "endpoints.jolokia", ignoreUnknownFields = false)
public class JolokiaMvcEndpoint implements MvcEndpoint {
public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean,
ApplicationContextAware, ServletContextAware {
@NotNull
@Pattern(regexp = "/[^/]*", message = "Path must start with /")
@ -39,8 +55,30 @@ public class JolokiaMvcEndpoint implements MvcEndpoint {
private boolean enabled = true;
private ServletWrappingController controller = new ServletWrappingController();
public JolokiaMvcEndpoint() {
this.path = "/jolokia";
this.controller.setServletClass(AgentServlet.class);
this.controller.setServletName("jolokia");
}
@Override
public void afterPropertiesSet() throws Exception {
this.controller.afterPropertiesSet();
}
public void setServletContext(ServletContext servletContext) {
this.controller.setServletContext(servletContext);
}
public void setInitParameters(Properties initParameters) {
this.controller.setInitParameters(initParameters);
}
public final void setApplicationContext(ApplicationContext context)
throws BeansException {
this.controller.setApplicationContext(context);
}
public boolean isEnabled() {
@ -74,4 +112,37 @@ public class JolokiaMvcEndpoint implements MvcEndpoint {
return null;
}
@RequestMapping("/**")
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
return this.controller.handleRequest(new PathStripper(request, getPath()),
response);
}
private static class PathStripper extends HttpServletRequestWrapper {
private String path;
public PathStripper(HttpServletRequest request, String path) {
super(request);
this.path = path;
}
@Override
public String getPathInfo() {
String value = super.getRequestURI();
if (value.startsWith(this.path)) {
value = value.substring(this.path.length());
}
int index = value.indexOf("?");
if (index > 0) {
value = value.substring(0, index);
}
while (value.startsWith("/")) {
value = value.substring(1);
}
return value;
}
}
}

View File

@ -4,8 +4,8 @@ org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ErrorMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ErrorMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\

View File

@ -16,26 +16,21 @@
package org.springframework.boot.actuate.autoconfigure;
import javax.servlet.Servlet;
import javax.servlet.ServletRegistration;
import org.jolokia.http.AgentServlet;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFactory.RegisteredServlet;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Tests for {@link JolokiaAutoConfiguration}.
@ -64,7 +59,7 @@ public class JolokiaAutoConfigurationTests {
HttpMessageConvertersAutoConfiguration.class,
JolokiaAutoConfiguration.class);
this.context.refresh();
assertEquals(1, this.context.getBeanNamesForType(AgentServlet.class).length);
assertEquals(1, this.context.getBeanNamesForType(JolokiaMvcEndpoint.class).length);
}
@Test
@ -76,29 +71,7 @@ public class JolokiaAutoConfigurationTests {
HttpMessageConvertersAutoConfiguration.class,
JolokiaAutoConfiguration.class);
this.context.refresh();
assertEquals(0, this.context.getBeanNamesForType(AgentServlet.class).length);
}
@Test
public void agentServletRegisteredWithServletContainer() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
this.context.register(Config.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
JolokiaAutoConfiguration.class);
this.context.refresh();
Servlet servlet = null;
ServletRegistration.Dynamic registration = null;
for (RegisteredServlet registeredServlet : Config.containerFactory.getContainer()
.getRegisteredServlets()) {
if (registeredServlet.getServlet() instanceof AgentServlet) {
servlet = registeredServlet.getServlet();
registration = registeredServlet.getRegistration();
}
}
assertNotNull(servlet);
assertNotNull(registration);
assertEquals(0, this.context.getBeanNamesForType(JolokiaMvcEndpoint.class).length);
}
@Configuration

View File

@ -22,6 +22,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpointTests.TestConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
@ -73,7 +74,8 @@ public class EnvironmentMvcEndpointTests {
.andExpect(content().string(equalToIgnoringCase("bar")));
}
@Import(EndpointWebMvcAutoConfiguration.class)
@Import({ EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class })
@EnableWebMvc
@Configuration
public static class TestConfiguration {

View File

@ -16,21 +16,35 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.TestUtils;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.mvc.JolokiaEndpointTests.Config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author Christian Dupuis
@ -44,21 +58,49 @@ public class JolokiaEndpointTests {
@Autowired
private MvcEndpoints endpoints;
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
TestUtils.addEnviroment((ConfigurableApplicationContext) this.context, "foo:bar");
}
@Test
public void endpointRegistered() throws Exception {
assertEquals(1, this.endpoints.getEndpoints().size());
Set<? extends MvcEndpoint> values = this.endpoints.getEndpoints();
assertEquals(1, values.size());
assertTrue(values.iterator().next() instanceof JolokiaMvcEndpoint);
}
@Test
public void search() throws Exception {
this.mvc.perform(get("/jolokia/search/java.lang:*")).andExpect(status().isOk())
.andExpect(content().string(containsString("GarbageCollector")));
}
@Test
public void read() throws Exception {
this.mvc.perform(get("/jolokia/read/java.lang:type=Memory"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("NonHeapMemoryUsage")));
}
@Test
public void list() throws Exception {
this.mvc.perform(get("/jolokia/list/java.lang/type=Memory/attr"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("NonHeapMemoryUsage")));
}
@Configuration
@EnableConfigurationProperties
@EnableWebMvc
@Import(EndpointWebMvcAutoConfiguration.class)
@Import({ EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class })
public static class Config {
@Bean
public JolokiaMvcEndpoint endpoint() {
return new JolokiaMvcEndpoint();
}
}
}

View File

@ -112,7 +112,6 @@ public class BasicErrorControllerSpecialIntegrationTests {
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class })
protected static class ChildConfiguration {
// For manual testing
public static void main(String[] args) {
new SpringApplicationBuilder(ParentConfiguration.class).child(

View File

@ -139,12 +139,13 @@ public class MultipartAutoConfigurationTests {
}
@Test
public void containerWithAutomatedMultipartTomcatConfiguration() {
public void containerWithAutomatedMultipartTomcatConfiguration() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithEverythingTomcat.class,
EmbeddedServletContainerAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
MultipartAutoConfiguration.class);
new RestTemplate().getForObject("http://localhost:8080/", String.class);
this.context.getBean(MultipartConfigElement.class);
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),
this.context.getBean(StandardServletMultipartResolver.class));

View File

@ -36,6 +36,10 @@
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -249,23 +249,30 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
customizeBinder(dataBinder);
Set<String> names = new HashSet<String>();
Set<String> patterns = new HashSet<String>();
if (this.target != null) {
PropertyDescriptor[] descriptors = BeanUtils
.getPropertyDescriptors(this.target.getClass());
String[] prefixes = this.targetName != null ? new String[] {
this.targetName + ".", this.targetName + "_" } : new String[] { "" };
String[] suffixes = new String[] { ".*", "_*" };
for (PropertyDescriptor descriptor : descriptors) {
String name = descriptor.getName();
if (!name.equals("class")) {
names.add(name);
names.add(name + ".*");
names.add(name + "_*");
names.add("*_"+name);
for (String prefix : prefixes) {
names.add(prefix + name);
patterns.add(prefix + name);
for (String suffix : suffixes) {
patterns.add(prefix + name + suffix);
}
}
}
}
}
PropertyValues propertyValues = (this.properties != null ? new MutablePropertyValues(
this.properties) : new PropertySourcesPropertyValues(
this.propertySources, names));
this.propertySources, patterns, names));
dataBinder.bind(propertyValues);
if (this.validator != null) {

View File

@ -45,37 +45,39 @@ public class PropertySourcesPropertyValues implements PropertyValues {
private PropertySources propertySources;
private Collection<String> NON_ENUMERABLES = Arrays.asList(
private Collection<String> NON_ENUMERABLE_ENUMERABLES = Arrays.asList(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);;
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
/**
* Create a new PropertyValues from the given PropertySources
* @param propertySources a PropertySources instance
*/
public PropertySourcesPropertyValues(PropertySources propertySources) {
this(propertySources, null);
this(propertySources, null, null);
}
/**
* Create a new PropertyValues from the given PropertySources
* @param propertySources a PropertySources instance
* @param systemPropertyNames property names to include from system properties and
* @param patterns property name patterns to include from system properties and
* environment variables
* @param names exact property names to include
*/
public PropertySourcesPropertyValues(PropertySources propertySources,
Collection<String> systemPropertyNames) {
Collection<String> patterns, Collection<String> names) {
this.propertySources = propertySources;
PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
propertySources);
String[] includes = systemPropertyNames == null ? new String[0]
: systemPropertyNames.toArray(new String[0]);
String[] includes = patterns == null ? new String[0] : patterns
.toArray(new String[0]);
String[] exacts = names == null ? new String[0] : names.toArray(new String[0]);
for (PropertySource<?> source : propertySources) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
if (enumerable.getPropertyNames().length > 0) {
for (String propertyName : enumerable.getPropertyNames()) {
if (this.NON_ENUMERABLES.contains(source.getName())
if (this.NON_ENUMERABLE_ENUMERABLES.contains(source.getName())
&& !PatternMatchUtils.simpleMatch(includes, propertyName)) {
continue;
}
@ -91,6 +93,25 @@ public class PropertySourcesPropertyValues implements PropertyValues {
}
}
}
else {
// We can only do exact matches for non-enumerable property names, but
// that's better than nothing...
for (String propertyName : exacts) {
Object value;
value = source.getProperty(propertyName);
if (value != null) {
this.propertyValues.put(propertyName, new PropertyValue(
propertyName, value));
continue;
}
value = source.getProperty(propertyName.toUpperCase());
if (value != null) {
this.propertyValues.put(propertyName, new PropertyValue(
propertyName, value));
continue;
}
}
}
}
}

View File

@ -52,7 +52,7 @@ public class ServletRegistrationBean extends RegistrationBean {
private Set<String> urlMappings = new LinkedHashSet<String>();
private int loadOnStartup = 1;
private int loadOnStartup = -1;
private MultipartConfigElement multipartConfig;

View File

@ -90,6 +90,15 @@ public class PropertySourcesPropertyValuesTests {
assertEquals("bar", target.getName());
}
@Test
public void testPlaceholdersBindingNonEnumerable() {
FooBean target = new FooBean();
DataBinder binder = new DataBinder(target);
binder.bind(new PropertySourcesPropertyValues(this.propertySources, null,
Collections.singleton("foo")));
assertEquals("bar", target.getFoo());
}
@Test
public void testPlaceholdersBindingWithError() {
TestBean target = new TestBean();
@ -112,4 +121,16 @@ public class PropertySourcesPropertyValuesTests {
}
}
public static class FooBean {
private String foo;
public String getFoo() {
return this.foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
}

View File

@ -88,8 +88,7 @@ public class SpringApplicationContextLoader extends AbstractContextLoader {
private Map<String, Object> getArgs(MergedContextConfiguration mergedConfig) {
Map<String, Object> args = new LinkedHashMap<String, Object>();
// Not running an embedded server, just setting up web context
args.put("server.port", "0");
args.put("management.port", "0");
args.put("server.port", "-1");
return args;
}