diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index 16c3ffd0a6..acc8d78970 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -17,10 +17,6 @@ package org.springframework.boot.actuate.autoconfigure; import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.util.List; import javax.servlet.Filter; @@ -38,6 +34,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties.Security; +import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.HealthEndpoint; @@ -53,17 +50,14 @@ import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; -import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; import org.springframework.boot.context.embedded.EmbeddedServletContainerException; import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext; @@ -73,14 +67,10 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextClosedEvent; -import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; -import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.servlet.DispatcherServlet; @@ -347,78 +337,4 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, } - /** - * {@link Conditional} that checks whether or not an endpoint is enabled. Matches if - * the value of the {@code endpoints..enabled} property is {@code true}. Does - * not match if the property's value or {@code enabledByDefault} is {@code false}. - * Otherwise, matches if the value of the {@code endpoints.enabled} property is - * {@code true} or if the property is not configured. - * - * @since 1.2.4 - */ - @Conditional(OnEnabledEndpointCondition.class) - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public static @interface ConditionalOnEnabledEndpoint { - - /** - * The name of the endpoint. - * @return The name of the endpoint - */ - public String value(); - - /** - * Returns whether or not the endpoint is enabled by default. - * @return {@code true} if the endpoint is enabled by default, otherwise - * {@code false} - */ - public boolean enabledByDefault() default true; - - } - - private static class OnEnabledEndpointCondition extends SpringBootCondition { - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - AnnotationAttributes annotationAttributes = AnnotationAttributes - .fromMap(metadata - .getAnnotationAttributes(ConditionalOnEnabledEndpoint.class - .getName())); - String endpointName = annotationAttributes.getString("value"); - boolean enabledByDefault = annotationAttributes - .getBoolean("enabledByDefault"); - ConditionOutcome specificEndpointOutcome = determineSpecificEndpointOutcome( - endpointName, enabledByDefault, context); - if (specificEndpointOutcome != null) { - return specificEndpointOutcome; - } - return determineAllEndpointsOutcome(context); - - } - - private ConditionOutcome determineSpecificEndpointOutcome(String endpointName, - boolean enabledByDefault, ConditionContext context) { - RelaxedPropertyResolver endpointPropertyResolver = new RelaxedPropertyResolver( - context.getEnvironment(), "endpoints." + endpointName + "."); - if (endpointPropertyResolver.containsProperty("enabled") || !enabledByDefault) { - boolean match = endpointPropertyResolver.getProperty("enabled", - Boolean.class, enabledByDefault); - return new ConditionOutcome(match, "The " + endpointName + " is " - + (match ? "enabled" : "disabled")); - } - return null; - } - - private ConditionOutcome determineAllEndpointsOutcome(ConditionContext context) { - RelaxedPropertyResolver allEndpointsPropertyResolver = new RelaxedPropertyResolver( - context.getEnvironment(), "endpoints."); - boolean match = Boolean.valueOf(allEndpointsPropertyResolver.getProperty( - "enabled", "true")); - return new ConditionOutcome(match, "All endpoints are " - + (match ? "enabled" : "disabled") + " by default"); - } - - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java index b7f4c9a3ba..e29e6e7f82 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java @@ -135,14 +135,12 @@ public class MetricFilterAutoConfiguration { } private boolean is4xxClientError(int status) { - HttpStatus httpStatus = HttpStatus.OK; try { - httpStatus = HttpStatus.valueOf(status); + return HttpStatus.valueOf(status).is4xxClientError(); } catch (Exception ex) { - // not convertible + return false; } - return httpStatus.is4xxClientError(); } private String getKey(String string) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java new file mode 100644 index 0000000000..2c2aa1da1a --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/ConditionalOnEnabledEndpoint.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2015 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.boot.actuate.condition; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that checks whether or not an endpoint is enabled. Matches if the + * value of the {@code endpoints..enabled} property is {@code true}. Does not match + * if the property's value or {@code enabledByDefault} is {@code false}. Otherwise, + * matches if the value of the {@code endpoints.enabled} property is {@code true} or if + * the property is not configured. + * + * @author Andy Wilkinson + * @since 1.2.4 + */ +@Conditional(OnEnabledEndpointCondition.class) +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ConditionalOnEnabledEndpoint { + + /** + * The name of the endpoint. + * @return The name of the endpoint + */ + public String value(); + + /** + * Returns whether or not the endpoint is enabled by default. + * @return {@code true} if the endpoint is enabled by default, otherwise {@code false} + */ + public boolean enabledByDefault() default true; + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java new file mode 100644 index 0000000000..89c1d9fb43 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/OnEnabledEndpointCondition.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2015 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.boot.actuate.condition; + +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link Condition} that checks whether or not an endpoint is enabled. + * + * @author Andy Wilkinson + */ +class OnEnabledEndpointCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata + .getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName())); + String endpointName = annotationAttributes.getString("value"); + boolean enabledByDefault = annotationAttributes.getBoolean("enabledByDefault"); + ConditionOutcome outcome = determineEndpointOutcome(endpointName, + enabledByDefault, context); + if (outcome != null) { + return outcome; + } + return determineAllEndpointsOutcome(context); + } + + private ConditionOutcome determineEndpointOutcome(String endpointName, + boolean enabledByDefault, ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), "endpoints." + endpointName + "."); + if (resolver.containsProperty("enabled") || !enabledByDefault) { + boolean match = resolver.getProperty("enabled", Boolean.class, + enabledByDefault); + return new ConditionOutcome(match, "The " + endpointName + " is " + + (match ? "enabled" : "disabled")); + } + return null; + } + + private ConditionOutcome determineAllEndpointsOutcome(ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), "endpoints."); + boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); + return new ConditionOutcome(match, "All endpoints are " + + (match ? "enabled" : "disabled") + " by default"); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java new file mode 100644 index 0000000000..00e6974da4 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/condition/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2015 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. + */ + +/** + * {@code @Condition} annotations and supporting classes. + */ +package org.springframework.boot.actuate.condition; \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index b1eb293dd7..947bf8995c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -324,9 +324,7 @@ public class ConfigurationPropertiesReportEndpoint extends private boolean isReadable(BeanDescription beanDesc, BeanPropertyWriter writer) { String parentType = beanDesc.getType().getRawClass().getName(); String type = writer.getPropertyType().getName(); - AnnotatedMethod setter = beanDesc.findMethod( - "set" + StringUtils.capitalize(writer.getName()), - new Class[] { writer.getPropertyType() }); + AnnotatedMethod setter = findSetter(beanDesc, writer); // If there's a setter, we assume it's OK to report on the value, // similarly, if there's no setter but the package names match, we assume // that its a nested class used solely for binding to config props, so it @@ -336,6 +334,19 @@ public class ConfigurationPropertiesReportEndpoint extends || ClassUtils.getPackageName(parentType).equals( ClassUtils.getPackageName(type)); } + + private AnnotatedMethod findSetter(BeanDescription beanDesc, + BeanPropertyWriter writer) { + String name = "set" + StringUtils.capitalize(writer.getName()); + Class type = writer.getPropertyType(); + AnnotatedMethod setter = beanDesc.findMethod(name, new Class[] { type }); + // The enabled property of endpoints returns a boolean primitive but is set + // using a Boolean class + if (setter == null && type.equals(Boolean.TYPE)) { + setter = beanDesc.findMethod(name, new Class[] { Boolean.class }); + } + return setter; + } } /** diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfigurationTests.java index 14cfd1e42f..4097b46669 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfigurationTests.java @@ -44,11 +44,11 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.FilterChainProxy; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.util.StringUtils; -import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.hamcrest.Matchers.greaterThan; @@ -209,44 +209,36 @@ public class ManagementSecurityAutoConfigurationTests { PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); - MockMvc mockMvc = MockMvcBuilders - .webAppContextSetup((WebApplicationContext) this.context) - .addFilters( - this.context.getBean("springSecurityFilterChain", Filter.class)) - .build(); - + Filter filter = this.context.getBean("springSecurityFilterChain", Filter.class); + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .addFilters(filter).build(); // no user (Main) - mockMvc.perform( - MockMvcRequestBuilders.get("/")) + mockMvc.perform(MockMvcRequestBuilders.get("/")) .andExpect(MockMvcResultMatchers.status().isUnauthorized()) - .andExpect( - MockMvcResultMatchers.header().string("www-authenticate", - Matchers.containsString("realm=\"Spring\""))); + .andExpect(springAuthenticateRealmHeader()); // invalid user (Main) mockMvc.perform( MockMvcRequestBuilders.get("/").header("authorization", "Basic xxx")) .andExpect(MockMvcResultMatchers.status().isUnauthorized()) - .andExpect( - MockMvcResultMatchers.header().string("www-authenticate", - Matchers.containsString("realm=\"Spring\""))); + .andExpect(springAuthenticateRealmHeader()); // no user (Management) - mockMvc.perform( - MockMvcRequestBuilders.get("/beans")) + mockMvc.perform(MockMvcRequestBuilders.get("/beans")) .andExpect(MockMvcResultMatchers.status().isUnauthorized()) - .andExpect( - MockMvcResultMatchers.header().string("www-authenticate", - Matchers.containsString("realm=\"Spring\""))); + .andExpect(springAuthenticateRealmHeader()); // invalid user (Management) mockMvc.perform( MockMvcRequestBuilders.get("/beans").header("authorization", "Basic xxx")) .andExpect(MockMvcResultMatchers.status().isUnauthorized()) - .andExpect( - MockMvcResultMatchers.header().string("www-authenticate", - Matchers.containsString("realm=\"Spring\""))); + .andExpect(springAuthenticateRealmHeader()); + } + + private ResultMatcher springAuthenticateRealmHeader() { + return MockMvcResultMatchers.header().string("www-authenticate", + Matchers.containsString("realm=\"Spring\"")); } @EnableGlobalAuthentication @@ -254,9 +246,8 @@ public class ManagementSecurityAutoConfigurationTests { static class AuthenticationConfig { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); + auth.inMemoryAuthentication().withUser("user").password("password") + .roles("USER"); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java index 87e2cf0d05..11cf9eaae2 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java @@ -26,6 +26,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -151,6 +152,17 @@ public class ConfigurationPropertiesReportEndpointTests extends assertEquals("******", nestedProperties.get("myTestProperty")); } + @Test + @SuppressWarnings("unchecked") + public void mixedBoolean() throws Exception { + ConfigurationPropertiesReportEndpoint report = getEndpointBean(); + Map properties = report.invoke(); + Map nestedProperties = (Map) ((Map) properties + .get("testProperties")).get("properties"); + System.out.println(nestedProperties); + assertThat(nestedProperties.get("mixedBoolean"), equalTo((Object) true)); + } + @Configuration @EnableConfigurationProperties public static class Parent { @@ -183,6 +195,8 @@ public class ConfigurationPropertiesReportEndpointTests extends private String myTestProperty = "654321"; + private Boolean mixedBoolean = true; + public String getDbPassword() { return this.dbPassword; } @@ -199,5 +213,13 @@ public class ConfigurationPropertiesReportEndpointTests extends this.myTestProperty = myTestProperty; } + public boolean isMixedBoolean() { + return (this.mixedBoolean == null ? false : this.mixedBoolean); + } + + public void setMixedBoolean(Boolean mixedBoolean) { + this.mixedBoolean = mixedBoolean; + } + } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java index 013991b20f..96fe2b20bc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java @@ -116,26 +116,14 @@ abstract class BeanTypeRegistry { definition.getFactoryMethodName()); Class generic = ResolvableType.forMethodReturnType(method) .as(FactoryBean.class).resolveGeneric(); - if (generic == null || generic.equals(Object.class)) { - generic = determineTypeFromDefinitionAttribute(factoryDefinition); + if ((generic == null || generic.equals(Object.class)) + && definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) { + generic = getTypeFromAttribute(definition + .getAttribute(FACTORY_BEAN_OBJECT_TYPE)); } return generic; } - private Class determineTypeFromDefinitionAttribute(BeanDefinition definition) - throws ClassNotFoundException, LinkageError { - if (definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) { - Object attributeObject = definition.getAttribute(FACTORY_BEAN_OBJECT_TYPE); - if (attributeObject instanceof Class) { - return (Class) attributeObject; - } - else if (attributeObject instanceof String) { - return ClassUtils.forName((String) attributeObject, null); - } - } - return Object.class; - } - private Class getDirectFactoryBeanGeneric( ConfigurableListableBeanFactory beanFactory, BeanDefinition definition, String name) throws ClassNotFoundException, LinkageError { @@ -143,12 +131,25 @@ abstract class BeanTypeRegistry { beanFactory.getBeanClassLoader()); Class generic = ResolvableType.forClass(factoryBeanClass) .as(FactoryBean.class).resolveGeneric(); - if (generic == null || generic.equals(Object.class)) { - generic = determineTypeFromDefinitionAttribute(definition); + if ((generic == null || generic.equals(Object.class)) + && definition.hasAttribute(FACTORY_BEAN_OBJECT_TYPE)) { + generic = getTypeFromAttribute(definition + .getAttribute(FACTORY_BEAN_OBJECT_TYPE)); } return generic; } + private Class getTypeFromAttribute(Object attribute) + throws ClassNotFoundException, LinkageError { + if (attribute instanceof Class) { + return (Class) attribute; + } + if (attribute instanceof String) { + return ClassUtils.forName((String) attribute, null); + } + return null; + } + /** * Factory method to get the {@link BeanTypeRegistry} for a given {@link BeanFactory}. * @param beanFactory the source bean factory diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java index 1b238d6af7..a180db2707 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java @@ -163,7 +163,7 @@ public class GzipFilterProperties { } public List getExcludedMimeTypes() { - return excludedMimeTypes; + return this.excludedMimeTypes; } public void setExcludedMimeTypes(List excludedMimeTypes) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchRepositoriesAutoConfigurationTests.java index 2c0ca346a5..537d9ad0a3 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchRepositoriesAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -51,9 +51,7 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { @Test public void testDefaultRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.elasticsearch.properties.path.data:target/data", - "spring.data.elasticsearch.properties.path.logs:target/logs"); + addElasticsearchProperties(this.context); this.context.register(TestConfiguration.class, ElasticsearchAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class, @@ -67,9 +65,7 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { @Test public void testNoRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.elasticsearch.properties.path.data:target/data", - "spring.data.elasticsearch.properties.path.logs:target/logs"); + addElasticsearchProperties(this.context); this.context.register(EmptyConfiguration.class, ElasticsearchAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class, @@ -82,9 +78,7 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.elasticsearch.properties.path.data:target/data", - "spring.data.elasticsearch.properties.path.logs:target/logs"); + addElasticsearchProperties(this.context); this.context.register(CustomizedConfiguration.class, ElasticsearchAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class, @@ -94,6 +88,12 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { assertNotNull(this.context.getBean(CityElasticsearchDbRepository.class)); } + private void addElasticsearchProperties(AnnotationConfigApplicationContext context) { + EnvironmentTestUtils.addEnvironment(context, + "spring.data.elasticsearch.properties.path.data:target/data", + "spring.data.elasticsearch.properties.path.logs:target/logs"); + } + @Configuration @TestAutoConfigurationPackage(City.class) protected static class TestConfiguration { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchAutoConfigurationTests.java index 33660ad358..80452211f1 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchDataAutoConfigurationTests.java index 361c13abb5..53f9d2899b 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchDataAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -54,4 +54,5 @@ public class ElasticsearchDataAutoConfigurationTests { assertEquals(1, this.context.getBeanNamesForType(ElasticsearchTemplate.class).length); } + } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java index 3c11166c80..3d59cadebd 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java @@ -34,6 +34,7 @@ import org.springframework.boot.loader.tools.RunProcess; class RunProcessCommand extends AbstractCommand { private final String[] command; + private volatile RunProcess process; public RunProcessCommand(String... command) { diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 955f94402c..609a483d58 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -71,7 +71,7 @@ 1.12 2.4.3 2.3.1 - 1.4.185 + 1.4.187 1.3 3.4.2 4.3.10.Final @@ -1876,4 +1876,4 @@ integration-test - \ No newline at end of file + diff --git a/spring-boot-samples/spring-boot-sample-data-elasticsearch/src/test/java/sample/data/elasticsearch/SampleElasticsearchApplicationTests.java b/spring-boot-samples/spring-boot-sample-data-elasticsearch/src/test/java/sample/data/elasticsearch/SampleElasticsearchApplicationTests.java index ac626eb34d..da1f9ca345 100644 --- a/spring-boot-samples/spring-boot-sample-data-elasticsearch/src/test/java/sample/data/elasticsearch/SampleElasticsearchApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-data-elasticsearch/src/test/java/sample/data/elasticsearch/SampleElasticsearchApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -33,6 +33,10 @@ import static org.junit.Assert.assertTrue; */ public class SampleElasticsearchApplicationTests { + private static final String[] PROPERTIES = { + "spring.data.elasticsearch.properties.path.data:target/data", + "spring.data.elasticsearch.properties.path.logs:target/logs" }; + @Rule public OutputCapture outputCapture = new OutputCapture(); @@ -40,10 +44,7 @@ public class SampleElasticsearchApplicationTests { public void testDefaultSettings() throws Exception { try { new SpringApplicationBuilder(SampleElasticsearchApplication.class) - .properties( - "spring.data.elasticsearch.properties.path.data:target/data", - "spring.data.elasticsearch.properties.path.logs:target/logs") - .run(); + .properties(PROPERTIES).run(); } catch (IllegalStateException ex) { if (serverNotRunning(ex)) { diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java index 5f79d25f52..adc3bde0b2 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntryData.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. @@ -19,6 +19,7 @@ package org.springframework.boot.loader.jar; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; +import java.util.Calendar; import java.util.GregorianCalendar; import java.util.zip.ZipEntry; @@ -31,6 +32,7 @@ import org.springframework.boot.loader.util.AsciiBytes; * the entry is actually needed. * * @author Phillip Webb + * @author Andy Wilkinson */ public final class JarEntryData { @@ -146,20 +148,27 @@ public final class JarEntryData { } public long getTime() { - long time = Bytes.littleEndianValue(this.header, 12, 2); - - int seconds = (int) ((time << 1) & 0x3E); - int minutes = (int) ((time >> 5) & 0x3F); - int hours = (int) ((time >> 11) & 0x1F); - long date = Bytes.littleEndianValue(this.header, 14, 2); + long time = Bytes.littleEndianValue(this.header, 12, 2); + return decodeMsDosFormatDateTime(date, time).getTimeInMillis(); + } - int day = (int) (date & 0x1F); - int month = (int) ((date >> 5) & 0xF) - 1; + /** + * Decode MSDOS Date Time details. See mindprod.com/jgloss/zip.html for + * more details of the format. + * @param date the date part + * @param time the time part + * @return a {@link Calendar} containing the decoded date. + */ + private Calendar decodeMsDosFormatDateTime(long date, long time) { int year = (int) ((date >> 9) & 0x7F) + 1980; - - return new GregorianCalendar(year, month, day, hours, minutes, seconds) - .getTimeInMillis(); + int month = (int) ((date >> 5) & 0xF) - 1; + int day = (int) (date & 0x1F); + int hours = (int) ((time >> 11) & 0x1F); + int minutes = (int) ((time >> 5) & 0x3F); + int seconds = (int) ((time << 1) & 0x3E); + return new GregorianCalendar(year, month, day, hours, minutes, seconds); } public long getCrc() { diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java index 3b59869c2b..dfbbb7149a 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 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. diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java index 83a87a8b85..ec13ad1a32 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/PropertySourcesPropertyValues.java @@ -121,16 +121,7 @@ public class PropertySourcesPropertyValues implements PropertyValues { .contains(source.getName()) && !includes.matches(propertyName)) { continue; } - Object value = null; - try { - value = resolver.getProperty(propertyName, Object.class); - } - catch (RuntimeException ex) { - // Probably could not resolve placeholders, ignore it here - if (value == null) { - value = source.getProperty(propertyName); - } - } + Object value = getEnumerableProperty(source, resolver, propertyName); if (!this.propertyValues.containsKey(propertyName)) { this.propertyValues.put(propertyName, new PropertyValue(propertyName, value)); @@ -139,6 +130,17 @@ public class PropertySourcesPropertyValues implements PropertyValues { } } + private Object getEnumerableProperty(EnumerablePropertySource source, + PropertySourcesPropertyResolver resolver, String propertyName) { + try { + return resolver.getProperty(propertyName, Object.class); + } + catch (RuntimeException ex) { + // Probably could not resolve placeholders, ignore it here + return source.getProperty(propertyName); + } + } + private void processCompositePropertySource(CompositePropertySource source, PropertySourcesPropertyResolver resolver, PropertyNamePatternsMatcher includes, Collection exacts) { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 3ddeb4e788..0fdb02b484 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -387,15 +387,17 @@ public class ConfigFileApplicationListener implements .getProperty(INCLUDE_PROFILES_PROPERTY)); } } - StringBuilder msg = new StringBuilder(); msg.append(propertySource == null ? "Skipped " : "Loaded "); msg.append("config file "); - msg.append("'").append(location).append("' "); - msg.append(StringUtils.hasLength(profile) ? "for profile " + profile : " "); - msg.append(resource == null || !resource.exists() ? "resource not found" : ""); + msg.append("'").append(location).append("'"); + if (StringUtils.hasLength(profile)) { + msg.append(" for profile" + profile); + } + if (resource == null || !resource.exists()) { + msg.append(" resource not found"); + } this.debug.add(msg); - return propertySource; } diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesPropertyValuesTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesPropertyValuesTests.java index afd1240884..458ca9732e 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesPropertyValuesTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/PropertySourcesPropertyValuesTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -44,6 +45,7 @@ public class PropertySourcesPropertyValuesTests { @Before public void init() { this.propertySources.addFirst(new PropertySource("static", "foo") { + @Override public Object getProperty(String name) { if (name.equals(getSource())) { @@ -59,10 +61,8 @@ public class PropertySourcesPropertyValuesTests { @Test public void testTypesPreserved() { - this.propertySources.replace( - "map", - new MapPropertySource("map", Collections. singletonMap( - "name", 123))); + Map map = Collections. singletonMap("name", 123); + this.propertySources.replace("map", new MapPropertySource("map", map)); PropertySourcesPropertyValues propertyValues = new PropertySourcesPropertyValues( this.propertySources); assertEquals(123, propertyValues.getPropertyValues()[0].getValue()); @@ -123,6 +123,7 @@ public class PropertySourcesPropertyValuesTests { @Test public void testNonEnumeratedPlaceholder() { this.propertySources.addFirst(new PropertySource("another", "baz") { + @Override public Object getProperty(String name) { if (name.equals(getSource())) { @@ -179,10 +180,12 @@ public class PropertySourcesPropertyValuesTests { TestBean target = new TestBean(); DataBinder binder = new DataBinder(target); this.propertySources.addFirst(new PropertySource("application", "STUFF") { + @Override public Object getProperty(String name) { return new Object(); } + }); binder.bind(new PropertySourcesPropertyValues(this.propertySources, (Collection) null, Collections.singleton("name")));