pull/3741/merge
Phillip Webb 9 years ago
parent db41fb16c0
commit 6193b640a4

@ -6,7 +6,6 @@ something, or simply want to hack on the code this document should help you get
== Using GitHub issues
We use GitHub issues to track bugs and enhancements. If you have a general usage question
please ask on http://stackoverflow.com[Stack Overflow]. The Spring Boot team and the
broader community monitor the http://stackoverflow.com/tags/spring-boot[`spring-boot`]

@ -42,8 +42,8 @@ public class ShellProperties {
private static Log logger = LogFactory.getLog(ShellProperties.class);
/**
* Authentication type. Auto-detected according to the environment (i.e. if
* Spring Security is available, "spring" is used by default).
* Authentication type. Auto-detected according to the environment (i.e. if Spring
* Security is available, "spring" is used by default).
*/
private String auth = "simple";

@ -16,14 +16,6 @@
package org.springframework.boot.actuate.autoconfigure;
import static org.hamcrest.Matchers.hasKey;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
@ -67,6 +59,14 @@ import org.springframework.util.SocketUtils;
import com.zaxxer.hikari.HikariDataSource;
import static org.hamcrest.Matchers.hasKey;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link PublicMetricsAutoConfiguration}.
*
@ -246,7 +246,8 @@ public class PublicMetricsAutoConfigurationTests {
}
context.register(DataSourcePoolMetadataProvidersConfiguration.class,
CacheStatisticsAutoConfiguration.class,
PublicMetricsAutoConfiguration.class, MockEmbeddedServletContainerFactory.class);
PublicMetricsAutoConfiguration.class,
MockEmbeddedServletContainerFactory.class);
context.refresh();
this.context = context;
}

@ -16,9 +16,6 @@
package org.springframework.boot.autoconfigure;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
import static org.springframework.util.StringUtils.trimAllWhitespace;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Iterator;
@ -44,6 +41,9 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.StringUtils;
import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
import static org.springframework.util.StringUtils.trimAllWhitespace;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.
*
@ -52,7 +52,7 @@ import org.springframework.util.StringUtils;
* @author Eddú Meléndez
*/
@Configuration
@ConditionalOnMissingBean(value=MessageSource.class, search=SearchStrategy.CURRENT)
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
@ -81,8 +81,8 @@ public class MessageSourceAutoConfiguration {
/**
* Set whether to fall back to the system Locale if no files for a specific Locale
* have been found. if this is turned off, the only fallback will be the default
* file (e.g. "messages.properties" for basename "messages").
* have been found. if this is turned off, the only fallback will be the default file
* (e.g. "messages.properties" for basename "messages").
*/
private boolean fallbackToSystemLocale = true;

@ -63,9 +63,8 @@ public @interface SpringBootApplication {
String[] excludeName() default {};
/**
* Base packages to scan for annotated components.
* <p>Use {@link #scanBasePackageClasses} for a type-safe alternative to
* String-based package names.
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@ -73,10 +72,11 @@ public @interface SpringBootApplication {
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jdbc;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanClassLoaderAware;
@ -48,8 +49,8 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
private String name = "testdb";
/**
* Fully qualified name of the connection pool implementation to use. By default,
* it is auto-detected from the classpath.
* Fully qualified name of the connection pool implementation to use. By default, it
* is auto-detected from the classpath.
*/
private Class<? extends DataSource> type;

@ -134,8 +134,8 @@ public class JpaProperties {
/**
* DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto"
* property. Default to "create-drop" when using an embedded database,
* "none" otherwise.
* property. Default to "create-drop" when using an embedded database, "none"
* otherwise.
*/
private String ddlAuto;

@ -69,7 +69,6 @@ public class AuthenticationManagerConfiguration {
private static Log logger = LogFactory
.getLog(AuthenticationManagerConfiguration.class);
@SuppressWarnings("unused")
@Autowired
private List<SecurityPrerequisite> dependencies;

@ -50,8 +50,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
@EnableConfigurationProperties
@Import({ SpringBootWebSecurityConfiguration.class,
AuthenticationManagerConfiguration.class,
BootGlobalAuthenticationConfiguration.class,
SecurityDataConfiguration.class })
BootGlobalAuthenticationConfiguration.class, SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
@Bean

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security;
import javax.servlet.Filter;
@ -44,15 +45,16 @@ import org.springframework.security.web.context.AbstractSecurityWebApplicationIn
@AutoConfigureAfter(SpringBootWebSecurityConfiguration.class)
public class SecurityFilterAutoConfiguration {
private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
@Bean
@ConditionalOnBean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public FilterRegistrationBean securityFilterChainRegistration(
@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter,
@Qualifier(DEFAULT_FILTER_NAME) Filter securityFilter,
SecurityProperties securityProperties) {
FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
registration.setOrder(securityProperties.getFilterOrder());
registration
.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
registration.setName(DEFAULT_FILTER_NAME);
return registration;
}

@ -40,8 +40,7 @@ public class SecurityProperties implements SecurityPrerequisite {
* useful place to put user-defined access rules if you want to override the default
* access rules.
*/
public static final int ACCESS_OVERRIDE_ORDER = SecurityProperties.BASIC_AUTH_ORDER
- 2;
public static final int ACCESS_OVERRIDE_ORDER = SecurityProperties.BASIC_AUTH_ORDER - 2;
/**
* Order applied to the WebSecurityConfigurerAdapter that is used to configure basic
@ -62,8 +61,7 @@ public class SecurityProperties implements SecurityPrerequisite {
* other filters registered with the container). There is no connection between this
* and the <code>@Order</code> on a WebSecurityConfigurer.
*/
public static final int DEFAULT_FILTER_ORDER = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER
- 100;
public static final int DEFAULT_FILTER_ORDER = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100;
/**
* Enable secure channel for all requests.

@ -31,9 +31,10 @@ import org.springframework.context.annotation.Conditional;
* @author Stephane Nicoll
* @since 1.3.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnEnabledResourceChainCondition.class)
public @interface ConditionalOnEnabledResourceChain {
}

@ -34,14 +34,16 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
class OnEnabledResourceChainCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
ResourceProperties resourceProperties = new ResourceProperties();
RelaxedDataBinder binder = new RelaxedDataBinder(resourceProperties, "spring.resources");
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConfigurableEnvironment environment = (ConfigurableEnvironment) context
.getEnvironment();
ResourceProperties properties = new ResourceProperties();
RelaxedDataBinder binder = new RelaxedDataBinder(properties, "spring.resources");
binder.bind(new PropertySourcesPropertyValues(environment.getPropertySources()));
Boolean match = resourceProperties.getChain().getEnabled();
return new ConditionOutcome(match, "Resource chain is " + (match ? "enabled" : "disabled" + ")"));
Boolean match = properties.getChain().getEnabled();
return new ConditionOutcome(match, "Resource chain is "
+ (match ? "enabled" : "disabled" + ")"));
}
}

@ -43,8 +43,8 @@ public class MessageSourceAutoConfigurationTests {
@After
public void closeContext() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@ -72,7 +72,8 @@ public class MessageSourceAutoConfigurationTests {
@Test
public void testMultipleMessageSourceCreated() throws Exception {
load("spring.messages.basename:test/messages,test/messages2");
assertEquals("bar", this.context.getMessage("foo", null, "Foo message", Locale.UK));
assertEquals("bar",
this.context.getMessage("foo", null, "Foo message", Locale.UK));
assertEquals("bar-bar",
this.context.getMessage("foo-foo", null, "Foo-Foo message", Locale.UK));
}
@ -124,4 +125,5 @@ public class MessageSourceAutoConfigurationTests {
protected static class Config {
}
}

@ -164,7 +164,9 @@ public class JobLauncherCommandLineRunnerTests {
protected static class BatchConfiguration implements BatchConfigurer {
private ResourcelessTransactionManager transactionManager = new ResourcelessTransactionManager();
private JobRepository jobRepository;
private MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(
this.transactionManager);
@ -198,6 +200,7 @@ public class JobLauncherCommandLineRunnerTests {
public JobExplorer getJobExplorer() throws Exception {
return new MapJobExplorerFactoryBean(this.jobRepositoryFactory).getObject();
}
}
}

@ -26,14 +26,13 @@ import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.Random;
import java.util.logging.Logger;
import javax.sql.DataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
@ -43,6 +42,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import com.zaxxer.hikari.HikariDataSource;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -158,8 +159,8 @@ public class DataSourceAutoConfigurationTests {
public void explicitType() {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:org.hsqldb.jdbcDriver",
"spring.datasource.url:jdbc:hsqldb:mem:testdb",
"spring.datasource.type:" + HikariDataSource.class.getName());
"spring.datasource.url:jdbc:hsqldb:mem:testdb", "spring.datasource.type:"
+ HikariDataSource.class.getName());
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@ -271,7 +272,8 @@ public class DataSourceAutoConfigurationTests {
}
@SuppressWarnings("unused") // see testExplicitDriverClassClearsUserName
@SuppressWarnings("unused")
// see testExplicitDriverClassClearsUserName
public static class DatabaseDriver implements Driver {
@Override

@ -16,12 +16,6 @@
package org.springframework.boot.autoconfigure.security;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import org.junit.After;
@ -63,6 +57,12 @@ import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Tests for {@link SecurityAutoConfiguration}.
*
@ -105,7 +105,7 @@ public class SecurityAutoConfigurationTests {
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertEquals(
FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER-100,
FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100,
this.context.getBean("securityFilterChainRegistration",
FilterRegistrationBean.class).getOrder());
}
@ -136,7 +136,7 @@ public class SecurityAutoConfigurationTests {
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertEquals(
FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER-100,
FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100,
this.context.getBean("securityFilterChainRegistration",
FilterRegistrationBean.class).getOrder());
}
@ -355,11 +355,9 @@ public class SecurityAutoConfigurationTests {
public void testSecurityEvaluationContextExtensionSupport() {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(AuthenticationManagerCustomizer.class,
SecurityAutoConfiguration.class, ServerPropertiesAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(SecurityEvaluationContextExtension.class));
}

@ -200,11 +200,13 @@ public class ThymeleafAutoConfigurationTests {
this.context.register(ThymeleafAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertEquals(0, this.context.getBeansOfType(ResourceUrlEncodingFilter.class).size());
assertEquals(0, this.context.getBeansOfType(ResourceUrlEncodingFilter.class)
.size());
}
@Test
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() throws Exception {
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled()
throws Exception {
this.context.register(ThymeleafAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.context,

@ -193,11 +193,13 @@ public class VelocityAutoConfigurationTests {
@Test
public void registerResourceHandlingFilterDisabledByDefault() throws Exception {
registerAndRefreshContext();
assertEquals(0, this.context.getBeansOfType(ResourceUrlEncodingFilter.class).size());
assertEquals(0, this.context.getBeansOfType(ResourceUrlEncodingFilter.class)
.size());
}
@Test
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() throws Exception {
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled()
throws Exception {
registerAndRefreshContext("spring.resources.chain.enabled:true");
assertNotNull(this.context.getBean(ResourceUrlEncodingFilter.class));
}

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.web;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@ -71,7 +70,6 @@ public class ConditionalOnEnabledResourceChainTests {
assertTrue(this.context.containsBean("foo"));
}
private void load(String... environment) {
this.context.register(Config.class);
EnvironmentTestUtils.addEnvironment(this.context, environment);

@ -184,7 +184,7 @@ class ProjectGenerationRequest {
* @return the package name or {@code null}
*/
public String getPackageName() {
return packageName;
return this.packageName;
}
public void setPackageName(String packageName) {

@ -266,9 +266,9 @@ public class InitCommandTests extends AbstractHttpClientMockTests {
public void parseProjectOptions() throws Exception {
this.handler.disableProjectGeneration();
this.command.run("-g=org.demo", "-a=acme", "-v=1.2.3-SNAPSHOT", "-n=acme-sample",
"--description=Acme sample project", "--package-name=demo.foo", "-t=ant-project",
"--build=grunt", "--format=web", "-p=war", "-j=1.9", "-l=groovy",
"-b=1.2.0.RELEASE", "-d=web,data-jpa");
"--description=Acme sample project", "--package-name=demo.foo",
"-t=ant-project", "--build=grunt", "--format=web", "-p=war", "-j=1.9",
"-l=groovy", "-b=1.2.0.RELEASE", "-d=web,data-jpa");
assertEquals("org.demo", this.handler.lastRequest.getGroupId());
assertEquals("acme", this.handler.lastRequest.getArtifactId());
assertEquals("1.2.3-SNAPSHOT", this.handler.lastRequest.getVersion());

@ -142,24 +142,21 @@ public class ProjectGenerationRequestTests {
@Test
public void outputCustomizeArtifactId() {
this.request.setOutput("my-project");
assertEquals(
createDefaultUrl("?artifactId=my-project&type=test-type"),
assertEquals(createDefaultUrl("?artifactId=my-project&type=test-type"),
this.request.generateUrl(createDefaultMetadata()));
}
@Test
public void outputArchiveCustomizeArtifactId() {
this.request.setOutput("my-project.zip");
assertEquals(
createDefaultUrl("?artifactId=my-project&type=test-type"),
assertEquals(createDefaultUrl("?artifactId=my-project&type=test-type"),
this.request.generateUrl(createDefaultMetadata()));
}
@Test
public void outputArchiveWithDotsCustomizeArtifactId() {
this.request.setOutput("my.nice.project.zip");
assertEquals(
createDefaultUrl("?artifactId=my.nice.project&type=test-type"),
assertEquals(createDefaultUrl("?artifactId=my.nice.project&type=test-type"),
this.request.generateUrl(createDefaultMetadata()));
}
@ -167,8 +164,7 @@ public class ProjectGenerationRequestTests {
public void outputDoesNotOverrideCustomArtifactId() {
this.request.setOutput("my-project");
this.request.setArtifactId("my-id");
assertEquals(
createDefaultUrl("?artifactId=my-id&type=test-type"),
assertEquals(createDefaultUrl("?artifactId=my-id&type=test-type"),
this.request.generateUrl(createDefaultMetadata()));
}

@ -65,7 +65,6 @@ public class DevToolsProperties {
private static final long DEFAULT_RESTART_QUIET_PERIOD = 400;
/**
* Enable automatic restart.
*/
@ -117,7 +116,8 @@ public class DevToolsProperties {
allExclude.addAll(StringUtils.commaDelimitedListToSet(this.exclude));
}
if (StringUtils.hasText(this.additionalExclude)) {
allExclude.addAll(StringUtils.commaDelimitedListToSet(this.additionalExclude));
allExclude.addAll(StringUtils
.commaDelimitedListToSet(this.additionalExclude));
}
return allExclude.toArray(new String[allExclude.size()]);
}

@ -34,9 +34,11 @@ public class DevToolsPropertiesTests {
public void additionalExcludeKeepsDefaults() {
DevToolsProperties.Restart restart = this.devToolsProperties.getRestart();
restart.setAdditionalExclude("foo/**,bar/**");
assertThat(restart.getAllExclude(), arrayContaining("META-INF/maven/**",
"META-INF/resources/**", "resources/**", "static/**", "public/**",
"templates/**", "foo/**", "bar/**"));
assertThat(
restart.getAllExclude(),
arrayContaining("META-INF/maven/**", "META-INF/resources/**",
"resources/**", "static/**", "public/**", "templates/**",
"foo/**", "bar/**"));
}
@Test

@ -255,4 +255,5 @@ public class LocalDevToolsAutoConfigurationTests {
public static class WebResourcesConfig {
}
}

@ -590,7 +590,8 @@ NOTE: The double backslashes are only required when you're using a properties fi
configuration. If you are using YAML, single backslashes are sufficient and a value
that's equivalent to the one shown above would be `192\.168\.\d{1,3}\.\d{1,3}`.
NOTE: You can trust all proxies by setting the `internal_proxies` to empty (but don't do this in production).
NOTE: You can trust all proxies by setting the `internal_proxies` to empty (but don't do
this in production).
You can take complete control of the configuration of the
`RemoteIpValve` by switching the automatic one off (i.e. set one of
@ -1164,16 +1165,17 @@ Check out {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`W
{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[`VelocityAutoConfiguration`]
[[howto-customize-view-resolvers-velocity]]
=== Velocity
By default, Spring Boot configures a `VelocityViewResolver`. If you need a `VelocityLayoutViewResolver`
instead, you can easily configure your own by creating a bean with name `velocityViewResolver`. You can
also inject the `VelocityProperties` instance to apply the base defaults to your custom view resolver.
By default, Spring Boot configures a `VelocityViewResolver`. If you need a
`VelocityLayoutViewResolver` instead, you can easily configure your own by creating a bean
with name `velocityViewResolver`. You can also inject the `VelocityProperties` instance to
apply the base defaults to your custom view resolver.
The following example replaces the auto-configured velocity view resolver with a
`VelocityLayoutViewResolver` defining a customized `layoutUrl` and all settings that would have been
applied from the auto-configuration:
`VelocityLayoutViewResolver` defining a customized `layoutUrl` and all settings that would
have been applied from the auto-configuration:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@ -1187,6 +1189,7 @@ applied from the auto-configuration:
----
[[howto-logging]]
== Logging
@ -1456,7 +1459,6 @@ entity manager based on the presence of a bean of that type.
[[howto-use-two-entity-managers]]
=== Use Two EntityManagers
Even if the default `EntityManagerFactory` works fine, you will need to define a new one
because otherwise the presence of the second bean of that type will switch off the
default. To make it easy to do that you can use the convenient `EntityManagerBuilder`
@ -1488,7 +1490,6 @@ Example:
.persistenceUnit("orders")
.build();
}
----
The configuration above almost works on its own. To complete the picture you need to
@ -1501,7 +1502,6 @@ If you are using Spring Data, you need to configure `@EnableJpaRepositories` acc
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@Configuration
@EnableJpaRepositories(basePackageClasses = Customer.class,
entityManagerFactoryRef = "customerEntityManagerFactory")
@ -1515,11 +1515,10 @@ If you are using Spring Data, you need to configure `@EnableJpaRepositories` acc
public class OrderConfiguration {
...
}
----
[[howto-use-traditional-persistence-xml]]
=== Use a traditional persistence.xml
Spring doesn't require the use of XML to configure the JPA provider, and Spring Boot

@ -1351,9 +1351,10 @@ https://spring.io/blog/2014/07/24/spring-framework-4-1-handling-static-web-resou
and in Spring Framework's {spring-reference}/#mvc-config-static-resources[reference documentation].
====
[[boot-features-spring-mvc-web-binding-initializer]]
==== ConfigurableWebBindingInitializer
Spring MVC uses a `WebBindingInitializer` to initialize a `WebDataBinder` for a particular
request. If you create your own `ConfigurableWebBindingInitializer` `@Bean`, Spring Boot
will automatically configure Spring MVC to use it.
@ -3419,7 +3420,8 @@ You could also specify the `hazelcast.xml` configuration file to use via configu
Otherwise, Spring Boot tries to find the Hazelcast configuration from the default
locations, that is `hazelcast.xml` in the working directory or at the root of the
classpath. We also check if the `hazelcast.config` system property is set. Check the
http://docs.hazelcast.org/docs/latest/manual/html-single/[Hazelcast documentation] for more details.
http://docs.hazelcast.org/docs/latest/manual/html-single/[Hazelcast documentation] for
more details.
NOTE: Spring Boot also has an
<<boot-features-caching-provider-hazelcast,explicit caching support for Hazelcast>>. The
@ -3712,6 +3714,7 @@ TIP: A https://github.com/snicoll-demos/spring-boot-master-auto-configuration[de
is available to showcase how you can create a starter step by step.
[[boot-features-understanding-auto-configured-beans]]
=== Understanding auto-configured beans
Under the hood, auto-configuration is implemented with standard `@Configuration` classes.
@ -3818,9 +3821,9 @@ The `@ConditionalOnExpression` annotation allows configuration to be included ba
result of a {spring-reference}/#expressions[SpEL expression].
[[boot-features-custom-starter]]
=== Creating your own starter
A full Spring Boot starter for a library may contain the following components:
* The `autoconfigure` module that contains the auto-configuration code.
@ -3831,10 +3834,11 @@ A full Spring Boot starter for a library may contain the following components:
TIP: You may combine the auto-configuration code and the dependency management in a single
module if you don't need to separate those two concerns.
[[boot-features-custom-starter-naming]]
==== Naming
Please make sure to provide a proper namespace for your starter. Do not start your module
FPlease make sure to provide a proper namespace for your starter. Do not start your module
names with `spring-boot`, even if you are using a different Maven groupId. We may offer an
official support for the thing you're auto-configuring in the future.
@ -3854,9 +3858,10 @@ meta-data generation>> so that IDE assistance is available for your keys as well
may want to review the generated meta-data (`META-INF/spring-configuration-metadata.json`)
to make sure your keys are properly documented.
[[boot-features-custom-starter-module-autoconfigure]]
==== Autoconfigure module
The autoconfigure module contains everything that is necessary to get started with the
library. It may also contain configuration keys definition (`@ConfigurationProperties`)
and any callback interface that can be used to further customize how the components are
@ -3866,9 +3871,10 @@ TIP: You should mark the dependencies to the library as optional so that you can
the autoconfigure module in your projects more easily. If you do it that way, the library
won't be provided and boot will backoff by default.
[[boot-features-custom-starter-module-starter]]
==== Starter module
The starter is an empty jar, really. Its only purpose is to provide the necessary
dependencies to work with the library; see it as an opinionated view of what is required
to get started.
@ -3879,6 +3885,8 @@ a proper set of _default_ dependencies may be hard if the number of optional dep
is high as you should avoid bringing unnecessary dependencies for a typical usage of the
library.
[[boot-features-websockets]]
== WebSockets
Spring Boot provides WebSockets auto-configuration for embedded Tomcat (8 and 7), Jetty 9

@ -54,7 +54,6 @@ of the library that you want to use.
=== EhCache 2.x
Simply add the `net.sf.ehcache:ehcache` dependency to the project. Since there is a
default `ehcache.xml` configuration file at the root of the classpath, it is automatically

@ -877,8 +877,8 @@ public class SpringApplication {
public void setApplicationContextClass(
Class<? extends ConfigurableApplicationContext> applicationContextClass) {
this.applicationContextClass = applicationContextClass;
if (!isSpringWebAvailable() || !WebApplicationContext.class.isAssignableFrom(
applicationContextClass)) {
if (!isSpringWebAvailable()
|| !WebApplicationContext.class.isAssignableFrom(applicationContextClass)) {
this.webEnvironment = false;
}
}

@ -57,4 +57,12 @@ class OriginCapablePropertyValue extends PropertyValue {
.getName() : "unknown";
return "'" + name + "' from '" + source + "'";
}
public static PropertyOrigin getOrigin(PropertyValue propertyValue) {
if (propertyValue instanceof OriginCapablePropertyValue) {
return ((OriginCapablePropertyValue) propertyValue).getOrigin();
}
return new OriginCapablePropertyValue(propertyValue).getOrigin();
}
}

@ -18,7 +18,6 @@ package org.springframework.boot.bind;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -35,6 +34,7 @@ import org.springframework.beans.InvalidPropertyException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.PropertyValue;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.LinkedMultiValueMap;
@ -52,15 +52,11 @@ import org.springframework.validation.DataBinder;
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Andy Wilkinson
* @see RelaxedNames
*/
public class RelaxedDataBinder extends DataBinder {
private static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES = Collections
.unmodifiableSet(new HashSet<String>(Arrays.asList(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)));
private static final Object BLANK = new Object();
private String namePrefix;
@ -83,12 +79,12 @@ public class RelaxedDataBinder extends DataBinder {
* @param namePrefix An optional prefix to be used when reading properties
*/
public RelaxedDataBinder(Object target, String namePrefix) {
super(wrapTarget(target),
(StringUtils.hasLength(namePrefix) ? namePrefix : DEFAULT_OBJECT_NAME));
super(wrapTarget(target), (StringUtils.hasLength(namePrefix) ? namePrefix
: DEFAULT_OBJECT_NAME));
this.namePrefix = cleanNamePrefix(namePrefix);
}
private static String cleanNamePrefix(String namePrefix) {
private String cleanNamePrefix(String namePrefix) {
if (!StringUtils.hasLength(namePrefix)) {
return null;
}
@ -146,8 +142,7 @@ public class RelaxedDataBinder extends DataBinder {
propertyValues = addMapPrefix(propertyValues);
}
BeanWrapper wrapper = new BeanWrapperImpl(target);
wrapper.setConversionService(
new RelaxedConversionService(getConversionService()));
wrapper.setConversionService(new RelaxedConversionService(getConversionService()));
wrapper.setAutoGrowNestedPaths(true);
List<PropertyValue> sortedValues = new ArrayList<PropertyValue>();
Set<String> modifiedNames = new HashSet<String>();
@ -214,9 +209,10 @@ public class RelaxedDataBinder extends DataBinder {
if (name.startsWith(candidate)) {
name = name.substring(candidate.length());
if (!(this.ignoreNestedProperties && name.contains("."))) {
PropertyOrigin propertyOrigin = findPropertyOrigin(value);
rtn.addPropertyValue(new OriginCapablePropertyValue(name,
value.getValue(), propertyOrigin));
PropertyOrigin propertyOrigin = OriginCapablePropertyValue
.getOrigin(value);
rtn.addPropertyValue(new OriginCapablePropertyValue(name, value
.getValue(), propertyOrigin));
}
}
}
@ -224,8 +220,7 @@ public class RelaxedDataBinder extends DataBinder {
return rtn;
}
private PropertyValue modifyProperty(BeanWrapper target,
PropertyValue propertyValue) {
private PropertyValue modifyProperty(BeanWrapper target, PropertyValue propertyValue) {
String name = propertyValue.getName();
String normalizedName = normalizePath(target, name);
if (!normalizedName.equals(name)) {
@ -251,55 +246,9 @@ public class RelaxedDataBinder extends DataBinder {
@Override
protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
return new BeanPropertyBindingResult(getTarget(), getObjectName(),
isAutoGrowNestedPaths(), getAutoGrowCollectionLimit()) {
@Override
protected BeanWrapper createBeanWrapper() {
BeanWrapper beanWrapper = new BeanWrapperImpl(getTarget()) {
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
try {
super.setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
PropertyOrigin origin = findPropertyOrigin(pv);
if (isFatal(origin)) {
if (origin != null) {
throw new RelaxedBindingNotWritablePropertyException(
ex, origin);
}
else {
throw ex;
}
}
else {
logger.debug("Ignoring benign property binding failure",
ex);
}
}
}
};
beanWrapper.setConversionService(
new RelaxedConversionService(getConversionService()));
beanWrapper.registerCustomEditor(InetAddress.class,
new InetAddressEditor());
return beanWrapper;
}
};
}
private boolean isFatal(PropertyOrigin origin) {
if (origin == null) {
return true;
}
return !BENIGN_PROPERTY_SOURCE_NAMES.contains(origin.getSource().getName());
}
private PropertyOrigin findPropertyOrigin(PropertyValue propertyValue) {
if (propertyValue instanceof OriginCapablePropertyValue) {
return ((OriginCapablePropertyValue) propertyValue).getOrigin();
}
return new OriginCapablePropertyValue(propertyValue).getOrigin();
return new RelaxedBeanPropertyBindingResult(getTarget(), getObjectName(),
isAutoGrowNestedPaths(), getAutoGrowCollectionLimit(),
getConversionService());
}
private String initializePath(BeanWrapper wrapper, BeanPath path, int index) {
@ -354,8 +303,8 @@ public class RelaxedDataBinder extends DataBinder {
@SuppressWarnings("rawtypes")
private boolean isBlanked(BeanWrapper wrapper, String propertyName, String key) {
Object value = (wrapper.isReadableProperty(propertyName)
? wrapper.getPropertyValue(propertyName) : null);
Object value = (wrapper.isReadableProperty(propertyName) ? wrapper
.getPropertyValue(propertyName) : null);
if (value instanceof Map) {
if (((Map) value).get(key) == BLANK) {
return true;
@ -364,8 +313,7 @@ public class RelaxedDataBinder extends DataBinder {
return false;
}
private void extendCollectionIfNecessary(BeanWrapper wrapper, BeanPath path,
int index) {
private void extendCollectionIfNecessary(BeanWrapper wrapper, BeanPath path, int index) {
String name = path.prefix(index);
TypeDescriptor elementDescriptor = wrapper.getPropertyTypeDescriptor(name)
.getElementTypeDescriptor();
@ -429,9 +377,8 @@ public class RelaxedDataBinder extends DataBinder {
String nested = resolvePropertyName(target, prefix, candidate.toString());
if (nested != null) {
Class<?> type = target.getPropertyType(nested);
if (type != null && Map.class.isAssignableFrom(type)) {
// Special case for map property (gh-3836). Maybe could be fixed
// in spring-beans)?
if ((type != null) && Map.class.isAssignableFrom(type)) {
// Special case for map property (gh-3836).
return nested + "[" + name.substring(candidate.length() + 1) + "]";
}
String propertyName = resolvePropertyName(target,
@ -507,6 +454,9 @@ public class RelaxedDataBinder extends DataBinder {
}
/**
* A path though properties of a bean.
*/
private static class BeanPath {
private List<PathNode> nodes;
@ -678,4 +628,71 @@ public class RelaxedDataBinder extends DataBinder {
}
/**
* Extended version of {@link BeanPropertyBindingResult} to support relaxed binding.
*/
private static class RelaxedBeanPropertyBindingResult extends
BeanPropertyBindingResult {
private RelaxedConversionService conversionService;
public RelaxedBeanPropertyBindingResult(Object target, String objectName,
boolean autoGrowNestedPaths, int autoGrowCollectionLimit,
ConversionService conversionService) {
super(target, objectName, autoGrowNestedPaths, autoGrowCollectionLimit);
this.conversionService = new RelaxedConversionService(conversionService);
}
@Override
protected BeanWrapper createBeanWrapper() {
BeanWrapper beanWrapper = new RelaxedBeanWrapper(getTarget());
beanWrapper.setConversionService(this.conversionService);
beanWrapper.registerCustomEditor(InetAddress.class, new InetAddressEditor());
return beanWrapper;
}
}
/**
* Extended version of {@link BeanWrapperImpl} to support relaxed binding.
*/
private static class RelaxedBeanWrapper extends BeanWrapperImpl {
private static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES;
static {
Set<String> names = new HashSet<String>();
names.add(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
names.add(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
BENIGN_PROPERTY_SOURCE_NAMES = Collections.unmodifiableSet(names);
}
public RelaxedBeanWrapper(Object target) {
super(target);
}
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
try {
super.setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
PropertyOrigin origin = OriginCapablePropertyValue.getOrigin(pv);
if (isBenign(origin)) {
logger.debug("Ignoring benign property binding failure", ex);
return;
}
if (origin == null) {
throw ex;
}
throw new RelaxedBindingNotWritablePropertyException(ex, origin);
}
}
private boolean isBenign(PropertyOrigin origin) {
String name = (origin == null ? null : origin.getSource().getName());
return BENIGN_PROPERTY_SOURCE_NAMES.contains(name);
}
}
}

@ -52,7 +52,7 @@ import org.springframework.util.Assert;
public class FilterRegistrationBean extends RegistrationBean {
/**
* Filters that wrap the servlet request should have an order less than or equal to this.
* Filters that wrap the servlet request should be ordered less than or equal to this.
*/
public static final int REQUEST_WRAPPER_FILTER_MAX_ORDER = 0;

@ -35,4 +35,5 @@ import org.springframework.beans.factory.annotation.Qualifier;
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationPropertiesBinding {
}

@ -72,8 +72,8 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
* @author Stephane Nicoll
*/
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware,
InitializingBean, DisposableBean, PriorityOrdered {
BeanFactoryAware, ResourceLoaderAware, EnvironmentAware, ApplicationContextAware,
InitializingBean, DisposableBean, PriorityOrdered {
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
@ -105,8 +105,8 @@ InitializingBean, DisposableBean, PriorityOrdered {
private int order = Ordered.HIGHEST_PRECEDENCE + 1;
/**
* A list of custom converters (in addition to the defaults) to use when
* converting properties for binding.
* A list of custom converters (in addition to the defaults) to use when converting
* properties for binding.
* @param converters the converters to set
*/
@Autowired(required = false)
@ -262,8 +262,8 @@ InitializingBean, DisposableBean, PriorityOrdered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
ConfigurationProperties annotation = AnnotationUtils
.findAnnotation(bean.getClass(), ConfigurationProperties.class);
ConfigurationProperties annotation = AnnotationUtils.findAnnotation(
bean.getClass(), ConfigurationProperties.class);
if (annotation != null || bean instanceof ConfigurationPropertiesHolder) {
postProcessBeforeInitialization(bean, beanName, annotation);
}
@ -283,13 +283,13 @@ InitializingBean, DisposableBean, PriorityOrdered {
private void postProcessBeforeInitialization(Object bean, String beanName,
ConfigurationProperties annotation) {
Object target = (bean instanceof ConfigurationPropertiesHolder
? ((ConfigurationPropertiesHolder) bean).getTarget() : bean);
Object target = (bean instanceof ConfigurationPropertiesHolder ? ((ConfigurationPropertiesHolder) bean)
.getTarget() : bean);
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
target);
if (annotation != null && annotation.locations().length != 0) {
factory.setPropertySources(
loadPropertySources(annotation.locations(), annotation.merge()));
factory.setPropertySources(loadPropertySources(annotation.locations(),
annotation.merge()));
}
else {
factory.setPropertySources(this.propertySources);
@ -297,15 +297,15 @@ InitializingBean, DisposableBean, PriorityOrdered {
factory.setValidator(determineValidator(bean));
// If no explicit conversion service is provided we add one so that (at least)
// comma-separated arrays of convertibles can be bound automatically
factory.setConversionService(this.conversionService == null
? getDefaultConversionService() : this.conversionService);
factory.setConversionService(this.conversionService == null ? getDefaultConversionService()
: this.conversionService);
if (annotation != null) {
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
String targetName = (StringUtils.hasLength(annotation.value())
? annotation.value() : annotation.prefix());
String targetName = (StringUtils.hasLength(annotation.value()) ? annotation
.value() : annotation.prefix());
if (StringUtils.hasLength(targetName)) {
factory.setTargetName(targetName);
}
@ -316,8 +316,7 @@ InitializingBean, DisposableBean, PriorityOrdered {
catch (Exception ex) {
String targetClass = ClassUtils.getShortName(target.getClass());
throw new BeanCreationException(beanName, "Could not bind properties to "
+ targetClass + " (" + getAnnotationDetails(annotation) + ")",
ex);
+ targetClass + " (" + getAnnotationDetails(annotation) + ")", ex);
}
}
@ -326,18 +325,19 @@ InitializingBean, DisposableBean, PriorityOrdered {
return "";
}
StringBuilder details = new StringBuilder();
details.append("prefix=").append((StringUtils.hasLength(annotation.value())
? annotation.value() : annotation.prefix()));
details.append("prefix=").append(
(StringUtils.hasLength(annotation.value()) ? annotation.value()
: annotation.prefix()));
details.append(", ignoreInvalidFields=").append(annotation.ignoreInvalidFields());
details.append(", ignoreUnknownFields=").append(annotation.ignoreUnknownFields());
details.append(", ignoreNestedProperties=")
.append(annotation.ignoreNestedProperties());
details.append(", ignoreNestedProperties=").append(
annotation.ignoreNestedProperties());
return details.toString();
}
private Validator determineValidator(Object bean) {
boolean globalValidatorSupportBean = (this.validator != null
&& this.validator.supports(bean.getClass()));
boolean globalValidatorSupportBean = (this.validator != null && this.validator
.supports(bean.getClass()));
if (ClassUtils.isAssignable(Validator.class, bean.getClass())) {
if (!globalValidatorSupportBean) {
return (Validator) bean;
@ -352,8 +352,8 @@ InitializingBean, DisposableBean, PriorityOrdered {
try {
PropertySourcesLoader loader = new PropertySourcesLoader();
for (String location : locations) {
Resource resource = this.resourceLoader
.getResource(this.environment.resolvePlaceholders(location));
Resource resource = this.resourceLoader.getResource(this.environment
.resolvePlaceholders(location));
String[] profiles = this.environment.getActiveProfiles();
for (int i = profiles.length; i-- > 0;) {
String profile = profiles[i];
@ -377,8 +377,7 @@ InitializingBean, DisposableBean, PriorityOrdered {
private ConversionService getDefaultConversionService() {
if (this.defaultConversionService == null) {
DefaultConversionService conversionService = new DefaultConversionService();
this.applicationContext.getAutowireCapableBeanFactory()
.autowireBean(this);
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(this);
for (Converter<?, ?> converter : this.converters) {
conversionService.addConverter(converter);
}
@ -388,8 +387,8 @@ InitializingBean, DisposableBean, PriorityOrdered {
}
/**
* Factory to create JSR 303 LocalValidatorFactoryBean. Inner class to prevent
* class loader issues.
* Factory to create JSR 303 LocalValidatorFactoryBean. Inner class to prevent class
* loader issues.
*/
private static class Jsr303ValidatorFactory {
@ -403,8 +402,8 @@ InitializingBean, DisposableBean, PriorityOrdered {
}
/**
* {@link Validator} implementation that wraps {@link Validator} instances and
* chains their execution.
* {@link Validator} implementation that wraps {@link Validator} instances and chains
* their execution.
*/
private static class ChainingValidator implements Validator {
@ -438,8 +437,7 @@ InitializingBean, DisposableBean, PriorityOrdered {
/**
* Convenience class to flatten out a tree of property sources without losing the
* reference to the backing data (which can therefore be updated in the
* background).
* reference to the backing data (which can therefore be updated in the background).
*/
private static class FlatPropertySources implements PropertySources {

@ -26,8 +26,8 @@ import org.springframework.web.filter.CharacterEncodingFilter;
* @author Phillip Webb
* @since 1.2.1
*/
public class OrderedCharacterEncodingFilter extends CharacterEncodingFilter
implements Ordered {
public class OrderedCharacterEncodingFilter extends CharacterEncodingFilter implements
Ordered {
private int order = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 9800;

@ -27,7 +27,7 @@ import org.springframework.web.filter.HiddenHttpMethodFilter;
* @since 1.2.4
*/
public class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements
Ordered {
Ordered {
/**
* The default order is high to ensure the filter is applied before Spring Security.

@ -27,7 +27,7 @@ import org.springframework.web.filter.HttpPutFormContentFilter;
* @since 1.3.0
*/
public class OrderedHttpPutFormContentFilter extends HttpPutFormContentFilter implements
Ordered {
Ordered {
/**
* Higher order to ensure the filter is applied before Spring Security.

@ -31,7 +31,6 @@ public interface EnvironmentPostProcessor {
/**
* Post-process the given {@code environment}
*
* @param environment the environment to post-process
* @param application the application to which the environment belongs
*/

@ -200,7 +200,8 @@ public class LoggingApplicationListener implements GenericApplicationListener {
}
private String getExceptionConversionWord(ConfigurableEnvironment environment) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment, "logging.");
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
"logging.");
return resolver.getProperty("exception-conversion-word", "%rEx");
}

@ -26,6 +26,7 @@ import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.Assert;
/**
* Abstract base class for handlers of Servlet components discovered via classpath
@ -49,15 +50,14 @@ abstract class ServletComponentHandler {
}
protected String[] extractUrlPatterns(String attribute, Map<String, Object> attributes) {
String[] value = (String[]) attributes.get("value");
String[] urlPatterns = (String[]) attributes.get("urlPatterns");
if (urlPatterns.length > 0) {
if (((String[]) attributes.get("value")).length > 0) {
throw new IllegalStateException("The urlPatterns and value attributes "
Assert.state(value.length == 0, "The urlPatterns and value attributes "
+ "are mututally exclusive");
}
return urlPatterns;
}
return (String[]) attributes.get("value");
return value;
}
protected final Map<String, String> extractInitParameters(

@ -16,7 +16,7 @@
package org.springframework.boot.web.servlet;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@ -43,8 +43,14 @@ import org.springframework.context.annotation.ScannedGenericBeanDefinition;
class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor,
ApplicationContextAware {
private final List<ServletComponentHandler> handlers = Arrays.asList(
new WebServletHandler(), new WebFilterHandler(), new WebListenerHandler());
private static final List<ServletComponentHandler> HANDLERS;
static {
List<ServletComponentHandler> handers = new ArrayList<ServletComponentHandler>();
handers.add(new WebServletHandler());
handers.add(new WebFilterHandler());
handers.add(new WebListenerHandler());
HANDLERS = Collections.unmodifiableList(handers);
}
private final Set<String> packagesToScan;
@ -60,18 +66,24 @@ class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcess
if (isRunningInEmbeddedContainer()) {
ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
for (String packageToScan : this.packagesToScan) {
scanPackage(componentProvider, packageToScan);
}
}
}
private void scanPackage(
ClassPathScanningCandidateComponentProvider componentProvider,
String packageToScan) {
for (BeanDefinition candidate : componentProvider
.findCandidateComponents(packageToScan)) {
if (candidate instanceof ScannedGenericBeanDefinition) {
for (ServletComponentHandler handler : this.handlers) {
for (ServletComponentHandler handler : HANDLERS) {
handler.handle(((ScannedGenericBeanDefinition) candidate),
(BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
}
}
private boolean isRunningInEmbeddedContainer() {
return this.applicationContext instanceof EmbeddedWebApplicationContext
@ -82,7 +94,7 @@ class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcess
private ClassPathScanningCandidateComponentProvider createComponentProvider() {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
for (ServletComponentHandler handler : this.handlers) {
for (ServletComponentHandler handler : HANDLERS) {
componentProvider.addIncludeFilter(handler.getTypeFilter());
}
return componentProvider;

@ -53,7 +53,6 @@ public @interface ServletComponentScan {
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @ServletComponentScan("org.my.pkg")} instead of
* {@code @ServletComponentScan(basePackages="org.my.pkg")}.
*
* @return the base packages to scan
*/
String[] value() default {};
@ -64,7 +63,6 @@ public @interface ServletComponentScan {
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
*/
String[] basePackages() default {};
@ -73,8 +71,8 @@ public @interface ServletComponentScan {
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for annotated servlet components. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default {};
}

@ -53,16 +53,6 @@ class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
}
}
private void addPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
private void updatePostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
@ -75,6 +65,16 @@ class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
constructorArguments.setValue(packagesToScan);
}
private void addPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(ServletComponentScan.class.getName()));

@ -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.
@ -16,9 +16,6 @@
package org.springframework.boot.bind;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,6 +32,9 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.convert.converter.Converter;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link ConfigurationProperties} binding with custom converters.
*
@ -82,6 +82,7 @@ public class ConverterBindingTests {
}
public static class Foo {
private String name;
public String getName() {
@ -96,6 +97,7 @@ public class ConverterBindingTests {
@ConfigurationProperties
public static class Wrapper {
private Foo foo;
public Foo getFoo() {
@ -105,6 +107,7 @@ public class ConverterBindingTests {
public void setFoo(Foo foo) {
this.foo = foo;
}
}
}

@ -16,15 +16,6 @@
package org.springframework.boot.bind;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -60,6 +51,15 @@ import org.springframework.validation.DataBinder;
import org.springframework.validation.FieldError;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link RelaxedDataBinder}.
*

@ -97,7 +97,8 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
fail("Expected exception");
}
catch (BeanCreationException ex) {
RelaxedBindingNotWritablePropertyException bex = (RelaxedBindingNotWritablePropertyException) ex.getRootCause();
RelaxedBindingNotWritablePropertyException bex = (RelaxedBindingNotWritablePropertyException) ex
.getRootCause();
assertThat(bex.getMessage(),
startsWith("Failed to bind 'com.example.baz' from 'test' to 'baz' "
+ "property on '" + TestConfiguration.class.getName()));

@ -65,6 +65,7 @@ public class ServletComponentScanIntegrationTests {
public TomcatEmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(0);
}
}
}

Loading…
Cancel
Save