From 7c3696bd6479ddc6801d20ddb654927d4c5f6259 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Apr 2018 09:46:49 +0100 Subject: [PATCH 001/701] Next development version (v2.1.0.BUILD-SNAPSHOT) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff6decef933a..b4b1c16cbe2f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ Spring Boot Build Spring Boot Build - 2.0.2.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT ${basedir} From 8944fa503bc041542bf99519fac3586d435764fc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 11 Apr 2018 18:28:10 +0200 Subject: [PATCH 002/701] Upgrade to AspectJ 1.9.0 Closes gh-12834 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index df2a263fc7b8..24cf8c227958 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -36,7 +36,7 @@ 2.7.7 1.9.63 2.4.0 - 1.8.13 + 1.9.0 3.9.1 4.0.6 2.1.4 From ec4f054497467bf3b56141d4a1876e24bf58fe44 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Wed, 11 Apr 2018 09:13:09 +0200 Subject: [PATCH 003/701] Upgrade to Jersey 2.27 Closes gh-12847 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 24cf8c227958..761104ceb565 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -95,7 +95,7 @@ 7.6.0.Final 2.0.6 2.9.0 - 2.26 + 2.27 5.3.3 9.4.9.v20180320 2.2.0.v201112011158 From 7b9c5a3dc374ff9a3d9c7c94d6ed00bdc67cee63 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Wed, 11 Apr 2018 09:07:04 +0200 Subject: [PATCH 004/701] Use Jersey BOM in dependency management Closes gh-12847 --- .../spring-boot-autoconfigure/pom.xml | 4 ++ .../spring-boot-dependencies/pom.xml | 62 ++----------------- .../spring-boot-starter-jersey/pom.xml | 4 ++ 3 files changed, 12 insertions(+), 58 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 5d10f20196db..7d46adb23203 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -156,6 +156,10 @@ jersey-spring4 true + + org.glassfish.hk2.external + bean-validator + org.hibernate hibernate-validator diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 761104ceb565..42bab06c2c7d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1783,65 +1783,11 @@ ${glassfish-el.version} - org.glassfish.jersey.containers - jersey-container-servlet - ${jersey.version} - - - org.glassfish.jersey.containers - jersey-container-servlet-core - ${jersey.version} - - - org.glassfish.jersey.core - jersey-client - ${jersey.version} - - - org.glassfish.jersey.core - jersey-common - ${jersey.version} - - - org.glassfish.jersey.core - jersey-server - ${jersey.version} - - - org.glassfish.jersey.ext - jersey-bean-validation - ${jersey.version} - - - org.glassfish.jersey.ext - jersey-entity-filtering - ${jersey.version} - - - org.glassfish.jersey.ext - jersey-spring4 - ${jersey.version} - - - org.glassfish.hk2.external - bean-validator - - - - - org.glassfish.jersey.media - jersey-media-jaxb - ${jersey.version} - - - org.glassfish.jersey.media - jersey-media-json-jackson - ${jersey.version} - - - org.glassfish.jersey.media - jersey-media-multipart + org.glassfish.jersey + jersey-bom ${jersey.version} + import + pom org.hamcrest diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml index 3de198fa4960..6ec2591f6dce 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml @@ -89,6 +89,10 @@ org.jvnet tiger-types + + org.glassfish.hk2.external + bean-validator + org.glassfish.hk2.external javax.inject From b6b92ba937e3a5aa86ae3ae1b4f45ea25824f05f Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Mon, 19 Mar 2018 20:34:28 +0000 Subject: [PATCH 005/701] Add auto-configuration for Hibernate metrics All Hibernate entityManagerFactories are automatically instrumented and their statistics are included into Micrometer using its HibernateMetrics binder. Closes gh-12550 --- .../pom.xml | 10 + .../HibernateMetricsAutoConfiguration.java | 89 ++++++++ .../main/resources/META-INF/spring.factories | 1 + ...ibernateMetricsAutoConfigurationTests.java | 191 ++++++++++++++++++ .../metrics/test/MetricsIntegrationTests.java | 2 + .../metrics/test/MetricsRun.java | 2 + .../asciidoc/production-ready-features.adoc | 19 ++ 7 files changed, 314 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index ef0ecf425dee..b0f71dccdc62 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -172,6 +172,11 @@ javax.servlet-api true + + org.hibernate + hibernate-core + true + net.sf.ehcache ehcache @@ -440,6 +445,11 @@ jsonassert test + + org.springframework + spring-orm + test + org.springframework.data spring-data-elasticsearch diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java new file mode 100644 index 000000000000..d3150479c14c --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.orm.jpa; + +import java.util.Collections; +import java.util.Map; + +import javax.persistence.EntityManagerFactory; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.jpa.HibernateMetrics; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available + * Hibernate {@link EntityManagerFactory entityManagerFactories} with statistics enabled. + *

+ * {@link HibernateMetrics} can only monitor Hibernate {@link EntityManagerFactory} + * instances with statistics enabled (for instance, by setting JPA property + * hibernate.generate_statistics to true). + * + * @author Rui Figueira + */ +@Configuration +@AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) +@ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class }) +public class HibernateMetricsAutoConfiguration { + + private static final String ENTITY_MANAGER_FACTORY_SUFFIX = "entityManagerFactory"; + + private final MeterRegistry registry; + + public HibernateMetricsAutoConfiguration(MeterRegistry registry) { + this.registry = registry; + } + + @Autowired + public void bindEntityManagerFactoriesToRegistry( + Map entityManagerFactories) { + entityManagerFactories.forEach(this::maybeBindEntityManagerFactoryToRegistry); + } + + private void maybeBindEntityManagerFactoryToRegistry(String beanName, + EntityManagerFactory entityManagerFactory) { + String entityManagerFactoryName = getEntityManagerFactoryName(beanName); + // HibernateMetrics internally checks if statistics are enabled before binding + new HibernateMetrics(entityManagerFactory, entityManagerFactoryName, + Collections.emptyList()).bindTo(this.registry); + } + + /** + * Get the name of a {@link EntityManagerFactory} based on its {@code beanName}. + * @param beanName the name of the {@link EntityManagerFactory} bean + * @return a name for the given entity manager factory + */ + private String getEntityManagerFactoryName(String beanName) { + if (beanName.length() > ENTITY_MANAGER_FACTORY_SUFFIX.length() && StringUtils + .endsWithIgnoreCase(beanName, ENTITY_MANAGER_FACTORY_SUFFIX)) { + return beanName.substring(0, + beanName.length() - ENTITY_MANAGER_FACTORY_SUFFIX.length()); + } + return beanName; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 60dabb05a23e..01ba105602e7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -49,6 +49,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxM org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..338b291aa68f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -0,0 +1,191 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.orm.jpa; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.Entity; +import javax.persistence.EntityManagerFactory; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.PersistenceException; +import javax.sql.DataSource; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.hibernate.SessionFactory; +import org.junit.Test; +import org.mockito.ArgumentMatchers; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link HibernateMetricsAutoConfiguration}. + * + * @author Rui Figueira + */ +public class HibernateMetricsAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + HibernateJpaAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class)) + .withUserConfiguration(BaseConfiguration.class).withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true"); + + @Test + public void autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() { + this.contextRunner.run((context) -> { + context.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "entityManagerFactory").meter(); + }); + } + + @Test + public void autoConfiguredEntityManagerFactoryWithoutStatsIsNotInstrumented() { + this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:false") + .run((context) -> { + context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Test + public void entityManagerFactoryInstrumentationCanBeDisabled() { + this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false") + .run((context) -> { + context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Test + public void allEntityManagerFactoriesCanBeInstrumented() { + this.contextRunner + .withUserConfiguration(TwoEntityManagerFactoriesConfiguration.class) + .run((context) -> { + context.getBean("firstEntityManagerFactory", + EntityManagerFactory.class).unwrap(SessionFactory.class); + context.getBean("secondOne", EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "first").meter(); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "secondOne").meter(); + }); + } + + @Test + public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFactory() { + this.contextRunner + .withUserConfiguration( + NonHibernateEntityManagerFactoryConfiguration.class) + .run((context) -> { + // ensure EntityManagerFactory is not an Hibernate SessionFactory + assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class)) + .isInstanceOf(PersistenceException.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Configuration + static class BaseConfiguration { + + @Bean + public SimpleMeterRegistry simpleMeterRegistry() { + return new SimpleMeterRegistry(); + } + + } + + @Entity + static class MyEntity { + + @Id + @GeneratedValue + private Long id; + } + + @Configuration + static class TwoEntityManagerFactoriesConfiguration { + + private static final Class[] PACKAGE_CLASSES = new Class[] { + MyEntity.class }; + + @Primary + @Bean + public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory( + DataSource ds) { + return createSessionFactory(ds); + } + + @Bean + public LocalContainerEntityManagerFactoryBean secondOne(DataSource ds) { + return createSessionFactory(ds); + } + + private LocalContainerEntityManagerFactoryBean createSessionFactory( + DataSource ds) { + Map jpaProperties = new HashMap<>(); + jpaProperties.put("hibernate.generate_statistics", "true"); + EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder( + new HibernateJpaVendorAdapter(), jpaProperties, null); + return builder.dataSource(ds).packages(PACKAGE_CLASSES).build(); + } + } + + @Configuration + static class NonHibernateEntityManagerFactoryConfiguration { + + @Bean + public EntityManagerFactory entityManagerFactory() { + EntityManagerFactory mockedFactory = mock(EntityManagerFactory.class); + // enforces JPA contract + given(mockedFactory.unwrap(ArgumentMatchers.>any())) + .willThrow(PersistenceException.class); + return mockedFactory; + } + } +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java index 6a5beebe004b..0abe5f1f4bbd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java @@ -38,6 +38,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; @@ -143,6 +144,7 @@ public void metricsFilterRegisteredForAsyncDispatches() { @ImportAutoConfiguration({ MetricsAutoConfiguration.class, RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class, RestTemplateMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index 67dffadea39a..fa35d78a8aef 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -37,6 +37,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; @@ -75,6 +76,7 @@ public final class MetricsRun { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class, RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class, RestTemplateMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 1a4dd9cda79a..71fae7e69d5f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1774,6 +1774,25 @@ Auto-configuration will enable the instrumentation of all available RabbitMQ con factories with a metric named `rabbitmq`. +[[production-ready-metrics-hibernate]] +==== Hibernate Metrics +Auto-configuration enables the instrumentation of all available Hibernate +`EntityManagerFactory` objects that have statistics enabled with a metric named +`hibernate`. + +Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from +the bean name. + +To enable statistics on Hibernate `EntityManagerFactory` instances, JPA property `hibernate.generate_statistics` must be set to `true`. For example, on the default +`EntityManagerFactory`, you need to set the following property: + +.application.properties +[source,properties,indent=0] +---- + spring.jpa.properties.hibernate.generate_statistics=true +---- + + [[production-ready-metrics-custom]] === Registering custom metrics From a85998f4c338639f130b5a4d821bd38847e42188 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Apr 2018 13:41:42 +0200 Subject: [PATCH 006/701] Polish "Add auto-configuration for Hibernate metrics" Closes gh-12550 --- .../pom.xml | 10 +++---- .../HibernateMetricsAutoConfiguration.java | 14 ++++----- .../metrics/orm/jpa/package-info.java | 20 +++++++++++++ ...ibernateMetricsAutoConfigurationTests.java | 30 ++++++++++++------- .../asciidoc/production-ready-features.adoc | 24 ++++++++------- 5 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index b0f71dccdc62..f8c2c72029ab 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -172,11 +172,6 @@ javax.servlet-api true - - org.hibernate - hibernate-core - true - net.sf.ehcache ehcache @@ -238,6 +233,11 @@ jersey-container-servlet-core true + + org.hibernate + hibernate-core + true + org.hibernate.validator hibernate-validator diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java index d3150479c14c..024e8278a063 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -30,23 +30,22 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available - * Hibernate {@link EntityManagerFactory entityManagerFactories} with statistics enabled. - *

- * {@link HibernateMetrics} can only monitor Hibernate {@link EntityManagerFactory} - * instances with statistics enabled (for instance, by setting JPA property - * hibernate.generate_statistics to true). + * Hibernate {@link EntityManagerFactory} instances that have statistics enabled. * * @author Rui Figueira + * @author Stephane Nicoll */ @Configuration @AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }) +@ConditionalOnClass({ EntityManagerFactory.class, MeterRegistry.class }) @ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class }) public class HibernateMetricsAutoConfiguration { @@ -61,13 +60,12 @@ public HibernateMetricsAutoConfiguration(MeterRegistry registry) { @Autowired public void bindEntityManagerFactoriesToRegistry( Map entityManagerFactories) { - entityManagerFactories.forEach(this::maybeBindEntityManagerFactoryToRegistry); + entityManagerFactories.forEach(this::bindEntityManagerFactoryToRegistry); } - private void maybeBindEntityManagerFactoryToRegistry(String beanName, + private void bindEntityManagerFactoryToRegistry(String beanName, EntityManagerFactory entityManagerFactory) { String entityManagerFactoryName = getEntityManagerFactoryName(beanName); - // HibernateMetrics internally checks if statistics are enabled before binding new HibernateMetrics(entityManagerFactory, entityManagerFactoryName, Collections.emptyList()).bindTo(this.registry); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java new file mode 100644 index 000000000000..ecb620329144 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for JDBC metrics. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java index 338b291aa68f..beff4b296468 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -61,17 +61,18 @@ public class HibernateMetricsAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, HibernateMetricsAutoConfiguration.class)) - .withUserConfiguration(BaseConfiguration.class).withPropertyValues( - "spring.jpa.properties.hibernate.generate_statistics:true"); + .withUserConfiguration(BaseConfiguration.class); @Test public void autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() { - this.contextRunner.run((context) -> { - context.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class); - MeterRegistry registry = context.getBean(MeterRegistry.class); - registry.get("hibernate.statements") - .tags("entityManagerFactory", "entityManagerFactory").meter(); - }); + this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") + .run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "entityManagerFactory").meter(); + }); } @Test @@ -89,7 +90,8 @@ public void autoConfiguredEntityManagerFactoryWithoutStatsIsNotInstrumented() { @Test public void entityManagerFactoryInstrumentationCanBeDisabled() { - this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false") + this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false", + "spring.jpa.properties.hibernate.generate_statistics:true") .run((context) -> { context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class); @@ -101,6 +103,8 @@ public void entityManagerFactoryInstrumentationCanBeDisabled() { @Test public void allEntityManagerFactoriesCanBeInstrumented() { this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") .withUserConfiguration(TwoEntityManagerFactoriesConfiguration.class) .run((context) -> { context.getBean("firstEntityManagerFactory", @@ -118,13 +122,15 @@ public void allEntityManagerFactoriesCanBeInstrumented() { @Test public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFactory() { this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") .withUserConfiguration( NonHibernateEntityManagerFactoryConfiguration.class) .run((context) -> { // ensure EntityManagerFactory is not an Hibernate SessionFactory assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class)) - .isInstanceOf(PersistenceException.class); + .isInstanceOf(PersistenceException.class); MeterRegistry registry = context.getBean(MeterRegistry.class); assertThat(registry.find("hibernate.statements").meter()).isNull(); }); @@ -146,6 +152,7 @@ static class MyEntity { @Id @GeneratedValue private Long id; + } @Configuration @@ -174,6 +181,7 @@ private LocalContainerEntityManagerFactoryBean createSessionFactory( new HibernateJpaVendorAdapter(), jpaProperties, null); return builder.dataSource(ds).packages(PACKAGE_CLASSES).build(); } + } @Configuration @@ -187,5 +195,7 @@ public EntityManagerFactory entityManagerFactory() { .willThrow(PersistenceException.class); return mockedFactory; } + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 71fae7e69d5f..e006f6f37ddf 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1768,32 +1768,34 @@ Also, Hikari-specific metrics are exposed with a `hikaricp` prefix. Each metric by the name of the Pool (can be controlled with `spring.datasource.name`). -[[production-ready-metrics-rabbitmq]] -==== RabbitMQ Metrics -Auto-configuration will enable the instrumentation of all available RabbitMQ connection -factories with a metric named `rabbitmq`. - [[production-ready-metrics-hibernate]] ==== Hibernate Metrics Auto-configuration enables the instrumentation of all available Hibernate -`EntityManagerFactory` objects that have statistics enabled with a metric named +`EntityManagerFactory` instances that have statistics enabled with a metric named `hibernate`. -Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from +Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from the bean name. -To enable statistics on Hibernate `EntityManagerFactory` instances, JPA property `hibernate.generate_statistics` must be set to `true`. For example, on the default -`EntityManagerFactory`, you need to set the following property: +To enable statistics, the standardJPA property `hibernate.generate_statistics` must be +set to `true`. You can enable that on the auto-configured `EntityManagerFactory` as shown +in the following example: -.application.properties [source,properties,indent=0] ---- - spring.jpa.properties.hibernate.generate_statistics=true + spring.jpa.properties.hibernate.generate_statistics=true ---- +[[production-ready-metrics-rabbitmq]] +==== RabbitMQ Metrics +Auto-configuration will enable the instrumentation of all available RabbitMQ connection +factories with a metric named `rabbitmq`. + + + [[production-ready-metrics-custom]] === Registering custom metrics To register custom metrics, inject `MeterRegistry` into your component, as shown in the From b2f34f5c20e0bab209b9e88085cd842612e7ae23 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Apr 2018 17:46:43 +0200 Subject: [PATCH 007/701] Remove spring.provides Closes gh-12435 --- .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - .../src/main/resources/META-INF/spring.provides | 1 - 50 files changed, 50 deletions(-) delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-activemq/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-actuator/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-amqp/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-aop/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-batch/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-cache/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-cloud-connectors/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra-reactive/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-elasticsearch/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb-reactive/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-neo4j/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis-reactive/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-solr/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-freemarker/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-hateoas/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-integration/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jdbc/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-json/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jta-atomikos/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jta-bitronix/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-jta-narayana/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-log4j2/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-logging/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-mail/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-mustache/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-quartz/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-security/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-test/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-thymeleaf/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-tomcat/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-validation/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-web/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/src/main/resources/META-INF/spring.provides delete mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter/src/main/resources/META-INF/spring.provides diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-activemq/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-activemq/src/main/resources/META-INF/spring.provides deleted file mode 100644 index c49ebaabdae7..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-activemq/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: activemq-broker,spring-jms diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-actuator/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-actuator/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 75b44b39adf4..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-actuator/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-boot-actuator,micrometer-core diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-amqp/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-amqp/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7620904a1415..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-amqp/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-rabbit,spring-amqp \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-aop/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-aop/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 3e5ae3a381bf..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-aop/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-aop,aspectjrt,aspectjweaver \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7c604a715713..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-artemis/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: artemis-jms-client,spring-jms diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 06ab61efdb56..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-batch-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-cache/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-cache/src/main/resources/META-INF/spring.provides deleted file mode 100644 index e50e626a4463..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-cache/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-context-support \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-cloud-connectors/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-cloud-connectors/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 89820f32f44a..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-cloud-connectors/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-cloud-spring-service-connector,spring-cloud-cloudfoundry-connector,spring-cloud-heroku-connector,spring-cloud-localconfig-connector \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra-reactive/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra-reactive/src/main/resources/META-INF/spring.provides deleted file mode 100644 index baf0a5ef88cd..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra-reactive/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-cassandra \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra/src/main/resources/META-INF/spring.provides deleted file mode 100644 index baf0a5ef88cd..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-cassandra/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-cassandra \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 49e43d3bf259..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-couchbase,reactor-core,rxjava-reactive-streams diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7eb2d6ff979f..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-couchbase diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-elasticsearch/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-elasticsearch/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 5ab75ebfdafb..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-elasticsearch/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-elasticsearch diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 9c1d8962e17e..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-orm,hibernate-entity-manager,spring-data-jpa \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 510e85a80c14..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-ldap/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-ldap-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb-reactive/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb-reactive/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 60fce3513b12..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb-reactive/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-mongodb,mongodb-driver-async,mongodb-driver-reactivestreams \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 14fde4c65bf5..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-mongodb/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-mongodb,mongodb-driver \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-neo4j/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-neo4j/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 38cc6363c56c..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-neo4j/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-neo4j \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis-reactive/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis-reactive/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7c4aeabfda91..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis-reactive/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-redis,lettuce-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7c4aeabfda91..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-redis/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-redis,lettuce-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 1d64b0573c52..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-hateoas,spring-data-rest-webmvc diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-solr/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-solr/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7c307abea5cc..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-solr/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-data-solr, solr-solrj \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-freemarker/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-freemarker/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 3f52c55a60b0..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-freemarker/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: freemarker,spring-context-support \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 3f52c55a60b0..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: freemarker,spring-context-support \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-hateoas/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-hateoas/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 216137d0d10d..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-hateoas/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-hateoas diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 63514baf3be6..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-integration-core,spring-integration-java-dsl diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jdbc/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jdbc/src/main/resources/META-INF/spring.provides deleted file mode 100644 index d33ab006e8f0..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jdbc/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-jdbc,spring-tx,HikariCP \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 8bdafc674530..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: jersey-container-servlet-core,jersey-container-servlet,jersey-server \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 671cf02179e5..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: jetty-webapp,jetty-jsp \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 062b6d60d289..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: jooq \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-json/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-json/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 323794021a2d..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-json/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-web,jackson-databind,jackson-datatype-jdk8,jackson-datatype-jsr310,jackson-module-parameter-names,jackson-module-kotlin \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-atomikos/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-atomikos/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 4500852d003b..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-atomikos/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: transactions-jms,transactions-jta,transactions-jdbc diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-bitronix/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-bitronix/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7aa4c8bb951b..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-bitronix/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: btm diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-narayana/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-narayana/src/main/resources/META-INF/spring.provides deleted file mode 100644 index ff483355d022..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jta-narayana/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: jta, jdbc, jms, jboss-transaction-spi \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-log4j2/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-log4j2/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 8b5bde70074b..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-log4j2/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: log4j2,log4j-slf4j-impl diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-logging/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-logging/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 10484626f8ad..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-logging/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: logback-classic,jcl-over-slf4j,jul-to-slf4j \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-mail/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-mail/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 0f1f2f9abd05..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-mail/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-context-support,mail \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-mustache/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-mustache/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 8e2ea4759fb7..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-mustache/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: jmustache \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-quartz/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-quartz/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 55020b99f9d8..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-quartz/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-context-support,spring-tx,quartz diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 6aaea8ae6034..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: reactor-netty \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-security/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-security/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 977cc20e37f3..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-security/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-security-web,spring-security-config \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-test/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-test/src/main/resources/META-INF/spring.provides deleted file mode 100644 index d53d3cc806c0..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-test/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-test,spring-boot,junit,mockito,hamcrest-library,assertj,jsonassert,json-path diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-thymeleaf/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-thymeleaf/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 801774b7d89c..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-thymeleaf/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: thymeleaf-spring5,thymeleaf-extras-java8time \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-tomcat/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-tomcat/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 368697023511..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-tomcat/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: tomcat-embed-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-validation/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-validation/src/main/resources/META-INF/spring.provides deleted file mode 100644 index ea07153b7bce..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-validation/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: hibernate-validator \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/src/main/resources/META-INF/spring.provides deleted file mode 100644 index d0da5438acc5..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-ws-core \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-web/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-web/src/main/resources/META-INF/spring.provides deleted file mode 100644 index d5f05dcffe82..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-web/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-webmvc,spring-web \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 9c0d58c173ba..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-webflux \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/src/main/resources/META-INF/spring.provides deleted file mode 100644 index c00ba75c8c95..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-websocket \ No newline at end of file diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter/src/main/resources/META-INF/spring.provides b/spring-boot-project/spring-boot-starters/spring-boot-starter/src/main/resources/META-INF/spring.provides deleted file mode 100644 index 7be6ca903426..000000000000 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter/src/main/resources/META-INF/spring.provides +++ /dev/null @@ -1 +0,0 @@ -provides: spring-boot,spring-context,spring-beans \ No newline at end of file From c43eb898238fd334c873e9b91172a241a5ab3f52 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Apr 2018 17:53:18 +0200 Subject: [PATCH 008/701] Make sure that finalName is read only Closes gh-12608 --- .../main/java/org/springframework/boot/maven/RepackageMojo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index f1b011736f65..a95110239851 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -86,7 +86,7 @@ public class RepackageMojo extends AbstractDependencyFilterMojo { * Name of the generated archive. * @since 1.0 */ - @Parameter(defaultValue = "${project.build.finalName}", required = true) + @Parameter(defaultValue = "${project.build.finalName}", readonly = true) private String finalName; /** From ba34bf6470a480bd875f1ab8fb26d8099e25294f Mon Sep 17 00:00:00 2001 From: Vadeg <0xvadeg@gmail.com> Date: Sat, 21 Oct 2017 13:18:52 +0200 Subject: [PATCH 009/701] Add system properties support using explicit configuration tag See gh-10741 --- .../src/it/run-disable-fork/pom.xml | 4 ++ .../src/it/run-disable-fork/verify.groovy | 2 +- .../src/it/run-jvm-system-props/pom.xml | 37 ++++++++++ .../main/java/org/test/SampleApplication.java | 44 ++++++++++++ .../src/it/run-jvm-system-props/verify.groovy | 3 + .../boot/maven/AbstractRunMojo.java | 68 +++++++++++++++++-- .../maven/SystemPropertyFormatterTests.java | 52 ++++++++++++++ 7 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/verify.groovy create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/pom.xml index 142c1c68295c..84c639e07111 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/pom.xml @@ -26,6 +26,10 @@ false -Dfoo=bar ${project.build.sourceDirectory} + + value1 + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy index baaf7a9a59b0..93ce0736fa12 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy @@ -2,6 +2,6 @@ import static org.junit.Assert.assertTrue def file = new File(basedir, "build.log") assertTrue file.text.contains("I haz been run") -assertTrue file.text.contains("Fork mode disabled, ignoring JVM argument(s) [-Dfoo=bar]") +assertTrue file.text.contains("Fork mode disabled, ignoring JVM argument(s) [-Dfoo=bar -Dproperty1=value1 -Dproperty2]") assertTrue file.text.contains("Fork mode disabled, ignoring working directory configuration") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml new file mode 100644 index 000000000000..318359736c40 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-jvmargs + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + package + + run + + + -Dfoo="value 1" -Dbar=value2 + + value1 + + + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java new file mode 100644 index 000000000000..165822591efb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2017 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.test; + +public class SampleApplication { + + public static void main(String[] args) { + String foo = System.getProperty("foo"); + if (!"value 1".equals(foo)) { + throw new IllegalStateException("foo system property mismatch (got [" + foo + "]"); + } + String bar = System.getProperty("bar"); + if (!"value2".equals(bar)) { + throw new IllegalStateException("bar system property mismatch (got [" + bar + "]"); + } + + String property1 = System.getProperty("property1"); + if (!"value1".equals(property1)) { + throw new IllegalStateException("property1 system property mismatch (got [" + property1 + "]"); + } + + String property2 = System.getProperty("property2"); + if (!"".equals(property2)) { + throw new IllegalStateException("property1 system property mismatch (got [" + property2 + "]"); + } + + System.out.println("I haz been run"); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/verify.groovy new file mode 100644 index 000000000000..841c4a97de58 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/verify.groovy @@ -0,0 +1,3 @@ +def file = new File(basedir, "build.log") +return file.text.contains("I haz been run") + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 3ec06db410bf..2923de341779 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -25,7 +25,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; @@ -169,6 +171,15 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Parameter(property = "spring-boot.run.skip", defaultValue = "false") private boolean skip; + /** + * List of JVM system properties. System property consists of key and value + * and it will be transformed to -Dkey=value format. + * In case if value is not specified or empty only key will be provided. + * @since 2.0 + */ + @Parameter(property = "spring-boot.run.systemPropertyVariabled") + private Map systemPropertyVariables; + @Override public void execute() throws MojoExecutionException, MojoFailureException { if (this.skip) { @@ -201,7 +212,8 @@ private boolean hasAgent() { } private boolean hasJvmArgs() { - return (this.jvmArguments != null && !this.jvmArguments.isEmpty()); + return (this.jvmArguments != null && !this.jvmArguments.isEmpty()) || + (this.systemPropertyVariables != null && !this.systemPropertyVariables.isEmpty()); } private boolean hasWorkingDirectorySet() { @@ -232,8 +244,22 @@ protected void logDisabledFork() { getLog().warn("Fork mode disabled, ignoring agent"); } if (hasJvmArgs()) { - getLog().warn("Fork mode disabled, ignoring JVM argument(s) [" - + this.jvmArguments + "]"); + String messageTemplate = "Fork mode disabled, ignoring JVM argument(s) [%s%s]"; + String sysPropsStr = ""; + if (this.systemPropertyVariables != null && !this.systemPropertyVariables.isEmpty()) { + sysPropsStr = this.systemPropertyVariables + .entrySet() + .stream() + .map(e -> SystemPropertyFormatter.format(e.getKey(), e.getValue())) + .collect(Collectors.joining(" ")); + } + String message = String.format( + messageTemplate, + this.jvmArguments, + sysPropsStr.isEmpty() ? sysPropsStr : " " + sysPropsStr + ); + + getLog().warn(message); } if (hasWorkingDirectorySet()) { getLog().warn("Fork mode disabled, ignoring working directory configuration"); @@ -292,7 +318,22 @@ private void addArgs(List args) { * @return a {@link RunArguments} defining the JVM arguments */ protected RunArguments resolveJvmArguments() { - return new RunArguments(this.jvmArguments); + final StringBuilder stringBuilder = new StringBuilder(); + if (this.jvmArguments != null) { + stringBuilder.append(this.jvmArguments); + } + if (this.systemPropertyVariables != null) { + String result = this.systemPropertyVariables + .entrySet() + .stream() + .map(e -> SystemPropertyFormatter.format(e.getKey(), e.getValue())) + .collect(Collectors.joining(" ")); + stringBuilder + .append(" ") + .append(result); + + } + return new RunArguments(stringBuilder.toString()); } private void addJvmArgs(List args) { @@ -509,4 +550,23 @@ public void run() { } + /** + * System properties formatter. + */ + static class SystemPropertyFormatter { + + private static final String NO_VALUE_FORMAT = "-D%s"; + private static final String KEY_VALUE_FORMAT = NO_VALUE_FORMAT + "=%s"; + + public static String format(Object key, Object value) { + if (key == null) { + return ""; + } + if (value == null || String.valueOf(value).trim().isEmpty()) { + return String.format(NO_VALUE_FORMAT, key); + } + return String.format(KEY_VALUE_FORMAT, key, value); + } + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java new file mode 100644 index 000000000000..97038d636c2a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2017 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.maven; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import org.springframework.boot.maven.AbstractRunMojo.SystemPropertyFormatter; + +/** + * Tests for {@link AbstractRunMojo.SystemPropertyFormatter} + */ +public class SystemPropertyFormatterTests { + + @Test + public void parseEmpty() throws Exception { + Assertions.assertThat(SystemPropertyFormatter.format(null, null)) + .isEqualTo(""); + } + + @Test + public void parseOnlyKey() throws Exception { + Assertions.assertThat(SystemPropertyFormatter.format("key1", null)) + .isEqualTo("-Dkey1"); + } + + @Test + public void parseKeyWithValue() throws Exception { + Assertions.assertThat(SystemPropertyFormatter.format("key1", "value1")) + .isEqualTo("-Dkey1=value1"); + } + + @Test + public void parseKeyWithEmptyValue() throws Exception { + Assertions.assertThat(SystemPropertyFormatter.format("key1", "")) + .isEqualTo("-Dkey1"); + } +} From 03539d8e16e6333790af7b4f0b19042cce44b187 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Apr 2018 11:42:49 +0200 Subject: [PATCH 010/701] Polish "Add system properties support using explicit configuration tag" Closes gh-10741 --- .../src/it/run-disable-fork/verify.groovy | 2 +- .../src/it/run-jvm-system-props/pom.xml | 2 + .../main/java/org/test/SampleApplication.java | 11 ++-- .../boot/maven/AbstractRunMojo.java | 57 +++++++----------- .../apt/examples/run-system-properties.apt.vm | 59 +++++++++++++++++++ .../src/site/apt/index.apt | 2 + .../src/site/apt/usage.apt.vm | 9 ++- .../src/site/site.xml | 1 + .../maven/SystemPropertyFormatterTests.java | 27 ++++----- 9 files changed, 111 insertions(+), 59 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy index 93ce0736fa12..752e0988f003 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-disable-fork/verify.groovy @@ -2,6 +2,6 @@ import static org.junit.Assert.assertTrue def file = new File(basedir, "build.log") assertTrue file.text.contains("I haz been run") -assertTrue file.text.contains("Fork mode disabled, ignoring JVM argument(s) [-Dfoo=bar -Dproperty1=value1 -Dproperty2]") +assertTrue file.text.contains("Fork mode disabled, ignoring JVM argument(s) [-Dproperty1=value1 -Dproperty2 -Dfoo=bar]") assertTrue file.text.contains("Fork mode disabled, ignoring working directory configuration") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml index 318359736c40..92f46e8ea698 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/pom.xml @@ -27,6 +27,8 @@ value1 + ${project.artifactId} + should-be-ignored diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java index 165822591efb..4932bfc419f9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-jvm-system-props/src/main/java/org/test/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -27,17 +27,18 @@ public static void main(String[] args) { if (!"value2".equals(bar)) { throw new IllegalStateException("bar system property mismatch (got [" + bar + "]"); } - String property1 = System.getProperty("property1"); if (!"value1".equals(property1)) { throw new IllegalStateException("property1 system property mismatch (got [" + property1 + "]"); } - String property2 = System.getProperty("property2"); if (!"".equals(property2)) { - throw new IllegalStateException("property1 system property mismatch (got [" + property2 + "]"); + throw new IllegalStateException("property2 system property mismatch (got [" + property2 + "]"); + } + String property3 = System.getProperty("property3"); + if (!"run-jvmargs".equals(property3)) { + throw new IllegalStateException("property3 system property mismatch (got [" + property3 + "]"); } - System.out.println("I haz been run"); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 2923de341779..2eb74cad2b6f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -107,6 +107,14 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Parameter(property = "spring-boot.run.jvmArguments") private String jvmArguments; + /** + * List of JVM system properties to pass to the process. NOTE: the use of system + * properties means that processes will be started by forking a new JVM. + * @since 2.1.0 + */ + @Parameter + private Map systemPropertyVariables; + /** * Arguments that should be passed to the application. On command line use commas to * separate multiple arguments. @@ -171,15 +179,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Parameter(property = "spring-boot.run.skip", defaultValue = "false") private boolean skip; - /** - * List of JVM system properties. System property consists of key and value - * and it will be transformed to -Dkey=value format. - * In case if value is not specified or empty only key will be provided. - * @since 2.0 - */ - @Parameter(property = "spring-boot.run.systemPropertyVariabled") - private Map systemPropertyVariables; - @Override public void execute() throws MojoExecutionException, MojoFailureException { if (this.skip) { @@ -213,7 +212,8 @@ private boolean hasAgent() { private boolean hasJvmArgs() { return (this.jvmArguments != null && !this.jvmArguments.isEmpty()) || - (this.systemPropertyVariables != null && !this.systemPropertyVariables.isEmpty()); + (this.systemPropertyVariables != null + && !this.systemPropertyVariables.isEmpty()); } private boolean hasWorkingDirectorySet() { @@ -244,22 +244,10 @@ protected void logDisabledFork() { getLog().warn("Fork mode disabled, ignoring agent"); } if (hasJvmArgs()) { - String messageTemplate = "Fork mode disabled, ignoring JVM argument(s) [%s%s]"; - String sysPropsStr = ""; - if (this.systemPropertyVariables != null && !this.systemPropertyVariables.isEmpty()) { - sysPropsStr = this.systemPropertyVariables - .entrySet() - .stream() - .map(e -> SystemPropertyFormatter.format(e.getKey(), e.getValue())) - .collect(Collectors.joining(" ")); - } - String message = String.format( - messageTemplate, - this.jvmArguments, - sysPropsStr.isEmpty() ? sysPropsStr : " " + sysPropsStr - ); - - getLog().warn(message); + RunArguments runArguments = resolveJvmArguments(); + getLog().warn("Fork mode disabled, ignoring JVM argument(s) [" + + Arrays.stream(runArguments.asArray()).collect( + Collectors.joining(" ")) + "]"); } if (hasWorkingDirectorySet()) { getLog().warn("Fork mode disabled, ignoring working directory configuration"); @@ -319,19 +307,15 @@ private void addArgs(List args) { */ protected RunArguments resolveJvmArguments() { final StringBuilder stringBuilder = new StringBuilder(); - if (this.jvmArguments != null) { - stringBuilder.append(this.jvmArguments); - } if (this.systemPropertyVariables != null) { - String result = this.systemPropertyVariables + stringBuilder.append(this.systemPropertyVariables .entrySet() .stream() .map(e -> SystemPropertyFormatter.format(e.getKey(), e.getValue())) - .collect(Collectors.joining(" ")); - stringBuilder - .append(" ") - .append(result); - + .collect(Collectors.joining(" "))); + } + if (this.jvmArguments != null) { + stringBuilder.append(" ").append(this.jvmArguments); } return new RunArguments(stringBuilder.toString()); } @@ -551,11 +535,12 @@ public void run() { } /** - * System properties formatter. + * Format System properties. */ static class SystemPropertyFormatter { private static final String NO_VALUE_FORMAT = "-D%s"; + private static final String KEY_VALUE_FORMAT = NO_VALUE_FORMAT + "=%s"; public static String format(Object key, Object value) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm new file mode 100644 index 000000000000..c1041e657a60 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm @@ -0,0 +1,59 @@ + ----- + Using System Properties + ----- + Stephane Nicoll + ----- + 2018-04-24 + ----- + + System properties can be specified using the <<>> attribute. + The following sets <<>> to <<>> and <<>> to 42: + +--- + + ... + + + 42 + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + test + ${my.value} + + + ... + + ... + + ... + + ... + +--- + + If the value is empty or not defined (i.e. <<<>>>), the system property + is set with an empty String as the value. + + Any String typed Maven variable can be passed as system properties. Any attempt to pass + any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the + variable expression to be passed literally (unevaluated). + + The <<>> parameter takes precedence over system properties defined with + the mechanism above. In the following example, the value for <<>> is + <<>>: + + +--- +mvn spring-boot:run -Dspring-boot.jvmArguments="-Dproperty1=overridden" +--- + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index a1f9db3d25ab..f3e47a5d96c2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -52,6 +52,8 @@ Spring Boot Maven Plugin * {{{./examples/run-debug.html}Debug the application}} + * {{{./examples/run-system-properties.html}Using system properties}} + * {{{./examples/it-random-port.html}Random port for integration tests}} * {{{./examples/it-skip.html}Skip integration tests}} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index 3452b1340bb3..ffa09b3e1f38 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -135,12 +135,15 @@ mvn spring-boot:run By default the application is executed directly from the Maven JVM. If you need to run in a forked process you can use the 'fork' option. Forking will also occur if the - 'jvmArguments' or 'agent' options are specified, or if devtools is present. + 'jvmArguments', 'systemPropertyVariables' or 'agent' options are specified, or if + devtools is present. If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the <<>> parameter, see {{{./examples/run-debug.html}Debug the application}} - for more details. As a convenience, the profiles to enable are handled by a specific - property (<<>>), see {{{./examples/run-profiles.html}Specify active profiles}}. + for more details. There is also explicit support + {{{./examples/run-system-properties.html}for system properties}}. As a convenience, the + profiles to enable are handled by a specific property (<<>>), see + {{{./examples/run-profiles.html}Specify active profiles}}. Spring Boot 1.3 has introduced <<>>, a module to improve the development-time experience when working on Spring Boot applications. To enable it, just add the following diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index 2ecc646ecab9..5e1157ab54d7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -11,6 +11,7 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java index 97038d636c2a..50b360980b08 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,37 +16,36 @@ package org.springframework.boot.maven; -import org.assertj.core.api.Assertions; import org.junit.Test; import org.springframework.boot.maven.AbstractRunMojo.SystemPropertyFormatter; +import static org.assertj.core.api.Assertions.assertThat; + /** - * Tests for {@link AbstractRunMojo.SystemPropertyFormatter} + * Tests for {@link AbstractRunMojo.SystemPropertyFormatter}. */ public class SystemPropertyFormatterTests { @Test - public void parseEmpty() throws Exception { - Assertions.assertThat(SystemPropertyFormatter.format(null, null)) - .isEqualTo(""); + public void parseEmpty() { + assertThat(SystemPropertyFormatter.format(null, null)).isEqualTo(""); } @Test - public void parseOnlyKey() throws Exception { - Assertions.assertThat(SystemPropertyFormatter.format("key1", null)) - .isEqualTo("-Dkey1"); + public void parseOnlyKey() { + assertThat(SystemPropertyFormatter.format("key1", null)).isEqualTo("-Dkey1"); } @Test - public void parseKeyWithValue() throws Exception { - Assertions.assertThat(SystemPropertyFormatter.format("key1", "value1")) + public void parseKeyWithValue() { + assertThat(SystemPropertyFormatter.format("key1", "value1")) .isEqualTo("-Dkey1=value1"); } @Test - public void parseKeyWithEmptyValue() throws Exception { - Assertions.assertThat(SystemPropertyFormatter.format("key1", "")) - .isEqualTo("-Dkey1"); + public void parseKeyWithEmptyValue() { + assertThat(SystemPropertyFormatter.format("key1", "")).isEqualTo("-Dkey1"); } + } From 95f7e3ca37b3d8139f7a5e299f1a96d5af509af1 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 9 Apr 2018 00:11:27 +0300 Subject: [PATCH 011/701] Add support for environment variables See gh-12800 --- .../src/main/asciidoc/howto.adoc | 8 ++ .../boot/loader/tools/RunProcess.java | 12 ++- .../src/it/run-envargs/pom.xml | 38 +++++++++ .../main/java/org/test/SampleApplication.java | 40 +++++++++ .../src/it/run-envargs/verify.groovy | 3 + .../boot/maven/AbstractRunMojo.java | 44 +++++++++- .../boot/maven/EnvVariables.java | 81 +++++++++++++++++++ .../springframework/boot/maven/RunMojo.java | 6 +- .../springframework/boot/maven/StartMojo.java | 10 ++- .../src/site/apt/examples/run-with-env.apt.vm | 43 ++++++++++ .../src/site/apt/index.apt | 2 + .../src/site/apt/usage.apt.vm | 9 ++- .../src/site/site.xml | 1 + .../boot/maven/EnvVariablesTests.java | 72 +++++++++++++++++ 14 files changed, 354 insertions(+), 15 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 7e43d55146be..75cbcda8a40c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -2771,6 +2771,14 @@ See {spring-boot-maven-plugin-site}/examples/run-debug.html[this example] for mo details. +[[howto-set-env-maven-run]] +=== Run Spring Boot Application with Environment variables Started with Maven +To set up the environment variables to a Spring Boot application that was started with Maven, you +can use the `environmentVariables` property of the {spring-boot-maven-plugin-site}[maven plugin]. + +See {spring-boot-maven-plugin-site}/examples/run-with-env.html[this example] for more +details. + [[howto-build-an-executable-archive-with-ant]] === Build an Executable Archive from Ant without Using `spring-boot-antlib` diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index 03b2a90cf4ba..e8b460cc7bbc 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Map; /** * Utility used to run a process. @@ -28,6 +30,7 @@ * @author Dave Syer * @author Andy Wilkinson * @author Stephane Nicoll + * @author Dmytro Nosan * @since 1.1.0 */ public class RunProcess { @@ -63,14 +66,19 @@ public RunProcess(File workingDirectory, String... command) { } public int run(boolean waitForProcess, String... args) throws IOException { - return run(waitForProcess, Arrays.asList(args)); + return run(waitForProcess, Arrays.asList(args), Collections.emptyMap()); } - protected int run(boolean waitForProcess, Collection args) + public int run(boolean waitForProcess, String[] args, Map environmentVariables) throws IOException { + return run(waitForProcess, Arrays.asList(args), environmentVariables); + } + + protected int run(boolean waitForProcess, Collection args, Map environmentVariables) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.directory(this.workingDirectory); builder.command().addAll(args); + builder.environment().putAll(environmentVariables); builder.redirectErrorStream(true); builder.inheritIO(); try { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml new file mode 100644 index 000000000000..b14692f6064d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-envargs + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + package + + run + + + + 5000 + Some Text + + + + + + + + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java new file mode 100644 index 000000000000..044ec3603575 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2018 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.test; + +public class SampleApplication { + + + public static void main(String[] args) { + assertEnvValue("ENV1", "5000"); + assertEnvValue("ENV2", "Some Text"); + assertEnvValue("ENV3", ""); + assertEnvValue("ENV4", ""); + + System.out.println("I haz been run"); + + } + + + static void assertEnvValue(String envKey, String expectedValue) { + String actual = System.getenv(envKey); + if (!expectedValue.equals(actual)) { + throw new IllegalStateException("env property [" + envKey + "] mismatch (got [" + actual + "], expected [" + expectedValue + "]"); + } + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy new file mode 100644 index 000000000000..841c4a97de58 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/verify.groovy @@ -0,0 +1,3 @@ +def file = new File(basedir, "build.log") +return file.text.contains("I haz been run") + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 2eb74cad2b6f..6c2e76ea134c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -48,6 +49,7 @@ * @author Stephane Nicoll * @author David Liu * @author Daniel Young + * @author Dmytro Nosan * @see RunMojo * @see StartMojo */ @@ -115,6 +117,15 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Parameter private Map systemPropertyVariables; + /** + * List of Environment variables that should be associated with the forked process used to run the + * application. + *

NOTE: the use of Environment variables means that processes will be started by forking a + * new JVM. + */ + @Parameter(property = "spring-boot.run.environmentVariables") + private Map environmentVariables; + /** * Arguments that should be passed to the application. On command line use commas to * separate multiple arguments. @@ -203,7 +214,7 @@ protected boolean isFork() { * @see #logDisabledFork() */ protected boolean enableForkByDefault() { - return hasAgent() || hasJvmArgs() || hasWorkingDirectorySet(); + return hasAgent() || hasJvmArgs() || hasEnvVariables() || hasWorkingDirectorySet(); } private boolean hasAgent() { @@ -216,6 +227,11 @@ private boolean hasJvmArgs() { && !this.systemPropertyVariables.isEmpty()); } + private boolean hasEnvVariables() { + return (this.environmentVariables != null && !this.environmentVariables.isEmpty()); + } + + private boolean hasWorkingDirectorySet() { return this.workingDirectory != null; } @@ -257,22 +273,27 @@ protected void logDisabledFork() { private void doRunWithForkedJvm(String startClassName) throws MojoExecutionException, MojoFailureException { List args = new ArrayList<>(); + Map envVariables = new LinkedHashMap<>(); addAgents(args); addJvmArgs(args); addClasspath(args); args.add(startClassName); addArgs(args); - runWithForkedJvm(this.workingDirectory, args); + addEnvironmentVariables(envVariables); + runWithForkedJvm(this.workingDirectory, args, envVariables); } + /** * Run with a forked VM, using the specified command line arguments. * @param workingDirectory the working directory of the forked JVM * @param args the arguments (JVM arguments and application arguments) + * @param environmentVariables the environment variables; * @throws MojoExecutionException in case of MOJO execution errors * @throws MojoFailureException in case of MOJO failures */ - protected abstract void runWithForkedJvm(File workingDirectory, List args) + protected abstract void runWithForkedJvm(File workingDirectory, List args, + Map environmentVariables) throws MojoExecutionException, MojoFailureException; /** @@ -295,12 +316,29 @@ protected RunArguments resolveApplicationArguments() { return runArguments; } + + /** + * Resolve the environment variables to use. + * + * @return a {@link EnvVariables} defining the environment variables + */ + protected EnvVariables resolveEnvVariables() { + return new EnvVariables(this.environmentVariables); + } + + private void addArgs(List args) { RunArguments applicationArguments = resolveApplicationArguments(); Collections.addAll(args, applicationArguments.asArray()); logArguments("Application argument(s): ", this.arguments); } + private void addEnvironmentVariables(Map environmentVariables) { + EnvVariables envVariables = resolveEnvVariables(); + environmentVariables.putAll(envVariables.asMap()); + logArguments("Environment variable(s): ", envVariables.asArray()); + } + /** * Resolve the JVM arguments to use. * @return a {@link RunArguments} defining the JVM arguments diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java new file mode 100644 index 000000000000..0ee67f00e987 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2018 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.maven; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Utility class for working with Env variables. + * + * @author Dmytro Nosan + */ +class EnvVariables { + + private static final String SPACE = "="; + private static final String NO_VALUE = ""; + + private final Map args = new LinkedHashMap<>(); + + EnvVariables(Map args) { + this.args.putAll(getArgs(args)); + } + + Map asMap() { + return Collections.unmodifiableMap(this.args); + } + + String[] asArray() { + List args = new ArrayList<>(this.args.size()); + for (Map.Entry arg : this.args.entrySet()) { + args.add(arg.getKey() + SPACE + arg.getValue()); + } + return args.toArray(new String[args.size()]); + } + + + private Map getArgs(Map args) { + + if (args == null || args.isEmpty()) { + return Collections.emptyMap(); + } + + Map result = new LinkedHashMap<>(); + for (Map.Entry e : args.entrySet()) { + if (hasText(e.getKey())) { + result.put(e.getKey(), getValue(e.getValue())); + } + } + return result; + } + + private String getValue(String value) { + if (hasText(value)) { + return value; + } + return NO_VALUE; + } + + private boolean hasText(String source) { + return source != null && !source.trim().isEmpty(); + } + + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 1280b881625f..6231252c6b89 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -20,6 +20,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.List; +import java.util.Map; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Execute; @@ -34,6 +35,7 @@ * Run an executable archive application. * * @author Phillip Webb + * @author Dmytro Nosan * @author Stephane Nicoll * @author Andy Wilkinson */ @@ -64,14 +66,14 @@ protected void logDisabledFork() { } @Override - protected void runWithForkedJvm(File workingDirectory, List args) + protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); Runtime.getRuntime() .addShutdownHook(new Thread(new RunProcessKiller(runProcess))); - int exitCode = runProcess.run(true, args.toArray(new String[0])); + int exitCode = runProcess.run(true, args.toArray(new String[0]), environmentVariables); if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) { return; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 9a27ca8479e9..5760e04f9026 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -23,6 +23,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import javax.management.MBeanServerConnection; @@ -46,6 +47,7 @@ * stopped after. * * @author Stephane Nicoll + * @author Dmytro Nosan * @since 1.3.0 * @see StopMojo */ @@ -88,9 +90,9 @@ public class StartMojo extends AbstractRunMojo { private final Object lock = new Object(); @Override - protected void runWithForkedJvm(File workingDirectory, List args) + protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException, MojoFailureException { - RunProcess runProcess = runProcess(workingDirectory, args); + RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables); try { waitForSpringApplication(); } @@ -100,12 +102,12 @@ protected void runWithForkedJvm(File workingDirectory, List args) } } - private RunProcess runProcess(File workingDirectory, List args) + private RunProcess runProcess(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); - runProcess.run(false, args.toArray(new String[0])); + runProcess.run(false, args.toArray(new String[0]), environmentVariables); return runProcess; } catch (Exception ex) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm new file mode 100644 index 000000000000..7bbe5b7b93c2 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm @@ -0,0 +1,43 @@ + ----- + Specify environment variables + ----- +Dmytro Nosan + ----- + 2018-04-08 + ----- + + The environmnet variables to use for a particular application can be specified using the <<>> + argument. The following configuration enables the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + 5000 + Some Text + + + + + ... + + ... + + ... + + ... + +--- + + Note that since you specified some Environment variables, the process is forked automatically. + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index f3e47a5d96c2..5ed3cc8a3758 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -60,6 +60,8 @@ Spring Boot Maven Plugin * {{{./examples/run-profiles.html}Specify active profiles}} + * {{{./examples/run-with-env.html}Specify Environment variables}} + * {{{./examples/build-info.html}Generate build information}} * {{{./examples/custom-layout.html}Custom layout}} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index ffa09b3e1f38..1bf825f0ad40 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -135,14 +135,15 @@ mvn spring-boot:run By default the application is executed directly from the Maven JVM. If you need to run in a forked process you can use the 'fork' option. Forking will also occur if the - 'jvmArguments', 'systemPropertyVariables' or 'agent' options are specified, or if - devtools is present. + 'jvmArguments', 'systemPropertyVariables', 'environmentVariables' or 'agent' options + are specified, or if devtools is present. If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the <<>> parameter, see {{{./examples/run-debug.html}Debug the application}} for more details. There is also explicit support - {{{./examples/run-system-properties.html}for system properties}}. As a convenience, the - profiles to enable are handled by a specific property (<<>>), see + {{{./examples/run-system-properties.html}for system properties}} and + {{{./examples/run-with-env.html}environment variables}}. As a convenience, the profiles + to enable are handled by a specific property (<<>>), see {{{./examples/run-profiles.html}Specify active profiles}}. Spring Boot 1.3 has introduced <<>>, a module to improve the development-time diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index 5e1157ab54d7..e0000dd907ff 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -15,6 +15,7 @@ + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java new file mode 100644 index 000000000000..595fe24b7a6b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2018 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.maven; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EnvVariables}. + * + * @author Dmytro Nosan + */ +public class EnvVariablesTests { + + @Test + public void asNull() { + Map args = new EnvVariables(null).asMap(); + assertThat(args).hasSize(0); + } + + + @Test + public void asArray() { + assertThat(new EnvVariables(getTestArgs()).asArray()) + .contains("key=My Value") + .contains("key1= tt ") + .contains("key2=") + .contains("key3="); + } + + @Test + public void asMap() { + assertThat(new EnvVariables(getTestArgs()).asMap()) + .containsEntry("key", "My Value") + .containsEntry("key1", " tt ") + .containsEntry("key2", "") + .containsEntry("key3", ""); + } + + + private Map getTestArgs() { + Map args = new LinkedHashMap<>(); + args.put("key", "My Value"); + //should not be trimmed + args.put("key1", " tt "); + args.put("key2", " "); + args.put("key3", null); + return args; + } + + + + +} From 40b7e02793184c377391d501dd5c843a31e1d1e4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Apr 2018 15:44:59 +0200 Subject: [PATCH 012/701] Polish "Add support for environment variables" Closes gh-12800 --- .../src/main/asciidoc/howto.adoc | 8 --- .../boot/loader/tools/RunProcess.java | 8 +-- .../main/java/org/test/SampleApplication.java | 8 ++- .../boot/maven/AbstractRunMojo.java | 26 ++++------ .../boot/maven/EnvVariables.java | 46 ++++++----------- .../springframework/boot/maven/RunMojo.java | 5 +- .../springframework/boot/maven/StartMojo.java | 9 ++-- .../apt/examples/run-env-variables.apt.vm | 50 +++++++++++++++++++ .../src/site/apt/examples/run-with-env.apt.vm | 43 ---------------- .../src/site/apt/index.apt | 4 +- .../src/site/apt/usage.apt.vm | 11 ++-- .../src/site/site.xml | 2 +- .../boot/maven/EnvVariablesTests.java | 22 +++----- 13 files changed, 103 insertions(+), 139 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 75cbcda8a40c..7e43d55146be 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -2771,14 +2771,6 @@ See {spring-boot-maven-plugin-site}/examples/run-debug.html[this example] for mo details. -[[howto-set-env-maven-run]] -=== Run Spring Boot Application with Environment variables Started with Maven -To set up the environment variables to a Spring Boot application that was started with Maven, you -can use the `environmentVariables` property of the {spring-boot-maven-plugin-site}[maven plugin]. - -See {spring-boot-maven-plugin-site}/examples/run-with-env.html[this example] for more -details. - [[howto-build-an-executable-archive-with-ant]] === Build an Executable Archive from Ant without Using `spring-boot-antlib` diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index e8b460cc7bbc..36f4ba5dfde1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -69,12 +69,8 @@ public int run(boolean waitForProcess, String... args) throws IOException { return run(waitForProcess, Arrays.asList(args), Collections.emptyMap()); } - public int run(boolean waitForProcess, String[] args, Map environmentVariables) throws IOException { - return run(waitForProcess, Arrays.asList(args), environmentVariables); - } - - protected int run(boolean waitForProcess, Collection args, Map environmentVariables) - throws IOException { + public int run(boolean waitForProcess, Collection args, + Map environmentVariables) throws IOException { ProcessBuilder builder = new ProcessBuilder(this.command); builder.directory(this.workingDirectory); builder.command().addAll(args); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java index 044ec3603575..c60eabec3917 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/run-envargs/src/main/java/org/test/SampleApplication.java @@ -18,7 +18,6 @@ public class SampleApplication { - public static void main(String[] args) { assertEnvValue("ENV1", "5000"); assertEnvValue("ENV2", "Some Text"); @@ -26,14 +25,13 @@ public static void main(String[] args) { assertEnvValue("ENV4", ""); System.out.println("I haz been run"); - } - - static void assertEnvValue(String envKey, String expectedValue) { + private static void assertEnvValue(String envKey, String expectedValue) { String actual = System.getenv(envKey); if (!expectedValue.equals(actual)) { - throw new IllegalStateException("env property [" + envKey + "] mismatch (got [" + actual + "], expected [" + expectedValue + "]"); + throw new IllegalStateException("env property [" + envKey + "] mismatch " + + "(got [" + actual + "], expected [" + expectedValue + "]"); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 6c2e76ea134c..74767347c5a8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -118,12 +117,12 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { private Map systemPropertyVariables; /** - * List of Environment variables that should be associated with the forked process used to run the - * application. - *

NOTE: the use of Environment variables means that processes will be started by forking a - * new JVM. + * List of Environment variables that should be associated with the forked process + * used to run the application. NOTE: the use of Environment variables means that + * processes will be started by forking a new JVM. + * @since 2.1 */ - @Parameter(property = "spring-boot.run.environmentVariables") + @Parameter private Map environmentVariables; /** @@ -231,7 +230,6 @@ private boolean hasEnvVariables() { return (this.environmentVariables != null && !this.environmentVariables.isEmpty()); } - private boolean hasWorkingDirectorySet() { return this.workingDirectory != null; } @@ -273,22 +271,19 @@ protected void logDisabledFork() { private void doRunWithForkedJvm(String startClassName) throws MojoExecutionException, MojoFailureException { List args = new ArrayList<>(); - Map envVariables = new LinkedHashMap<>(); addAgents(args); addJvmArgs(args); addClasspath(args); args.add(startClassName); addArgs(args); - addEnvironmentVariables(envVariables); - runWithForkedJvm(this.workingDirectory, args, envVariables); + runWithForkedJvm(this.workingDirectory, args, determineEnvironmentVariables()); } - /** * Run with a forked VM, using the specified command line arguments. * @param workingDirectory the working directory of the forked JVM * @param args the arguments (JVM arguments and application arguments) - * @param environmentVariables the environment variables; + * @param environmentVariables the environment variables * @throws MojoExecutionException in case of MOJO execution errors * @throws MojoFailureException in case of MOJO failures */ @@ -316,27 +311,24 @@ protected RunArguments resolveApplicationArguments() { return runArguments; } - /** * Resolve the environment variables to use. - * * @return a {@link EnvVariables} defining the environment variables */ protected EnvVariables resolveEnvVariables() { return new EnvVariables(this.environmentVariables); } - private void addArgs(List args) { RunArguments applicationArguments = resolveApplicationArguments(); Collections.addAll(args, applicationArguments.asArray()); logArguments("Application argument(s): ", this.arguments); } - private void addEnvironmentVariables(Map environmentVariables) { + private Map determineEnvironmentVariables() { EnvVariables envVariables = resolveEnvVariables(); - environmentVariables.putAll(envVariables.asMap()); logArguments("Environment variable(s): ", envVariables.asArray()); + return envVariables.asMap(); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java index 0ee67f00e987..a38d4876e1cb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java @@ -29,53 +29,39 @@ */ class EnvVariables { - private static final String SPACE = "="; - private static final String NO_VALUE = ""; + private final Map variables; - private final Map args = new LinkedHashMap<>(); - - EnvVariables(Map args) { - this.args.putAll(getArgs(args)); - } - - Map asMap() { - return Collections.unmodifiableMap(this.args); - } - - String[] asArray() { - List args = new ArrayList<>(this.args.size()); - for (Map.Entry arg : this.args.entrySet()) { - args.add(arg.getKey() + SPACE + arg.getValue()); - } - return args.toArray(new String[args.size()]); + EnvVariables(Map variables) { + this.variables = parseEnvVariables(variables); } - - private Map getArgs(Map args) { - + private static Map parseEnvVariables(Map args) { if (args == null || args.isEmpty()) { return Collections.emptyMap(); } - Map result = new LinkedHashMap<>(); for (Map.Entry e : args.entrySet()) { - if (hasText(e.getKey())) { + if (e.getKey() != null) { result.put(e.getKey(), getValue(e.getValue())); } } return result; } - private String getValue(String value) { - if (hasText(value)) { - return value; - } - return NO_VALUE; + private static String getValue(String value) { + return (value != null ? value : ""); } - private boolean hasText(String source) { - return source != null && !source.trim().isEmpty(); + public Map asMap() { + return Collections.unmodifiableMap(this.variables); } + public String[] asArray() { + List args = new ArrayList<>(this.variables.size()); + for (Map.Entry arg : this.variables.entrySet()) { + args.add(arg.getKey() + "=" + arg.getValue()); + } + return args.toArray(new String[0]); + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 6231252c6b89..cf75bd6b50ac 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -66,14 +66,15 @@ protected void logDisabledFork() { } @Override - protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) + protected void runWithForkedJvm(File workingDirectory, List args, + Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); Runtime.getRuntime() .addShutdownHook(new Thread(new RunProcessKiller(runProcess))); - int exitCode = runProcess.run(true, args.toArray(new String[0]), environmentVariables); + int exitCode = runProcess.run(true, args, environmentVariables); if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) { return; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 5760e04f9026..151981c6c275 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -47,7 +47,6 @@ * stopped after. * * @author Stephane Nicoll - * @author Dmytro Nosan * @since 1.3.0 * @see StopMojo */ @@ -90,7 +89,8 @@ public class StartMojo extends AbstractRunMojo { private final Object lock = new Object(); @Override - protected void runWithForkedJvm(File workingDirectory, List args, Map environmentVariables) + protected void runWithForkedJvm(File workingDirectory, List args, + Map environmentVariables) throws MojoExecutionException, MojoFailureException { RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables); try { @@ -102,12 +102,13 @@ protected void runWithForkedJvm(File workingDirectory, List args, Map args, Map environmentVariables) + private RunProcess runProcess(File workingDirectory, List args, + Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); - runProcess.run(false, args.toArray(new String[0]), environmentVariables); + runProcess.run(false, args, environmentVariables); return runProcess; } catch (Exception ex) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm new file mode 100644 index 000000000000..855fc8a3296e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm @@ -0,0 +1,50 @@ + ----- + Using environment variables + ----- +Dmytro Nosan + ----- + 2018-04-08 + ----- + + Environment variables can be specified using the <<>> attribute. + The following sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + 5000 + Some Text + + + + + ... + + ... + + ... + + ... + +--- + + If the value is empty or not defined (i.e. <<<>>>), the env variable is set + with an empty String as the value. + + Any String typed Maven variable can be passed as system properties. Any attempt to pass + any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the + variable expression to be passed literally (unevaluated). + + Environment variables defined this way take precedence over existing values. + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm deleted file mode 100644 index 7bbe5b7b93c2..000000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-with-env.apt.vm +++ /dev/null @@ -1,43 +0,0 @@ - ----- - Specify environment variables - ----- -Dmytro Nosan - ----- - 2018-04-08 - ----- - - The environmnet variables to use for a particular application can be specified using the <<>> - argument. The following configuration enables the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables: - ---- - - ... - - ... - - ... - - ${project.groupId} - ${project.artifactId} - ${project.version} - - - 5000 - Some Text - - - - - ... - - ... - - ... - - ... - ---- - - Note that since you specified some Environment variables, the process is forked automatically. - - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index 5ed3cc8a3758..22fa6c63cadb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -54,14 +54,14 @@ Spring Boot Maven Plugin * {{{./examples/run-system-properties.html}Using system properties}} + * {{{./examples/run-env-variables.html}Using environment variables}} + * {{{./examples/it-random-port.html}Random port for integration tests}} * {{{./examples/it-skip.html}Skip integration tests}} * {{{./examples/run-profiles.html}Specify active profiles}} - * {{{./examples/run-with-env.html}Specify Environment variables}} - * {{{./examples/build-info.html}Generate build information}} * {{{./examples/custom-layout.html}Custom layout}} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm index 1bf825f0ad40..f7cc89ed0659 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/usage.apt.vm @@ -140,11 +140,12 @@ mvn spring-boot:run If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the <<>> parameter, see {{{./examples/run-debug.html}Debug the application}} - for more details. There is also explicit support - {{{./examples/run-system-properties.html}for system properties}} and - {{{./examples/run-with-env.html}environment variables}}. As a convenience, the profiles - to enable are handled by a specific property (<<>>), see - {{{./examples/run-profiles.html}Specify active profiles}}. + for more details. There is also explicit support for + {{{./examples/run-system-properties.html}system properties}} and + {{{./examples/run-env-variables.html}environment variables}}. + + As a convenience, the profiles to enable are handled by a specific property ( + <<>>), see {{{./examples/run-profiles.html}Specify active profiles}}. Spring Boot 1.3 has introduced <<>>, a module to improve the development-time experience when working on Spring Boot applications. To enable it, just add the following diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml index e0000dd907ff..89218fd978de 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/site.xml @@ -12,10 +12,10 @@ + - diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java index 595fe24b7a6b..21242e19b7f4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java @@ -22,6 +22,7 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link EnvVariables}. @@ -33,40 +34,29 @@ public class EnvVariablesTests { @Test public void asNull() { Map args = new EnvVariables(null).asMap(); - assertThat(args).hasSize(0); + assertThat(args).isEmpty(); } - @Test public void asArray() { assertThat(new EnvVariables(getTestArgs()).asArray()) - .contains("key=My Value") - .contains("key1= tt ") - .contains("key2=") - .contains("key3="); + .contains("key=My Value", "key1= tt ", "key2= ", "key3="); } @Test public void asMap() { - assertThat(new EnvVariables(getTestArgs()).asMap()) - .containsEntry("key", "My Value") - .containsEntry("key1", " tt ") - .containsEntry("key2", "") - .containsEntry("key3", ""); + assertThat(new EnvVariables(getTestArgs()).asMap()).containsExactly( + entry("key", "My Value"), entry("key1", " tt "), entry("key2", " "), + entry("key3", "")); } - private Map getTestArgs() { Map args = new LinkedHashMap<>(); args.put("key", "My Value"); - //should not be trimmed args.put("key1", " tt "); args.put("key2", " "); args.put("key3", null); return args; } - - - } From d4729f5389db60092a11ad82566876b07769c463 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Apr 2018 15:52:47 +0200 Subject: [PATCH 013/701] Polish --- .../java/org/springframework/boot/maven/AbstractRunMojo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 74767347c5a8..3ddfe3c59703 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -111,7 +111,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { /** * List of JVM system properties to pass to the process. NOTE: the use of system * properties means that processes will be started by forking a new JVM. - * @since 2.1.0 + * @since 2.1 */ @Parameter private Map systemPropertyVariables; From fd47b728c16ea55b4f0fba6189b9556a0a706571 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Apr 2018 16:26:51 +0200 Subject: [PATCH 014/701] Properly handle values with spaces Closes gh-10741 --- .../springframework/boot/maven/AbstractRunMojo.java | 10 +++------- .../src/site/apt/examples/run-env-variables.apt.vm | 3 ++- .../src/site/apt/examples/run-system-properties.apt.vm | 4 +++- .../boot/maven/SystemPropertyFormatterTests.java | 8 +++++++- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 3ddfe3c59703..8a26e9d12dcb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -569,18 +569,14 @@ public void run() { */ static class SystemPropertyFormatter { - private static final String NO_VALUE_FORMAT = "-D%s"; - - private static final String KEY_VALUE_FORMAT = NO_VALUE_FORMAT + "=%s"; - public static String format(Object key, Object value) { if (key == null) { return ""; } - if (value == null || String.valueOf(value).trim().isEmpty()) { - return String.format(NO_VALUE_FORMAT, key); + if (value == null || String.valueOf(value).isEmpty()) { + return String.format("-D%s", key); } - return String.format(KEY_VALUE_FORMAT, key, value); + return String.format("-D%s=\"%s\"", key, value); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm index 855fc8a3296e..0fc0f6934b4b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm @@ -39,7 +39,8 @@ Dmytro Nosan --- If the value is empty or not defined (i.e. <<<>>>), the env variable is set - with an empty String as the value. + with an empty String as the value. Maven trims values specified in the pom so it is + not possible to specify a env variable who needs to start or end with a space. Any String typed Maven variable can be passed as system properties. Any attempt to pass any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm index c1041e657a60..962b8e6c3521 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm @@ -40,7 +40,9 @@ --- If the value is empty or not defined (i.e. <<<>>>), the system property - is set with an empty String as the value. + is set with an empty String as the value. Maven trims values specified in the pom so it + is not possible to specify a System property who needs to start or end with a space via + this mechanism: consider using <<> instead. Any String typed Maven variable can be passed as system properties. Any attempt to pass any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java index 50b360980b08..8a18a8a93fd5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java @@ -40,7 +40,7 @@ public void parseOnlyKey() { @Test public void parseKeyWithValue() { assertThat(SystemPropertyFormatter.format("key1", "value1")) - .isEqualTo("-Dkey1=value1"); + .isEqualTo("-Dkey1=\"value1\""); } @Test @@ -48,4 +48,10 @@ public void parseKeyWithEmptyValue() { assertThat(SystemPropertyFormatter.format("key1", "")).isEqualTo("-Dkey1"); } + @Test + public void parseKeyWithOnlySpace() { + assertThat(SystemPropertyFormatter.format("key1", " ")) + .isEqualTo("-Dkey1=\" \""); + } + } From 080e189d06ddec61eb9c56d129de47256340cca9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Apr 2018 10:40:23 +0200 Subject: [PATCH 015/701] Fix broken syntax --- .../src/site/apt/examples/run-system-properties.apt.vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm index 962b8e6c3521..493edf8c6478 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm @@ -42,7 +42,7 @@ If the value is empty or not defined (i.e. <<<>>>), the system property is set with an empty String as the value. Maven trims values specified in the pom so it is not possible to specify a System property who needs to start or end with a space via - this mechanism: consider using <<> instead. + this mechanism: consider using <<>> instead. Any String typed Maven variable can be passed as system properties. Any attempt to pass any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the From b090280b0c37a26d72c3fcc37a26efc5c46113b8 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Apr 2018 13:35:49 +0200 Subject: [PATCH 016/701] Improve Couchbase auto-configuration This commit improves the couchbase auto-configuration so that it is easier to customize the way the connection to the couchbase server is initiated. See gh-11146 --- .../couchbase/CouchbaseAutoConfiguration.java | 120 +------------ .../couchbase/CouchbaseConfiguration.java | 157 ++++++++++++++++++ ...uchbaseConfigurerAdapterConfiguration.java | 4 +- .../CouchbaseAutoConfigurationTests.java | 4 - 4 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java index 45107c1ac715..142f9e98dcc4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -16,31 +16,18 @@ package org.springframework.boot.autoconfigure.couchbase; -import java.util.function.BiFunction; - -import com.couchbase.client.core.env.KeyValueServiceConfig; -import com.couchbase.client.core.env.QueryServiceConfig; -import com.couchbase.client.core.env.ViewServiceConfig; -import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.CouchbaseBucket; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.cluster.ClusterInfo; -import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 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.couchbase.CouchbaseProperties.Endpoints; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Endpoints.CouchbaseService; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration Auto-configuration} for Couchbase. @@ -58,109 +45,8 @@ public class CouchbaseAutoConfiguration { @Configuration @ConditionalOnMissingBean(value = CouchbaseConfiguration.class, type = "org.springframework.data.couchbase.config.CouchbaseConfigurer") - public static class CouchbaseConfiguration { - - private final CouchbaseProperties properties; - - public CouchbaseConfiguration(CouchbaseProperties properties) { - this.properties = properties; - } - - @Bean - @Primary - public DefaultCouchbaseEnvironment couchbaseEnvironment() throws Exception { - return initializeEnvironmentBuilder(this.properties).build(); - } - - @Bean - @Primary - public Cluster couchbaseCluster() throws Exception { - return CouchbaseCluster.create(couchbaseEnvironment(), - this.properties.getBootstrapHosts()); - } - - @Bean - @Primary - @DependsOn("couchbaseClient") - public ClusterInfo couchbaseClusterInfo() throws Exception { - return couchbaseCluster() - .clusterManager(this.properties.getBucket().getName(), - this.properties.getBucket().getPassword()) - .info(); - } - - @Bean - @Primary - public Bucket couchbaseClient() throws Exception { - return couchbaseCluster().openBucket(this.properties.getBucket().getName(), - this.properties.getBucket().getPassword()); - } - - /** - * Initialize an environment builder based on the specified settings. - * @param properties the couchbase properties to use - * @return the {@link DefaultCouchbaseEnvironment} builder. - */ - protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder( - CouchbaseProperties properties) { - CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints(); - CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts(); - DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment - .builder(); - if (timeouts.getConnect() != null) { - builder = builder.connectTimeout(timeouts.getConnect().toMillis()); - } - builder = builder.keyValueServiceConfig( - KeyValueServiceConfig.create(endpoints.getKeyValue())); - if (timeouts.getKeyValue() != null) { - builder = builder.kvTimeout(timeouts.getKeyValue().toMillis()); - } - if (timeouts.getQuery() != null) { - builder = builder.queryTimeout(timeouts.getQuery().toMillis()); - builder = builder.queryServiceConfig(getQueryServiceConfig(endpoints)); - builder = builder.viewServiceConfig(getViewServiceConfig(endpoints)); - } - if (timeouts.getSocketConnect() != null) { - builder = builder.socketConnectTimeout( - (int) timeouts.getSocketConnect().toMillis()); - } - if (timeouts.getView() != null) { - builder = builder.viewTimeout(timeouts.getView().toMillis()); - } - CouchbaseProperties.Ssl ssl = properties.getEnv().getSsl(); - if (ssl.getEnabled()) { - builder = builder.sslEnabled(true); - if (ssl.getKeyStore() != null) { - builder = builder.sslKeystoreFile(ssl.getKeyStore()); - } - if (ssl.getKeyStorePassword() != null) { - builder = builder.sslKeystorePassword(ssl.getKeyStorePassword()); - } - } - return builder; - } - - @SuppressWarnings("deprecation") - private QueryServiceConfig getQueryServiceConfig(Endpoints endpoints) { - return getServiceConfig(endpoints.getQueryservice(), endpoints.getQuery(), - QueryServiceConfig::create); - } - - @SuppressWarnings("deprecation") - private ViewServiceConfig getViewServiceConfig(Endpoints endpoints) { - return getServiceConfig(endpoints.getViewservice(), endpoints.getView(), - ViewServiceConfig::create); - } - - private T getServiceConfig(CouchbaseService service, Integer fallback, - BiFunction factory) { - if (service.getMinEndpoints() != 1 || service.getMaxEndpoints() != 1) { - return factory.apply(service.getMinEndpoints(), - service.getMaxEndpoints()); - } - int endpoints = (fallback != null ? fallback : 1); - return factory.apply(endpoints, endpoints); - } + @Import(CouchbaseConfiguration.class) + static class DefaultCouchbaseConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java new file mode 100644 index 000000000000..ac5c688ef1b9 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java @@ -0,0 +1,157 @@ +/* + * Copyright 2012-2018 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.autoconfigure.couchbase; + +import java.util.List; +import java.util.function.BiFunction; + +import com.couchbase.client.core.env.KeyValueServiceConfig; +import com.couchbase.client.core.env.QueryServiceConfig; +import com.couchbase.client.core.env.ViewServiceConfig; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; + +import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Endpoints; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Endpoints.CouchbaseService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Primary; + +/** + * Support class to configure Couchbase based on {@link CouchbaseProperties}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Configuration +public class CouchbaseConfiguration { + + private final CouchbaseProperties properties; + + public CouchbaseConfiguration(CouchbaseProperties properties) { + this.properties = properties; + } + + @Bean + @Primary + public DefaultCouchbaseEnvironment couchbaseEnvironment() { + return initializeEnvironmentBuilder(this.properties).build(); + } + + @Bean + @Primary + public Cluster couchbaseCluster() { + return CouchbaseCluster.create(couchbaseEnvironment(), + determineBootstrapHosts()); + } + + /** + * Determine the Couchbase nodes to bootstrap from. + * @return the Couchbase nodes to bootstrap from + */ + protected List determineBootstrapHosts() { + return this.properties.getBootstrapHosts(); + } + + @Bean + @Primary + @DependsOn("couchbaseClient") + public ClusterInfo couchbaseClusterInfo() { + return couchbaseCluster() + .clusterManager(this.properties.getBucket().getName(), + this.properties.getBucket().getPassword()) + .info(); + } + + @Bean + @Primary + public Bucket couchbaseClient() { + return couchbaseCluster().openBucket(this.properties.getBucket().getName(), + this.properties.getBucket().getPassword()); + } + + /** + * Initialize an environment builder based on the specified settings. + * @param properties the couchbase properties to use + * @return the {@link DefaultCouchbaseEnvironment} builder. + */ + protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder( + CouchbaseProperties properties) { + CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints(); + CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts(); + DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment + .builder(); + if (timeouts.getConnect() != null) { + builder = builder.connectTimeout(timeouts.getConnect().toMillis()); + } + builder = builder.keyValueServiceConfig( + KeyValueServiceConfig.create(endpoints.getKeyValue())); + if (timeouts.getKeyValue() != null) { + builder = builder.kvTimeout(timeouts.getKeyValue().toMillis()); + } + if (timeouts.getQuery() != null) { + builder = builder.queryTimeout(timeouts.getQuery().toMillis()); + builder = builder.queryServiceConfig(getQueryServiceConfig(endpoints)); + builder = builder.viewServiceConfig(getViewServiceConfig(endpoints)); + } + if (timeouts.getSocketConnect() != null) { + builder = builder.socketConnectTimeout( + (int) timeouts.getSocketConnect().toMillis()); + } + if (timeouts.getView() != null) { + builder = builder.viewTimeout(timeouts.getView().toMillis()); + } + CouchbaseProperties.Ssl ssl = properties.getEnv().getSsl(); + if (ssl.getEnabled()) { + builder = builder.sslEnabled(true); + if (ssl.getKeyStore() != null) { + builder = builder.sslKeystoreFile(ssl.getKeyStore()); + } + if (ssl.getKeyStorePassword() != null) { + builder = builder.sslKeystorePassword(ssl.getKeyStorePassword()); + } + } + return builder; + } + + @SuppressWarnings("deprecation") + private QueryServiceConfig getQueryServiceConfig(Endpoints endpoints) { + return getServiceConfig(endpoints.getQueryservice(), endpoints.getQuery(), + QueryServiceConfig::create); + } + + @SuppressWarnings("deprecation") + private ViewServiceConfig getViewServiceConfig(Endpoints endpoints) { + return getServiceConfig(endpoints.getViewservice(), endpoints.getView(), + ViewServiceConfig::create); + } + + private T getServiceConfig(CouchbaseService service, Integer fallback, + BiFunction factory) { + if (service.getMinEndpoints() != 1 || service.getMaxEndpoints() != 1) { + return factory.apply(service.getMinEndpoints(), + service.getMaxEndpoints()); + } + int endpoints = (fallback != null ? fallback : 1); + return factory.apply(endpoints, endpoints); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java index bf2bf0302971..5f8d7d7d6365 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,7 +19,7 @@ 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.couchbase.CouchbaseAutoConfiguration.CouchbaseConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.couchbase.config.CouchbaseConfigurer; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java index 4f5255f7c9c1..411131ea6918 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java @@ -28,12 +28,9 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration.CouchbaseConfiguration; -import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -203,7 +200,6 @@ public void customizeEnvWithCustomCouchbaseConfiguration() { } @Configuration - @Import(CouchbaseDataAutoConfiguration.class) static class CustomCouchbaseConfiguration extends CouchbaseConfiguration { CustomCouchbaseConfiguration(CouchbaseProperties properties) { From 518f41a4aecb2b3b2059fbbd395d90f5c2b9f532 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 23 Apr 2018 10:57:14 +0200 Subject: [PATCH 017/701] Improve @ConditionalOnEnabledEndpoint to be used on any component This commit adds an `endpoint` attribute so that the condition can be used on arbitrary components, not only endpoints or extensions. Closes gh-12945 --- .../ConditionalOnEnabledEndpoint.java | 65 ++++++++++++++++++- .../condition/OnEnabledEndpointCondition.java | 23 +++++-- .../ConditionalOnEnabledEndpointTests.java | 59 +++++++++++++++++ 3 files changed, 139 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java index 52664b9d5822..3d6e8b954329 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension; import org.springframework.context.annotation.Conditional; import org.springframework.core.env.Environment; @@ -31,6 +32,60 @@ * according to the endpoints specific {@link Environment} property, falling back to * {@code management.endpoints.enabled-by-default} or failing that * {@link Endpoint#enableByDefault()}. + *

+ * When placed on a {@code @Bean} method, the endpoint defaults to the return type of the + * factory method: + * + *

+ * @Configuration
+ * public class MyConfiguration {
+ *
+ *     @ConditionalOnEnableEndpoint
+ *     @Bean
+ *     public MyEndpoint myEndpoint() {
+ *         ...
+ *     }
+ *
+ * }
+ *

+ * It is also possible to use the same mechanism for extensions: + * + *

+ * @Configuration
+ * public class MyConfiguration {
+ *
+ *     @ConditionalOnEnableEndpoint
+ *     @Bean
+ *     public MyEndpointWebExtension myEndpointWebExtension() {
+ *         ...
+ *     }
+ *
+ * }
+ *

+ * In the sample above, {@code MyEndpointWebExtension} will be created if the endpoint is + * enabled as defined by the rules above. {@code MyEndpointWebExtension} must be a regular + * extension that refers to an endpoint, something like: + * + *

+ * @EndpointWebExtension(endpoint = MyEndpoint.class)
+ * class MyEndpointWebExtension {
+ *
+ * }
+ *

+ * Alternatively, the target endpoint can be manually specified for components that should + * only be created when a given endpoint is enabled: + * + *

+ * @Configuration
+ * public class MyConfiguration {
+ *
+ *     @ConditionalOnEnableEndpoint(endpoint = MyEndpoint.class)
+ *     @Bean
+ *     public MyComponent myComponent() {
+ *         ...
+ *     }
+ *
+ * }
* * @author Stephane Nicoll * @since 2.0.0 @@ -42,4 +97,12 @@ @Conditional(OnEnabledEndpointCondition.class) public @interface ConditionalOnEnabledEndpoint { + /** + * The endpoint type that should be checked. Inferred when the return type of the + * {@code @Bean} method is either an {@link Endpoint} or an {@link EndpointExtension}. + * @return the endpoint type to check + * @since 2.1.0 + */ + Class endpoint() default Void.class; + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java index 6e2f93a6eda7..dc48b1ef5ea6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.condition; +import java.util.Map; import java.util.Optional; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -92,16 +93,24 @@ private AnnotationAttributes getEndpointAttributes(ConditionContext context, metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName()), "OnEnabledEndpointCondition may only be used on @Bean methods"); - return getEndpointAttributes(context, (MethodMetadata) metadata); + Class endpointType = getEndpointType(context, (MethodMetadata) metadata); + return getEndpointAttributes(endpointType); } - private AnnotationAttributes getEndpointAttributes(ConditionContext context, + private Class getEndpointType(ConditionContext context, MethodMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes( + ConditionalOnEnabledEndpoint.class.getName()); + if (attributes != null && attributes.containsKey("endpoint")) { + Class target = (Class) attributes.get("endpoint"); + if (target != Void.class) { + return target; + } + } // We should be safe to load at this point since we are in the REGISTER_BEAN phase try { - Class returnType = ClassUtils.forName(metadata.getReturnTypeName(), + return ClassUtils.forName(metadata.getReturnTypeName(), context.getClassLoader()); - return getEndpointAttributes(returnType); } catch (Throwable ex) { throw new IllegalStateException("Failed to extract endpoint id for " @@ -119,8 +128,8 @@ protected AnnotationAttributes getEndpointAttributes(Class type) { attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type, EndpointExtension.class, false, true); Assert.state(attributes != null, - "OnEnabledEndpointCondition may only be used on @Bean methods that " - + "return an @Endpoint or @EndpointExtension"); + "No endpoint is specified and the return type of the @Bean method is " + + "neither an @Endpoint, nor an @EndpointExtension"); return getEndpointAttributes(attributes.getClass("endpoint")); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java index def3920af7eb..efccbf99bd5b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java @@ -102,6 +102,43 @@ public void outcomeWhenNoPropertiesAndExtensionAnnotationIsNotEnabledByDefaultSh .doesNotHaveBean("fooExt")); } + @Test + public void outcomeWithReferenceWhenNoPropertiesShouldMatch() { + this.contextRunner.withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, + ComponentEnabledIfEndpointIsEnabledConfiguration.class).run((context) -> + assertThat(context).hasBean("fooComponent")); + } + + @Test + public void outcomeWithReferenceWhenEndpointEnabledPropertyIsTrueShouldMatch() { + this.contextRunner.withPropertyValues("management.endpoint.foo.enabled=true") + .withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, + ComponentEnabledIfEndpointIsEnabledConfiguration.class) + .run((context) -> + assertThat(context).hasBean("fooComponent")); + } + + @Test + public void outcomeWithReferenceWhenEndpointEnabledPropertyIsFalseShouldNotMatch() { + this.contextRunner.withPropertyValues("management.endpoint.foo.enabled=false") + .withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, + ComponentEnabledIfEndpointIsEnabledConfiguration.class) + .run((context) -> + assertThat(context).doesNotHaveBean("fooComponent")); + } + + @Test + public void outcomeWithNoReferenceShouldFail() { + this.contextRunner.withUserConfiguration( + ComponentWithNoEndpointReferenceConfiguration.class).run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure().getCause().getMessage()).contains( + "No endpoint is specified and the return type of the @Bean method " + + "is neither an @Endpoint, nor an @EndpointExtension"); + }); + } + + @Endpoint(id = "foo", enableByDefault = true) static class FooEndpointEnabledByDefaultTrue { @@ -187,4 +224,26 @@ public FooEndpointExtensionEnabledByDefaultFalse fooExt() { } + @Configuration + static class ComponentEnabledIfEndpointIsEnabledConfiguration { + + @Bean + @ConditionalOnEnabledEndpoint(endpoint = FooEndpointEnabledByDefaultTrue.class) + public String fooComponent() { + return "foo"; + } + + } + + @Configuration + static class ComponentWithNoEndpointReferenceConfiguration { + + @Bean + @ConditionalOnEnabledEndpoint + public String fooComponent() { + return "foo"; + } + + } + } From 8c67ef10791cfef3d77415fe2d6c0c377ee6af6a Mon Sep 17 00:00:00 2001 From: Tim Ysewyn Date: Sun, 25 Feb 2018 15:52:10 +0100 Subject: [PATCH 018/701] Add actuator endpoint for exposing the Spring Integration graph See gh-12331 --- .../asciidoc/endpoints/integrationgraph.adoc | 40 +++++++++++ .../src/main/asciidoc/index.adoc | 1 + ...grationGraphEndpointAutoConfiguration.java | 49 +++++++++++++ .../integration/package-info.java | 20 ++++++ .../main/resources/META-INF/spring.factories | 1 + ...rationGraphEndpointDocumentationTests.java | 69 ++++++++++++++++++ ...onGraphEndpointAutoConfigurationTests.java | 68 ++++++++++++++++++ .../integration/IntegrationGraphEndpoint.java | 58 +++++++++++++++ .../actuate/integration/package-info.java | 20 ++++++ .../IntegrationGraphEndpointTests.java | 70 ++++++++++++++++++ ...ationGraphEndpointWebIntegrationTests.java | 71 +++++++++++++++++++ .../IntegrationAutoConfiguration.java | 8 +++ .../IntegrationAutoConfigurationTests.java | 3 + .../asciidoc/production-ready-features.adoc | 8 +++ 14 files changed, 486 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc new file mode 100644 index 000000000000..fd5d8f4a8a44 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc @@ -0,0 +1,40 @@ +[[integrationgraph]] += Spring Integration graph (`integrationgraph`) + +The `integrationgraph` endpoint exposes a graph containing all Spring Integration components. + + + +[[integrationgraph-retrieving]] +== Retrieving the Spring Integration graph + +To retrieve the information about the application, make a `GET` request to +`/actuator/integrationgraph`, as shown in the following curl-based example: + +include::{snippets}integrationgraph/graph/curl-request.adoc[] + +The resulting response is similar to the following: + +include::{snippets}integrationgraph/graph/http-response.adoc[] + + + +[[integrationgraph-retrieving-response-structure]] +=== Response Structure + +The response contains all Spring Integration components used within the application, as well as the links between them. +More information about the structure can be found in the https://docs.spring.io/spring-integration/reference/html/system-management-chapter.html#integration-graph[subchapter] for the integration graph in the reference documentation of Spring Integration. + + + +[[integrationgraph-rebuilding]] +== Rebuilding the Spring Integration graph + +To rebuild the exposed graph, make a `POST` request to +`/actuator/integrationgraph`, as shown in the following curl-based example: + +include::{snippets}integrationgraph/rebuild/curl-request.adoc[] + +This will result in a `204 - No Content` response: + +include::{snippets}integrationgraph/rebuild/http-response.adoc[] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc index ac46a02c14b7..7fb1913b299f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc @@ -59,6 +59,7 @@ include::endpoints/health.adoc[leveloffset=+1] include::endpoints/heapdump.adoc[leveloffset=+1] include::endpoints/httptrace.adoc[leveloffset=+1] include::endpoints/info.adoc[leveloffset=+1] +include::endpoints/integrationgraph.adoc[leveloffset=+1] include::endpoints/liquibase.adoc[leveloffset=+1] include::endpoints/logfile.adoc[leveloffset=+1] include::endpoints/loggers.adoc[leveloffset=+1] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java new file mode 100644 index 000000000000..4bf6ea4560c8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2018 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.autoconfigure.integration; + +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for the {@link IntegrationGraphEndpoint}. + * + * @author Tim Ysewyn + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass(IntegrationGraphServer.class) +public class IntegrationGraphEndpointAutoConfiguration { + + @Bean + @ConditionalOnBean(IntegrationGraphServer.class) + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public IntegrationGraphEndpoint integrationGraphEndpoint( + IntegrationGraphServer integrationGraphServer) { + return new IntegrationGraphEndpoint(integrationGraphServer); + } + +} + diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/package-info.java new file mode 100644 index 000000000000..20e0a9b7d9d3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for actuator Spring Integration concerns. + */ +package org.springframework.boot.actuate.autoconfigure.integration; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 01ba105602e7..f5d7a66caf41 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -21,6 +21,7 @@ org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfigu org.springframework.boot.actuate.autoconfigure.influx.InfluxDbHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.integration.IntegrationGraphEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.jms.JmsHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java new file mode 100644 index 000000000000..0ccc5dd153c0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2018 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.autoconfigure.endpoint.web.documentation; + +import org.junit.Test; + +import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Tests for generating documentation describing the {@link IntegrationGraphEndpoint}. + * + * @author Tim Ysewyn + */ +public class IntegrationGraphEndpointDocumentationTests extends MockMvcEndpointDocumentationTests { + + @Test + public void graph() throws Exception { + this.mockMvc.perform(get("/actuator/integrationgraph")).andExpect(status().isOk()) + .andDo(MockMvcRestDocumentation.document("integrationgraph/graph")); + } + + @Test + public void rebuild() throws Exception { + this.mockMvc.perform(post("/actuator/integrationgraph")).andExpect(status().isNoContent()) + .andDo(MockMvcRestDocumentation.document("integrationgraph/rebuild")); + } + + @Configuration + @EnableIntegration + @Import(BaseDocumentationConfiguration.class) + static class TestConfiguration { + + @Bean + public IntegrationGraphServer integrationGraphServer() { + return new IntegrationGraphServer(); + } + + @Bean + public IntegrationGraphEndpoint endpoint() { + return new IntegrationGraphEndpoint(integrationGraphServer()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java new file mode 100644 index 000000000000..7ba5a60c1b24 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2018 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.autoconfigure.integration; + +import org.junit.Test; + +import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link IntegrationGraphEndpointAutoConfiguration}. + * + * @author Tim Ysewyn + */ +public class IntegrationGraphEndpointAutoConfigurationTests { + + private final ApplicationContextRunner contextRunnerWithoutIntegrationGraph = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(IntegrationGraphEndpointAutoConfiguration.class)); + + private final ApplicationContextRunner contextRunnerWithIntegrationGraph = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(IntegrationGraphEndpointAutoConfiguration.class)) + .withUserConfiguration(TestConfiguration.class); + + @Test + public void runShouldNotHaveEndpointBean() { + this.contextRunnerWithoutIntegrationGraph.run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); + this.contextRunnerWithoutIntegrationGraph.withPropertyValues("management.endpoint.integrationgraph.enabled:true") + .run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); + this.contextRunnerWithIntegrationGraph.run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); + } + + @Test + public void runWhenEnabledPropertyIsTrueShouldHaveEndpointBean() { + this.contextRunnerWithIntegrationGraph.withPropertyValues("management.endpoint.integrationgraph.enabled:true") + .run((context) -> assertThat(context).hasSingleBean(IntegrationGraphEndpoint.class)); + } + + @Configuration + public static class TestConfiguration { + + @Bean + public IntegrationGraphServer integrationGraphServer() { + return new IntegrationGraphServer(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java new file mode 100644 index 000000000000..7eb8d5aad978 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2018 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.integration; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; +import org.springframework.integration.support.management.graph.Graph; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; + +/** + * {@link Endpoint} to expose the Spring Integration graph. + * + * @author Tim Ysewyn + * @since 2.1.0 + */ +@Endpoint(id = "integrationgraph", enableByDefault = false) +public class IntegrationGraphEndpoint { + + private final IntegrationGraphServer integrationGraphServer; + + /** + * Creates a new {@code IntegrationGraphEndpoint} that exposes a graph containing all the + * Spring Integration components in the given {@code integrationGraphServer}. + * + * @param integrationGraphServer the integration graph server + * @see IntegrationGraphServer + */ + public IntegrationGraphEndpoint(IntegrationGraphServer integrationGraphServer) { + this.integrationGraphServer = integrationGraphServer; + } + + @ReadOperation + public Graph graph() { + return this.integrationGraphServer.getGraph(); + } + + + @WriteOperation + public void rebuild() { + this.integrationGraphServer.rebuild(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java new file mode 100644 index 000000000000..6801a40a5869 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Actuator support relating to Spring Integration. + */ +package org.springframework.boot.actuate.integration; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java new file mode 100644 index 000000000000..a50ac5e86752 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2018 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.integration; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.springframework.integration.support.management.graph.Graph; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.mock; +import static org.mockito.BDDMockito.verify; +import static org.mockito.BDDMockito.when; + +/** + * Tests for {@link IntegrationGraphEndpoint}. + * + * @author Tim Ysewyn + */ +public class IntegrationGraphEndpointTests { + + @Mock + private IntegrationGraphServer integrationGraphServer; + + @InjectMocks + private IntegrationGraphEndpoint integrationGraphEndpoint; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldReturnGraph() { + Graph mockedGraph = mock(Graph.class); + when(this.integrationGraphServer.getGraph()).thenReturn(mockedGraph); + + Graph graph = this.integrationGraphEndpoint.graph(); + + verify(this.integrationGraphServer).getGraph(); + + assertThat(graph).isEqualTo(mockedGraph); + } + + @Test + public void shouldRebuildGraph() { + this.integrationGraphEndpoint.rebuild(); + + verify(this.integrationGraphServer).rebuild(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java new file mode 100644 index 000000000000..dcfbd3934759 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2018 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.integration; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.actuate.endpoint.web.test.WebEndpointRunners; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.test.web.reactive.server.WebTestClient; + +/** + * Integration tests for {@link IntegrationGraphEndpoint} exposed by Jersey, Spring MVC, and WebFlux. + * + * @author Tim Ysewyn + */ +@RunWith(WebEndpointRunners.class) +public class IntegrationGraphEndpointWebIntegrationTests { + + private static WebTestClient client; + + @Test + public void graph() { + client.get().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange() + .expectStatus().isOk().expectBody() + .jsonPath("contentDescriptor.providerVersion").isEqualTo("5.0.3.RELEASE") + .jsonPath("contentDescriptor.providerFormatVersion").isEqualTo(1.0f) + .jsonPath("contentDescriptor.provider").isEqualTo("spring-integration"); + } + + @Test + public void rebuild() { + client.post().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange() + .expectStatus().isNoContent(); + } + + @Configuration + @EnableIntegration + public static class TestConfiguration { + + @Bean + public IntegrationGraphEndpoint endpoint(IntegrationGraphServer integrationGraphServer) { + return new IntegrationGraphEndpoint(integrationGraphServer); + } + + @Bean + public IntegrationGraphServer integrationGraphServer() { + return new IntegrationGraphServer(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 016c3fa0d6eb..4de51998d507 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -43,6 +43,7 @@ import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport; import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; import org.springframework.util.StringUtils; /** @@ -54,6 +55,7 @@ * @author Stephane Nicoll * @author Vedran Pavic * @author Madhura Bhave + * @author Tim Ysewyn * @since 1.1.0 */ @Configuration @@ -69,6 +71,12 @@ public class IntegrationAutoConfiguration { @EnableIntegration protected static class IntegrationConfiguration { + @Bean + @ConditionalOnMissingBean + public IntegrationGraphServer integrationGraphServer() { + return new IntegrationGraphServer(); + } + } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index 9bc0518bbee2..ab9ee920ea6a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -42,6 +42,7 @@ import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.support.channel.HeaderChannelRegistry; import org.springframework.integration.support.management.IntegrationManagementConfigurer; +import org.springframework.integration.support.management.graph.IntegrationGraphServer; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jmx.export.MBeanExporter; @@ -55,6 +56,7 @@ * @author Artem Bilan * @author Stephane Nicoll * @author Vedran Pavic + * @author Tim Ysewyn */ public class IntegrationAutoConfigurationTests { @@ -68,6 +70,7 @@ public class IntegrationAutoConfigurationTests { @Test public void integrationIsAvailable() { this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(IntegrationGraphServer.class); assertThat(context).hasSingleBean(TestGateway.class); assertThat(context) .hasSingleBean(IntegrationComponentScanAutoConfiguration.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index e006f6f37ddf..eb68a5932ffd 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -105,6 +105,10 @@ exchanges). |Displays arbitrary application info. |Yes +|`integrationgraph` +|Exposes the Spring Integration graph. +|No + |`loggers` |Shows and modifies the configuration of loggers in the application. |Yes @@ -252,6 +256,10 @@ endpoints: |Yes |Yes +|`integrationgraph` +|Yes +|Yes + |`jolokia` |N/A |No From 03cf4fbb10d72bb061cb7e7e651e68f6de027dee Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Apr 2018 15:40:39 +0200 Subject: [PATCH 019/701] Polish "Add actuator endpoint for exposing the Spring Integration graph" Closes gh-12331 --- .../asciidoc/endpoints/integrationgraph.adoc | 13 +++-- ...grationGraphEndpointAutoConfiguration.java | 14 +++++- ...rationGraphEndpointDocumentationTests.java | 3 +- ...onGraphEndpointAutoConfigurationTests.java | 50 ++++++++++--------- .../integration/IntegrationGraphEndpoint.java | 21 ++++---- .../actuate/integration/package-info.java | 2 +- .../IntegrationGraphEndpointTests.java | 7 +-- ...ationGraphEndpointWebIntegrationTests.java | 2 +- .../IntegrationAutoConfiguration.java | 8 --- .../IntegrationAutoConfigurationTests.java | 3 -- .../asciidoc/production-ready-features.adoc | 4 +- 11 files changed, 64 insertions(+), 63 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc index fd5d8f4a8a44..8d0e3a19cc16 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc @@ -1,7 +1,8 @@ [[integrationgraph]] = Spring Integration graph (`integrationgraph`) -The `integrationgraph` endpoint exposes a graph containing all Spring Integration components. +The `integrationgraph` endpoint exposes a graph containing all Spring Integration +components. @@ -22,16 +23,18 @@ include::{snippets}integrationgraph/graph/http-response.adoc[] [[integrationgraph-retrieving-response-structure]] === Response Structure -The response contains all Spring Integration components used within the application, as well as the links between them. -More information about the structure can be found in the https://docs.spring.io/spring-integration/reference/html/system-management-chapter.html#integration-graph[subchapter] for the integration graph in the reference documentation of Spring Integration. +The response contains all Spring Integration components used within the application, as +well as the links between them. More information about the structure can be found in the +https://docs.spring.io/spring-integration/reference/html/system-management-chapter.html#integration-graph[reference +documentation]. [[integrationgraph-rebuilding]] == Rebuilding the Spring Integration graph -To rebuild the exposed graph, make a `POST` request to -`/actuator/integrationgraph`, as shown in the following curl-based example: +To rebuild the exposed graph, make a `POST` request to `/actuator/integrationgraph`, as +shown in the following curl-based example: include::{snippets}integrationgraph/rebuild/curl-request.adoc[] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java index 4bf6ea4560c8..ddc838a6bc49 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java @@ -18,26 +18,31 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.integration.support.channel.HeaderChannelRegistry; import org.springframework.integration.support.management.graph.IntegrationGraphServer; /** * {@link EnableAutoConfiguration Auto-configuration} for the {@link IntegrationGraphEndpoint}. * * @author Tim Ysewyn + * @author Stephane Nicoll * @since 2.1.0 */ @Configuration @ConditionalOnClass(IntegrationGraphServer.class) +@ConditionalOnBean(HeaderChannelRegistry.class) +@AutoConfigureAfter(IntegrationAutoConfiguration.class) public class IntegrationGraphEndpointAutoConfiguration { @Bean - @ConditionalOnBean(IntegrationGraphServer.class) @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint public IntegrationGraphEndpoint integrationGraphEndpoint( @@ -45,5 +50,12 @@ public IntegrationGraphEndpoint integrationGraphEndpoint( return new IntegrationGraphEndpoint(integrationGraphServer); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint(endpoint = IntegrationGraphEndpoint.class) + public IntegrationGraphServer integrationGraphServer() { + return new IntegrationGraphServer(); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java index 0ccc5dd153c0..1e16977b7919 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java @@ -45,7 +45,8 @@ public void graph() throws Exception { @Test public void rebuild() throws Exception { - this.mockMvc.perform(post("/actuator/integrationgraph")).andExpect(status().isNoContent()) + this.mockMvc.perform(post("/actuator/integrationgraph")).andExpect(status() + .isNoContent()) .andDo(MockMvcRestDocumentation.document("integrationgraph/rebuild")); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java index 7ba5a60c1b24..53f5575d196c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java @@ -20,9 +20,9 @@ import org.springframework.boot.actuate.integration.IntegrationGraphEndpoint; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; +import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.integration.support.management.graph.IntegrationGraphServer; import static org.assertj.core.api.Assertions.assertThat; @@ -31,38 +31,40 @@ * Tests for {@link IntegrationGraphEndpointAutoConfiguration}. * * @author Tim Ysewyn + * @author Stephane Nicoll */ public class IntegrationGraphEndpointAutoConfigurationTests { - private final ApplicationContextRunner contextRunnerWithoutIntegrationGraph = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(IntegrationGraphEndpointAutoConfiguration.class)); - - private final ApplicationContextRunner contextRunnerWithIntegrationGraph = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(IntegrationGraphEndpointAutoConfiguration.class)) - .withUserConfiguration(TestConfiguration.class); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, + IntegrationAutoConfiguration.class, + IntegrationGraphEndpointAutoConfiguration.class)); @Test - public void runShouldNotHaveEndpointBean() { - this.contextRunnerWithoutIntegrationGraph.run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); - this.contextRunnerWithoutIntegrationGraph.withPropertyValues("management.endpoint.integrationgraph.enabled:true") - .run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); - this.contextRunnerWithIntegrationGraph.run((context) -> assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class)); + public void runShouldHaveEndpointBean() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(IntegrationGraphEndpoint.class)); } @Test - public void runWhenEnabledPropertyIsTrueShouldHaveEndpointBean() { - this.contextRunnerWithIntegrationGraph.withPropertyValues("management.endpoint.integrationgraph.enabled:true") - .run((context) -> assertThat(context).hasSingleBean(IntegrationGraphEndpoint.class)); + public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { + this.contextRunner + .withPropertyValues("management.endpoint.integrationgraph.enabled:false") + .run((context) -> { + assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class); + assertThat(context).doesNotHaveBean(IntegrationGraphServer.class); + }); } - @Configuration - public static class TestConfiguration { - - @Bean - public IntegrationGraphServer integrationGraphServer() { - return new IntegrationGraphServer(); - } - + @Test + public void runWhenSpringIntegrationIsNotEnabledShouldNotHaveEndpointBean() { + ApplicationContextRunner noSiRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + IntegrationGraphEndpointAutoConfiguration.class)); + noSiRunner.run((context) -> { + assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class); + assertThat(context).doesNotHaveBean(IntegrationGraphServer.class); + }); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java index 7eb8d5aad978..f2e034e8735f 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java @@ -28,31 +28,28 @@ * @author Tim Ysewyn * @since 2.1.0 */ -@Endpoint(id = "integrationgraph", enableByDefault = false) +@Endpoint(id = "integrationgraph") public class IntegrationGraphEndpoint { - private final IntegrationGraphServer integrationGraphServer; + private final IntegrationGraphServer graphServer; /** - * Creates a new {@code IntegrationGraphEndpoint} that exposes a graph containing all the - * Spring Integration components in the given {@code integrationGraphServer}. - * - * @param integrationGraphServer the integration graph server - * @see IntegrationGraphServer + * Create a new {@code IntegrationGraphEndpoint} that exposes a graph containing all + * the Spring Integration components in the given {@link IntegrationGraphServer}. + * @param graphServer the integration graph server */ - public IntegrationGraphEndpoint(IntegrationGraphServer integrationGraphServer) { - this.integrationGraphServer = integrationGraphServer; + public IntegrationGraphEndpoint(IntegrationGraphServer graphServer) { + this.graphServer = graphServer; } @ReadOperation public Graph graph() { - return this.integrationGraphServer.getGraph(); + return this.graphServer.getGraph(); } - @WriteOperation public void rebuild() { - this.integrationGraphServer.rebuild(); + this.graphServer.rebuild(); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java index 6801a40a5869..f42d84d3f1ed 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/package-info.java @@ -15,6 +15,6 @@ */ /** - * Actuator support relating to Spring Integration. + * Actuator support for Spring Integration. */ package org.springframework.boot.actuate.integration; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java index a50ac5e86752..d4f5808ae577 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java @@ -49,21 +49,18 @@ public void setUp() { } @Test - public void shouldReturnGraph() { + public void readOperationShouldReturnGraph() { Graph mockedGraph = mock(Graph.class); when(this.integrationGraphServer.getGraph()).thenReturn(mockedGraph); Graph graph = this.integrationGraphEndpoint.graph(); - verify(this.integrationGraphServer).getGraph(); - assertThat(graph).isEqualTo(mockedGraph); } @Test - public void shouldRebuildGraph() { + public void writeOperationShouldRebuildGraph() { this.integrationGraphEndpoint.rebuild(); - verify(this.integrationGraphServer).rebuild(); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java index dcfbd3934759..9fc6fe21034e 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java @@ -41,7 +41,7 @@ public class IntegrationGraphEndpointWebIntegrationTests { public void graph() { client.get().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange() .expectStatus().isOk().expectBody() - .jsonPath("contentDescriptor.providerVersion").isEqualTo("5.0.3.RELEASE") + .jsonPath("contentDescriptor.providerVersion").isNotEmpty() .jsonPath("contentDescriptor.providerFormatVersion").isEqualTo(1.0f) .jsonPath("contentDescriptor.provider").isEqualTo("spring-integration"); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 4de51998d507..016c3fa0d6eb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -43,7 +43,6 @@ import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport; import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.integration.support.management.IntegrationManagementConfigurer; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; import org.springframework.util.StringUtils; /** @@ -55,7 +54,6 @@ * @author Stephane Nicoll * @author Vedran Pavic * @author Madhura Bhave - * @author Tim Ysewyn * @since 1.1.0 */ @Configuration @@ -71,12 +69,6 @@ public class IntegrationAutoConfiguration { @EnableIntegration protected static class IntegrationConfiguration { - @Bean - @ConditionalOnMissingBean - public IntegrationGraphServer integrationGraphServer() { - return new IntegrationGraphServer(); - } - } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index ab9ee920ea6a..9bc0518bbee2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -42,7 +42,6 @@ import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.support.channel.HeaderChannelRegistry; import org.springframework.integration.support.management.IntegrationManagementConfigurer; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jmx.export.MBeanExporter; @@ -56,7 +55,6 @@ * @author Artem Bilan * @author Stephane Nicoll * @author Vedran Pavic - * @author Tim Ysewyn */ public class IntegrationAutoConfigurationTests { @@ -70,7 +68,6 @@ public class IntegrationAutoConfigurationTests { @Test public void integrationIsAvailable() { this.contextRunner.run((context) -> { - assertThat(context).hasSingleBean(IntegrationGraphServer.class); assertThat(context).hasSingleBean(TestGateway.class); assertThat(context) .hasSingleBean(IntegrationComponentScanAutoConfiguration.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index eb68a5932ffd..bf290b561990 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -106,8 +106,8 @@ exchanges). |Yes |`integrationgraph` -|Exposes the Spring Integration graph. -|No +|Shows the Spring Integration graph. +|Yes |`loggers` |Shows and modifies the configuration of loggers in the application. From b45c5f1a27bc2a6f7cdfe1685f50c2a725b6e2a9 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 27 Apr 2018 11:48:13 +0900 Subject: [PATCH 020/701] Polish See gh-12981 --- .../IntegrationGraphEndpointAutoConfigurationTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java index 53f5575d196c..3d34e6b77666 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java @@ -58,10 +58,10 @@ public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { @Test public void runWhenSpringIntegrationIsNotEnabledShouldNotHaveEndpointBean() { - ApplicationContextRunner noSiRunner = new ApplicationContextRunner() + ApplicationContextRunner noSpringIntegrationRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of( IntegrationGraphEndpointAutoConfiguration.class)); - noSiRunner.run((context) -> { + noSpringIntegrationRunner.run((context) -> { assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class); assertThat(context).doesNotHaveBean(IntegrationGraphServer.class); }); From 1a41ff941ae4dd40307ff62aecd94ece453ce778 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 27 Apr 2018 10:14:31 +0200 Subject: [PATCH 021/701] Polish --- .../src/main/asciidoc/appendix-application-properties.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 37e7992acda3..5e23c0e8a98e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1218,6 +1218,10 @@ content into your application. Rather, pick only the properties that you need. management.endpoint.info.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.info.enabled=true # Whether to enable the info endpoint. + # INTEGRATION GRAPH ENDPOINT ({sc-spring-boot-actuator}/integration/IntegrationGraphEndpoint.{sc-ext}[IntegrationGraphEndpoint]) + management.endpoint.integrationgraph.cache.time-to-live=0ms # Maximum time that a response can be cached. + management.endpoint.integrationgraph.enabled=true # Whether to enable the integrationgraph endpoint. + # JOLOKIA ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/jolokia/JolokiaProperties.{sc-ext}[JolokiaProperties]) management.endpoint.jolokia.config.*= # Jolokia settings. Refer to the documentation of Jolokia for more details. management.endpoint.jolokia.enabled=true # Whether to enable the jolokia endpoint. From c8843947fed9dbc26d04200b81f86cf4cb3e8cd4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 27 Apr 2018 10:14:51 +0200 Subject: [PATCH 022/701] Polish --- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 5e23c0e8a98e..e3ac6762bf9d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1220,7 +1220,7 @@ content into your application. Rather, pick only the properties that you need. # INTEGRATION GRAPH ENDPOINT ({sc-spring-boot-actuator}/integration/IntegrationGraphEndpoint.{sc-ext}[IntegrationGraphEndpoint]) management.endpoint.integrationgraph.cache.time-to-live=0ms # Maximum time that a response can be cached. - management.endpoint.integrationgraph.enabled=true # Whether to enable the integrationgraph endpoint. + management.endpoint.integrationgraph.enabled=true # Whether to enable the integrationgraph endpoint. # JOLOKIA ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/jolokia/JolokiaProperties.{sc-ext}[JolokiaProperties]) management.endpoint.jolokia.config.*= # Jolokia settings. Refer to the documentation of Jolokia for more details. From 1ef0098ab58ee12677da1bf9d42ce03331ca3226 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 27 Apr 2018 13:54:14 +0200 Subject: [PATCH 023/701] Add WebClient metrics support This commit adds support for Actuator Metrics for WebClient. This support mirrors the current behavior for `RestTemplate`, reusing the same metric name `"http.client.requests"` and tags. `WebClient` is instrumented by a `MetricsWebClientFilterFunction` which is applied by a `WebClientCustomizer`. This instrumentation happens automatically only if you create an instance of `WebClient` using an auto-configured `WebClient.Builder` bean. This infrastructure is reusing de facto the `MeterFilter` that has been added for `RestTemplate` in order to limit the "uri" tag cardinality. Closes gh-12228 --- .../RestTemplateMetricsAutoConfiguration.java | 4 +- .../WebClientMetricsAutoConfiguration.java | 72 ++++++++++ .../WebFluxMetricsAutoConfiguration.java | 4 +- .../main/resources/META-INF/spring.factories | 1 + .../metrics/test/MetricsRun.java | 2 + ...TemplateMetricsAutoConfigurationTests.java | 4 +- ...ebClientMetricsAutoConfigurationTests.java | 124 ++++++++++++++++++ .../WebFluxMetricsAutoConfigurationTests.java | 78 +++++++++++ .../DefaultWebClientExchangeTagsProvider.java | 50 +++++++ .../client/MetricsWebClientCustomizer.java | 57 ++++++++ .../MetricsWebClientFilterFunction.java | 69 ++++++++++ .../client/WebClientExchangeTags.java | 107 +++++++++++++++ .../client/WebClientExchangeTagsProvider.java | 42 ++++++ .../web/reactive/client/package-info.java | 21 +++ .../reactive/server/WebFluxTagsProvider.java | 4 +- ...ultWebClientExchangeTagsProviderTests.java | 99 ++++++++++++++ .../MetricsWebClientCustomizerTests.java | 67 ++++++++++ .../MetricsWebClientFilterFunctionTests.java | 119 +++++++++++++++++ .../client/WebClientExchangeTagsTests.java | 114 ++++++++++++++++ .../asciidoc/production-ready-features.adoc | 25 ++-- 20 files changed, 1047 insertions(+), 16 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizer.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java index 7ec4df10dea3..672261971214 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java @@ -74,7 +74,7 @@ public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer( @Bean @Order(0) - public MeterFilter metricsWebClientUriTagFilter(MetricsProperties properties) { + public MeterFilter metricsHttpClientUriTagFilter(MetricsProperties properties) { String metricName = properties.getWeb().getClient().getRequestsMetricName(); MeterFilter denyFilter = new MaximumUriTagsReachedMeterFilter(metricName); return MeterFilter.maximumAllowableTags(metricName, "uri", @@ -109,7 +109,7 @@ private void logWarning() { if (this.logger.isWarnEnabled()) { this.logger.warn( "Reached the maximum number of URI tags for '" + this.metricName - + "'. Are you using uriVariables on RestTemplate calls?"); + + "'. Are you using uriVariables on HTTP client calls?"); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java new file mode 100644 index 000000000000..dc7d24a8077a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.web.reactive; + +import io.micrometer.core.instrument.MeterRegistry; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; +import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider; +import org.springframework.boot.actuate.metrics.web.reactive.client.MetricsWebClientCustomizer; +import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for instrumentation + * of {@link org.springframework.web.reactive.function.client.WebClient}. + * + *

This is reusing the {@link io.micrometer.core.instrument.config.MeterFilter} + * defined in {@link RestTemplateMetricsAutoConfiguration} for limiting the + * cardinality of "uri" tags. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass(WebClient.class) +@AutoConfigureAfter({MetricsAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class}) +@AutoConfigureBefore(WebClientAutoConfiguration.class) +@ConditionalOnBean(MeterRegistry.class) +public class WebClientMetricsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public WebClientExchangeTagsProvider defaultWebClientExchangeTagsProvider() { + return new DefaultWebClientExchangeTagsProvider(); + } + + @Bean + public MetricsWebClientCustomizer metricsWebClientCustomizer(MeterRegistry meterRegistry, + WebClientExchangeTagsProvider tagsProvider, + MetricsProperties properties) { + return new MetricsWebClientCustomizer(meterRegistry, tagsProvider, + properties.getWeb().getClient().getRequestsMetricName()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java index 6f619440d97d..86d957096b6d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java @@ -33,8 +33,8 @@ import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring - * WebFlux MVC annotation-based programming model request mappings. + * {@link EnableAutoConfiguration Auto-configuration} for instrumentation + * of Spring WebFlux applications. * * @author Jon Schneider * @since 2.0.0 diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index f5d7a66caf41..48a19de9797f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -52,6 +52,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.Wavefron org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebClientMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat.TomcatMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index fa35d78a8aef..dfd8e7bf8a2d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -39,6 +39,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebClientMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -78,6 +79,7 @@ public final class MetricsRun { DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class, RestTemplateMetricsAutoConfiguration.class, + WebClientMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class); private MetricsRun() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java index 19a90db871e3..0bd8cb5b336b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java @@ -75,7 +75,9 @@ public void restTemplateCanBeCustomizedManually() { @Test public void afterMaxUrisReachedFurtherUrisAreDenied() { - this.contextRunner.run((context) -> { + this.contextRunner + .withPropertyValues("management.metrics.web.client.max-uri-tags=10") + .run((context) -> { MetricsProperties properties = context.getBean(MetricsProperties.class); int maxUriTags = properties.getWeb().getClient().getMaxUriTags(); MeterRegistry registry = context.getBean(MeterRegistry.class); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..b02843bb8512 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.web.reactive; + +import io.micrometer.core.instrument.MeterRegistry; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.mock.http.client.reactive.MockClientHttpResponse; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link WebClientMetricsAutoConfiguration} + * + * @author Brian Clozel + */ +public class WebClientMetricsAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = + new ApplicationContextRunner().with(MetricsRun.simple()) + .withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class)); + + private ClientHttpConnector connector; + + @Rule + public OutputCapture out = new OutputCapture(); + + @Before + public void setup() { + this.connector = mock(ClientHttpConnector.class); + given(this.connector.connect(any(), any(), any())) + .willReturn(Mono.just(new MockClientHttpResponse(HttpStatus.OK))); + } + + @Test + public void webClientCreatedWithBuilderIsInstrumented() { + this.contextRunner.run((context) -> { + WebClient.Builder builder = context.getBean(WebClient.Builder.class); + WebClient webClient = builder.clientConnector(this.connector).build(); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("http.client.requests").meter()).isNull(); + ClientResponse response = webClient.get() + .uri("http://example.org/projects/{project}", "spring-boot") + .exchange().block(); + assertThat(registry.find("http.client.requests") + .tags("uri", "/projects/{project}").meter()).isNotNull(); + }); + } + + @Test + public void shouldNotOverrideCustomTagsProvider() { + this.contextRunner.withUserConfiguration(CustomTagsProviderConfig.class) + .run((context) -> { + assertThat(context) + .getBeans(WebClientExchangeTagsProvider.class) + .hasSize(1).containsKey("customTagProvider"); + }); + } + + @Test + public void afterMaxUrisReachedFurtherUrisAreDenied() { + this.contextRunner + .withPropertyValues("management.metrics.web.client.max-uri-tags=10") + .run((context) -> { + WebClient.Builder builder = context.getBean(WebClient.Builder.class); + WebClient webClient = builder.clientConnector(this.connector).build(); + MetricsProperties properties = context.getBean(MetricsProperties.class); + int maxUriTags = properties.getWeb().getClient().getMaxUriTags(); + MeterRegistry registry = context.getBean(MeterRegistry.class); + for (int i = 0; i < maxUriTags + 10; i++) { + webClient.get() + .uri("http://example.org/projects/" + i) + .exchange().block(); + } + assertThat(registry.get("http.client.requests").meters()).hasSize(maxUriTags); + assertThat(this.out.toString()) + .contains("Reached the maximum number of URI tags " + + "for 'http.client.requests'"); + }); + } + + @Configuration + protected static class CustomTagsProviderConfig { + + @Bean + public WebClientExchangeTagsProvider customTagProvider() { + return mock(WebClientExchangeTagsProvider.class); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..842b01fba700 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.web.reactive; + +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; +import org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter; +import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsProvider; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link WebFluxMetricsAutoConfiguration} + * + * @author Brian Clozel + */ +public class WebFluxMetricsAutoConfigurationTests { + + private ReactiveWebApplicationContextRunner contextRunner = + new ReactiveWebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + MetricsAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class, + WebFluxMetricsAutoConfiguration.class)); + + @Test + public void shouldProvideWebFluxMetricsBeans() { + this.contextRunner + .run((context) -> { + assertThat(context) + .getBeans(MetricsWebFilter.class).hasSize(1); + assertThat(context) + .getBeans(DefaultWebFluxTagsProvider.class).hasSize(1); + }); + } + + @Test + public void shouldNotOverrideCustomTagsProvider() { + this.contextRunner + .withUserConfiguration(CustomWebFluxTagsProviderConfig.class) + .run((context) -> { + assertThat(context) + .getBeans(WebFluxTagsProvider.class) + .hasSize(1).containsKey("customWebFluxTagsProvider"); + }); + } + + @Configuration + protected static class CustomWebFluxTagsProviderConfig { + + @Bean + public WebFluxTagsProvider customWebFluxTagsProvider() { + return mock(WebFluxTagsProvider.class); + } + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java new file mode 100644 index 000000000000..b0ad69866ba8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import java.util.Arrays; + +import io.micrometer.core.instrument.Tag; + +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; + +/** + * Default implementation of {@link WebClientExchangeTagsProvider}. + * + * @author Brian Clozel + * @since 2.1.0 + */ +public class DefaultWebClientExchangeTagsProvider + implements WebClientExchangeTagsProvider { + + @Override + public Iterable tags(ClientRequest request, ClientResponse response, + Throwable throwable) { + Tag method = WebClientExchangeTags.method(request); + Tag uri = WebClientExchangeTags.uri(request); + Tag clientName = WebClientExchangeTags.clientName(request); + if (response != null) { + return Arrays.asList(method, uri, clientName, + WebClientExchangeTags.status(response)); + } + else { + return Arrays.asList(method, uri, clientName, + WebClientExchangeTags.status(throwable)); + } + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizer.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizer.java new file mode 100644 index 000000000000..65dc49966132 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizer.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import io.micrometer.core.instrument.MeterRegistry; + +import org.springframework.boot.web.reactive.function.client.WebClientCustomizer; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * {@link WebClientCustomizer} that configures the {@link WebClient} + * to record request metrics. + * + * @author Brian Clozel + * @since 2.1.0 + */ +public class MetricsWebClientCustomizer implements WebClientCustomizer { + + private final MetricsWebClientFilterFunction filterFunction; + + /** + * Create a new {@code MetricsWebClientFilterFunction} that will record + * metrics using the given {@code meterRegistry} with tags provided by the + * given {@code tagProvider}. + * @param meterRegistry the meter registry + * @param tagProvider the tag provider + * @param metricName the name of the recorded metric + */ + public MetricsWebClientCustomizer(MeterRegistry meterRegistry, + WebClientExchangeTagsProvider tagProvider, String metricName) { + this.filterFunction = new MetricsWebClientFilterFunction(meterRegistry, + tagProvider, metricName); + } + + @Override + public void customize(WebClient.Builder webClientBuilder) { + webClientBuilder.filters(filterFunctions -> { + if (!filterFunctions.contains(this.filterFunction)) { + filterFunctions.add(0, this.filterFunction); + } + }); + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java new file mode 100644 index 000000000000..4946f46186cc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import java.util.concurrent.TimeUnit; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Timer; +import reactor.core.publisher.Mono; + +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; + +/** + * {@link ExchangeFilterFunction} applied via a + * {@link MetricsWebClientCustomizer} to record metrics. + * + * @author Brian Clozel + * @since 2.1.0 + */ +public class MetricsWebClientFilterFunction implements ExchangeFilterFunction { + + private final MeterRegistry meterRegistry; + + private final WebClientExchangeTagsProvider tagProvider; + + private final String metricName; + + public MetricsWebClientFilterFunction(MeterRegistry meterRegistry, + WebClientExchangeTagsProvider tagProvider, String metricName) { + this.meterRegistry = meterRegistry; + this.tagProvider = tagProvider; + this.metricName = metricName; + } + + @Override + public Mono filter(ClientRequest clientRequest, + ExchangeFunction exchangeFunction) { + long startTime = System.nanoTime(); + return exchangeFunction.exchange(clientRequest) + .doOnSuccessOrError((clientResponse, throwable) -> { + Iterable tags = this.tagProvider.tags(clientRequest, + clientResponse, throwable); + Timer.builder(this.metricName) + .tags(tags) + .description("Timer of WebClient operation") + .register(this.meterRegistry) + .record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS); + }); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java new file mode 100644 index 000000000000..8987632c99bb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -0,0 +1,107 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import java.io.IOException; + +import io.micrometer.core.instrument.Tag; + +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * Factory methods for creating {@link Tag Tags} related to a request-response exchange + * performed by a {@link WebClient}. + * + * @author Brian Clozel + * @since 2.1.0 + */ +public final class WebClientExchangeTags { + + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + + private static final Tag IO_ERROR = Tag.of("status", "IO_ERROR"); + + private static final Tag CLIENT_ERROR = Tag.of("status", "CLIENT_ERROR"); + + private WebClientExchangeTags() { + } + + /** + * Creates a {@code method} {@code Tag} for the + * {@link ClientHttpRequest#getMethod() method} of the given {@code request}. + * @param request the request + * @return the method tag + */ + public static Tag method(ClientRequest request) { + return Tag.of("method", request.method().name()); + } + + /** + * Creates a {@code uri} {@code Tag} for the URI path of the given {@code request}. + * @param request the request + * @return the uri tag + */ + public static Tag uri(ClientRequest request) { + String uri = (String) request.attribute(URI_TEMPLATE_ATTRIBUTE) + .orElseGet(() -> request.url().getPath()); + return Tag.of("uri", extractPath(uri)); + } + + private static String extractPath(String url) { + String path = url.replaceFirst("^https?://[^/]+/", ""); + return path.startsWith("/") ? path : "/" + path; + } + + /** + * Creates a {@code status} {@code Tag} derived from the + * {@link ClientResponse#statusCode()} of the given {@code response}. + * @param response the response + * @return the status tag + */ + public static Tag status(ClientResponse response) { + return Tag.of("status", response.statusCode().toString()); + } + + /** + * Creates a {@code status} {@code Tag} derived from the + * exception thrown by the client. + * @param throwable the exception + * @return the status tag + */ + public static Tag status(Throwable throwable) { + return throwable instanceof IOException ? IO_ERROR : CLIENT_ERROR; + } + + /** + * Create a {@code clientName} {@code Tag} derived from + * the {@link java.net.URI#getHost host} + * of the {@link ClientRequest#url() URL} of the given {@code request}. + * @param request the request + * @return the clientName tag + */ + public static Tag clientName(ClientRequest request) { + String host = request.url().getHost(); + if (host == null) { + host = "none"; + } + return Tag.of("clientName", host); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java new file mode 100644 index 000000000000..7444c332f951 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import io.micrometer.core.instrument.Tag; + +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; + +/** + * {@link Tag Tags} provider for an exchange performed by a + * {@link org.springframework.web.reactive.function.client.WebClient}. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@FunctionalInterface +public interface WebClientExchangeTagsProvider { + + /** + * Provide tags to be associated with metrics for the client exchange. + * @param request the client request + * @param response the server response (may be {@code null}) + * @param throwable the exception (may be {@code null}) + * @return tags to associate with metrics for the request and response exchange + */ + Iterable tags(ClientRequest request, ClientResponse response, Throwable throwable); +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java new file mode 100644 index 000000000000..74592677574f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Actuator support for + * {@link org.springframework.web.reactive.function.client.WebClient} metrics. + */ +package org.springframework.boot.actuate.metrics.web.reactive.client; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsProvider.java index 942991696683..1a62d49f4813 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,7 +33,7 @@ public interface WebFluxTagsProvider { /** * Provides tags to be associated with metrics for the given {@code exchange}. * @param exchange the exchange - * @param ex the current exception (may be {@code null} + * @param ex the current exception (may be {@code null}) * @return tags to associate with metrics for the request and response exchange */ Iterable httpRequestTags(ServerWebExchange exchange, Throwable ex); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java new file mode 100644 index 000000000000..6c43347295b8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + + +import java.io.IOException; +import java.net.URI; + +import io.micrometer.core.instrument.Tag; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link DefaultWebClientExchangeTagsProvider} + * + * @author Brian Clozel + */ +public class DefaultWebClientExchangeTagsProviderTests { + + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + + private WebClientExchangeTagsProvider tagsProvider = new DefaultWebClientExchangeTagsProvider(); + + private ClientRequest request; + + private ClientResponse response; + + @Before + public void setup() { + this.request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, "http://example.org/projects/{project}") + .build(); + this.response = mock(ClientResponse.class); + given(this.response.statusCode()).willReturn(HttpStatus.OK); + } + + @Test + public void tagsShouldBePopulated() { + Iterable tags = this.tagsProvider.tags(this.request, this.response, null); + assertThat(tags).containsExactlyInAnyOrder( + Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), + Tag.of("clientName", "example.org"), Tag.of("status", "200")); + } + + @Test + public void tagsWhenNoUriTemplateShouldProvideUriPath() { + ClientRequest request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) + .build(); + Iterable tags = this.tagsProvider.tags(request, this.response, null); + assertThat(tags).containsExactlyInAnyOrder( + Tag.of("method", "GET"), Tag.of("uri", "/projects/spring-boot"), + Tag.of("clientName", "example.org"), Tag.of("status", "200")); + } + + @Test + public void tagsWhenIoExceptionShouldReturnIoErrorStatus() { + Iterable tags = this.tagsProvider.tags(this.request, + null, new IOException()); + assertThat(tags).containsExactlyInAnyOrder( + Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), + Tag.of("clientName", "example.org"), Tag.of("status", "IO_ERROR")); + } + + @Test + public void tagsWhenExceptionShouldReturnClientErrorStatus() { + Iterable tags = this.tagsProvider.tags(this.request, + null, new IllegalArgumentException()); + assertThat(tags).containsExactlyInAnyOrder( + Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), + Tag.of("clientName", "example.org"), Tag.of("status", "CLIENT_ERROR")); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java new file mode 100644 index 000000000000..0adb320c4dd9 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import io.micrometer.core.instrument.MeterRegistry; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link MetricsWebClientCustomizer} + * + * @author Brian Clozel + */ +public class MetricsWebClientCustomizerTests { + + private MetricsWebClientCustomizer customizer; + + private WebClient.Builder clientBuilder; + + @Before + public void setup() { + this.customizer = new MetricsWebClientCustomizer(mock(MeterRegistry.class), + mock(WebClientExchangeTagsProvider.class), "test"); + this.clientBuilder = WebClient.builder(); + } + + @Test + public void customizeShouldAddFilterFunction() { + this.clientBuilder.filter(mock(ExchangeFilterFunction.class)); + this.customizer.customize(this.clientBuilder); + this.clientBuilder.filters(filters -> + assertThat(filters) + .hasSize(2) + .first().isInstanceOf(MetricsWebClientFilterFunction.class)); + } + + @Test + public void customizeShouldNotAddDuplicateFilterFunction() { + this.customizer.customize(this.clientBuilder); + this.clientBuilder.filters(filters -> assertThat(filters).hasSize(1)); + this.customizer.customize(this.clientBuilder); + this.clientBuilder.filters(filters -> + assertThat(filters) + .hasSize(1) + .first().isInstanceOf(MetricsWebClientFilterFunction.class)); + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java new file mode 100644 index 000000000000..2f4d7b95136d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import java.io.IOException; +import java.net.URI; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.MockClock; +import io.micrometer.core.instrument.simple.SimpleConfig; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.Before; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + + +/** + * Tests for {@link MetricsWebClientFilterFunction} + * + * @author Brian Clozel + */ +public class MetricsWebClientFilterFunctionTests { + + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + + private MeterRegistry registry; + + private MetricsWebClientFilterFunction filterFunction; + + private ClientResponse response; + + private ExchangeFunction exchange; + + @Before + public void setup() { + this.registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock()); + this.filterFunction = new MetricsWebClientFilterFunction(this.registry, + new DefaultWebClientExchangeTagsProvider(), "http.client.requests"); + this.response = mock(ClientResponse.class); + this.exchange = r -> Mono.just(this.response); + } + + @Test + public void filterShouldRecordTimer() { + ClientRequest request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.com/projects/spring-boot")) + .build(); + given(this.response.statusCode()).willReturn(HttpStatus.OK); + this.filterFunction.filter(request, this.exchange).block(); + assertThat(this.registry.get("http.client.requests") + .tags("method", "GET", "uri", "/projects/spring-boot", "status", "200").timer() + .count()).isEqualTo(1); + } + + @Test + public void filterWhenUriTemplatePresentShouldRecordTimer() { + ClientRequest request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.com/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}") + .build(); + given(this.response.statusCode()).willReturn(HttpStatus.OK); + this.filterFunction.filter(request, this.exchange).block(); + assertThat(this.registry.get("http.client.requests") + .tags("method", "GET", "uri", "/projects/{project}", "status", "200").timer() + .count()).isEqualTo(1); + } + + @Test + public void filterWhenIoExceptionThrownShouldRecordTimer() { + ClientRequest request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.com/projects/spring-boot")) + .build(); + ExchangeFunction errorExchange = r -> Mono.error(new IOException()); + this.filterFunction.filter(request, errorExchange) + .onErrorResume(IOException.class, t -> Mono.empty()).block(); + assertThat(this.registry.get("http.client.requests") + .tags("method", "GET", "uri", "/projects/spring-boot", "status", "IO_ERROR").timer() + .count()).isEqualTo(1); + } + + @Test + public void filterWhenExceptionThrownShouldRecordTimer() { + ClientRequest request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.com/projects/spring-boot")) + .build(); + ExchangeFunction exchange = r -> Mono.error(new IllegalArgumentException()); + this.filterFunction.filter(request, exchange) + .onErrorResume(IllegalArgumentException.class, t -> Mono.empty()).block(); + assertThat(this.registry.get("http.client.requests") + .tags("method", "GET", "uri", "/projects/spring-boot", "status", "CLIENT_ERROR").timer() + .count()).isEqualTo(1); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java new file mode 100644 index 000000000000..f3dce2b13dbd --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2018 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.metrics.web.reactive.client; + +import java.io.IOException; +import java.net.URI; + +import io.micrometer.core.instrument.Tag; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link WebClientExchangeTags} + * + * @author Brian Clozel + */ +public class WebClientExchangeTagsTests { + + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + + private ClientRequest request; + + private ClientResponse response; + + @Before + public void setup() { + this.request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, "http://example.org/projects/{project}") + .build(); + this.response = mock(ClientResponse.class); + given(this.response.statusCode()).willReturn(HttpStatus.OK); + } + + @Test + public void method() { + assertThat(WebClientExchangeTags.method(this.request)) + .isEqualTo(Tag.of("method", "GET")); + } + + @Test + public void uriWhenAbsoluteTemplateIsAvailableShouldReturnTemplate() { + assertThat(WebClientExchangeTags.uri(this.request)) + .isEqualTo(Tag.of("uri", "/projects/{project}")); + } + + @Test + public void uriWhenRelativeTemplateIsAvailableShouldReturnTemplate() { + this.request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}") + .build(); + assertThat(WebClientExchangeTags.uri(this.request)) + .isEqualTo(Tag.of("uri", "/projects/{project}")); + } + + @Test + public void uriWhenTemplateIsMissingShouldReturnPath() { + this.request = ClientRequest + .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) + .build(); + assertThat(WebClientExchangeTags.uri(this.request)) + .isEqualTo(Tag.of("uri", "/projects/spring-boot")); + } + + @Test + public void clientName() { + assertThat(WebClientExchangeTags.clientName(this.request)) + .isEqualTo(Tag.of("clientName", "example.org")); + } + + @Test + public void status() { + assertThat(WebClientExchangeTags.status(this.response)) + .isEqualTo(Tag.of("status", "200")); + } + + @Test + public void statusWhenIOException() { + assertThat(WebClientExchangeTags.status(new IOException())) + .isEqualTo(Tag.of("status", "IO_ERROR")); + } + + @Test + public void statusWhenClientException() { + assertThat(WebClientExchangeTags.status(new IllegalArgumentException())) + .isEqualTo(Tag.of("status", "CLIENT_ERROR")); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index bf290b561990..5ec53b503103 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1713,16 +1713,22 @@ To customize the tags, provide a `@Bean` that implements `WebFluxTagsProvider`. -[[production-ready-metrics-rest-template]] -==== RestTemplate Metrics -The instrumentation of any `RestTemplate` created using the auto-configured -`RestTemplateBuilder` is enabled. It is also possible to apply -`MetricsRestTemplateCustomizer` manually. +[[production-ready-metrics-http-clients]] +==== HTTP Client Metrics +Spring Boot Actuator manages the instrumentation of both `RestTemplate` and `WebClient`. +For that, you have to get injected with an auto-configured builder +and use it to create instances: + +* `RestTemplateBuilder` for `RestTemplate` +* `WebClient.Builder` for `WebClient` + +It is also possible to apply manually the customizers responsible for this instrumentation, +namely `MetricsRestTemplateCustomizer` and `MetricsWebClientCustomizer`. By default, metrics are generated with the name, `http.client.requests`. The name can be customized by setting the `management.metrics.web.client.requests-metric-name` property. -By default, metrics generated by an instrumented `RestTemplate` are tagged with the +By default, metrics generated by an instrumented client are tagged with the following information: * `method`, the request's method (for example, `GET` or `POST`). @@ -1731,9 +1737,10 @@ example, `/api/person/{id}`). * `status`, the response's HTTP status code (for example, `200` or `500`). * `clientName`, the host portion of the URI. -To customize the tags, provide a `@Bean` that implements -`RestTemplateExchangeTagsProvider`. There are convenience static functions in -`RestTemplateExchangeTags`. +To customize the tags, and depending on your choice of client, you can provide +a `@Bean` that implements `RestTemplateExchangeTagsProvider` or +`WebClientExchangeTagsProvider`. There are convenience static functions in +`RestTemplateExchangeTags` and `WebClientExchangeTags`. From 22b99a90ded0070ea02c7f2e9b753fac0d6e2e0a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sat, 28 Apr 2018 10:36:41 +0200 Subject: [PATCH 024/701] Polish See gh-12906 --- .../boot/autoconfigure/session/SessionProperties.java | 11 +++++------ .../src/main/asciidoc/spring-boot-features.adoc | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java index f75e44cf3ca4..6f9cebf67acd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionProperties.java @@ -65,8 +65,7 @@ public SessionProperties(ObjectProvider serverProperties) { @PostConstruct public void checkSessionTimeout() { if (this.timeout == null && this.serverProperties != null) { - Session session = this.serverProperties.getServlet().getSession(); - this.timeout = (session == null ? null : session.getTimeout()); + this.timeout = this.serverProperties.getServlet().getSession().getTimeout(); } } @@ -87,6 +86,10 @@ public Duration getTimeout() { return this.timeout; } + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + public Servlet getServlet() { return this.servlet; } @@ -95,10 +98,6 @@ public void setServlet(Servlet servlet) { this.servlet = servlet; } - public void setTimeout(Duration timeout) { - this.timeout = timeout; - } - /** * Servlet-related properties. */ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 38a2fe917e10..860870b8655d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6015,7 +6015,8 @@ the name of the table for the JDBC store, as shown in the following example: ---- For setting the timeout of the session you can use the `spring.session.timeout` property. -If that property is not set, the auto-configuration will fallback to the value of `server.servlet.session.timeout`. +If that property is not set, the auto-configuration fallbacks to the value of +`server.servlet.session.timeout`. [[boot-features-jmx]] == Monitoring and Management over JMX From 1a57673345ac144b28f368088e37d305fb0bc869 Mon Sep 17 00:00:00 2001 From: Johannes Edmeier Date: Sun, 25 Feb 2018 19:34:42 +0100 Subject: [PATCH 025/701] Add cache actuator endpoint This commits adds an actuator endpoint which lists the caches per context and cacheManager and provides a delete operation to clear the caches. As the statistics are exposed via the metrics endpoint they are not included See gh-12216 --- .../CachesEndpointAutoConfiguration.java | 51 ++++++++ .../autoconfigure/cache/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 1 + .../CachesEndpointAutoConfigurationTests.java | 66 ++++++++++ .../boot/actuate/cache/CachesEndpoint.java | 119 ++++++++++++++++++ .../boot/actuate/cache/package-info.java | 20 +++ .../actuate/cache/CachesEndpointTests.java | 117 +++++++++++++++++ 7 files changed, 394 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java new file mode 100644 index 000000000000..f8f9f72003d4 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2018 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.autoconfigure.cache; + +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.cache.CachesEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cache.CacheManager; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link CachesEndpoint}. + * + * @author Johannes Edmeier + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass(CacheManager.class) +@AutoConfigureAfter(CacheAutoConfiguration.class) +public class CachesEndpointAutoConfiguration { + + @Bean + @ConditionalOnBean(CacheManager.class) + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public CachesEndpoint cachesEndpoint(ApplicationContext context) { + return new CachesEndpoint(context); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java new file mode 100644 index 000000000000..e1350cafb1a8 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 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. + */ + +/** + * Auto-configuration for actuator cache concerns. + */ +package org.springframework.boot.actuate.autoconfigure.cache; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 48a19de9797f..ca7b7da9193e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -3,6 +3,7 @@ org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoCon org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java new file mode 100644 index 000000000000..9c725722553b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2017 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.autoconfigure.cache; + +import org.junit.Test; + +import org.springframework.boot.actuate.cache.CachesEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CachesEndpointAutoConfiguration}. + * + * @author Johannes Edmeier + */ +public class CachesEndpointAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(CachesEndpointAutoConfiguration.class)) + .withUserConfiguration(CacheConfiguration.class); + + @Test + public void runShouldHaveEndpointBean() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class)); + } + + @Test + public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { + this.contextRunner.withPropertyValues("management.endpoint.caches.enabled:false") + .run((context) -> assertThat(context) + .doesNotHaveBean(CachesEndpoint.class)); + } + + @Configuration + static class CacheConfiguration { + + @Bean + public CacheManager cacheManager() { + return mock(CacheManager.class); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java new file mode 100644 index 000000000000..6535828b77fd --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -0,0 +1,119 @@ +/* + * Copyright 2012-2017 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.cache; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; + +import static java.util.stream.Collectors.toList; + +/** + * {@link Endpoint} to expose cache operations. + * + * @author Johannes Edmeuer + * @since 2.0.2 + */ +@Endpoint(id = "caches") +public class CachesEndpoint { + private final ApplicationContext context; + + public CachesEndpoint(ApplicationContext context) { + this.context = context; + } + + @ReadOperation + public CachesDescriptor caches() { + List caches = new ArrayList<>(); + this.context.getBeansOfType(CacheManager.class) + .forEach((name, cacheManager) -> caches.addAll( + getCacheDescriptors(name, cacheManager.getCacheNames()))); + return new CachesDescriptor(caches); + } + + private Collection getCacheDescriptors(String cacheManager, + Collection cacheNames) { + return cacheNames.stream().map(cacheName -> new CacheDescriptor(cacheName, cacheManager)).collect(toList()); + } + + @DeleteOperation + public void clearCaches(@Nullable String cacheManager, @Nullable String cacheName) { + if (cacheManager == null) { + this.context.getBeansOfType(CacheManager.class) + .forEach((name, manager) -> this.clearCaches(manager, cacheName)); + } else { + this.clearCaches(this.context.getBean(cacheManager, CacheManager.class), cacheName); + } + } + + private void clearCaches(CacheManager cacheManager, String cacheName) { + if (cacheName == null) { + cacheManager.getCacheNames().forEach(cn -> cacheManager.getCache(cn).clear()); + } else { + Cache cache = cacheManager.getCache(cacheName); + if (cache != null) { + cache.clear(); + } + } + } + + /** + * Description of an application context's caches, primarily + * intended for serialization to JSON. + */ + public static final class CachesDescriptor { + private final List caches; + + private CachesDescriptor(List caches) { + this.caches = caches; + } + + public List getCaches() { + return this.caches; + } + } + + /** + * Description of a {@link Cache}, primarily intended for serialization to + * JSON. + */ + public static final class CacheDescriptor { + private final String name; + private final String cacheManager; + + public CacheDescriptor(String name, String cacheManager) { + this.name = name; + this.cacheManager = cacheManager; + } + + public String getName() { + return name; + } + + public String getCacheManager() { + return cacheManager; + } + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/package-info.java new file mode 100644 index 000000000000..674fe09dc755 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Actuator support for caches. + */ +package org.springframework.boot.actuate.cache; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java new file mode 100644 index 000000000000..fe6a051bf724 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java @@ -0,0 +1,117 @@ +/* + * Copyright 2012-2018 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.cache; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cache.Cache; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCache; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CachesEndpoint}. + * + * @author Johannes Edmeier + */ +public class CachesEndpointTests { + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(CacheAutoConfiguration.class)); + + @Test + public void cacheReportIsReturned() { + //@formatter:off + this.contextRunner.withUserConfiguration(Config.class) + .run(context -> assertThat(context.getBean(CachesEndpoint.class).caches().getCaches()) + .hasSize(2) + .anySatisfy(cache -> { + assertThat(cache.getName()).isEqualTo("first"); + assertThat(cache.getCacheManager()).isEqualTo("cacheManager"); + }).anySatisfy(cache -> { + assertThat(cache.getName()).isEqualTo("second"); + assertThat(cache.getCacheManager()).isEqualTo("cacheManager"); + }) + ); + //@formatter:on + } + + @Test + public void cacheIsCleared() { + this.contextRunner.withUserConfiguration(Config.class).run((context) -> { + Cache firstCache = context.getBean("firstCache", Cache.class); + firstCache.put("key", "vale"); + Cache secondCache = context.getBean("secondCache", Cache.class); + secondCache.put("key", "value"); + context.getBean(CachesEndpoint.class).clearCaches(null, null); + assertThat(firstCache.get("key", String.class)).isNull(); + assertThat(secondCache.get("key", String.class)).isNull(); + }); + } + + @Test + public void namedCacheIsCleared() { + this.contextRunner.withUserConfiguration(Config.class).run((context) -> { + Cache firstCache = context.getBean("firstCache", Cache.class); + firstCache.put("key", "value"); + Cache secondCache = context.getBean("secondCache", Cache.class); + secondCache.put("key", "value"); + context.getBean(CachesEndpoint.class).clearCaches(null, "first"); + assertThat(firstCache.get("key", String.class)).isNull(); + assertThat(secondCache.get("key", String.class)).isEqualTo("value"); + }); + } + + @Test + public void unknwonCache() { + this.contextRunner.withUserConfiguration(Config.class).run((context) -> { + Cache firstCache = context.getBean("firstCache", Cache.class); + firstCache.put("key", "value"); + Cache secondCache = context.getBean("secondCache", Cache.class); + secondCache.put("key", "value"); + context.getBean(CachesEndpoint.class).clearCaches(null, "UNKNWON"); + assertThat(firstCache.get("key", String.class)).isEqualTo("value"); + assertThat(secondCache.get("key", String.class)).isEqualTo("value"); + }); + } + + @Configuration + @EnableCaching + public static class Config { + @Bean + public Cache firstCache() { + return new ConcurrentMapCache("first"); + } + + @Bean + public Cache secondCache() { + return new ConcurrentMapCache("second"); + } + + @Bean + public CachesEndpoint endpoint(ApplicationContext context) { + return new CachesEndpoint(context); + } + } + +} From fb8a5a9864de20cda052edb7cca03a35d3cb94d1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 30 Apr 2018 16:33:39 +0200 Subject: [PATCH 026/701] Polish "Add cache actuator endpoint" This commit improves the initial proposal by providing a by name read operation that returns the detail of a particular cache. It also adds more tests and complete API documentation for the feature. Closes gh-12216 --- .../src/main/asciidoc/endpoints/caches.adoc | 102 ++++++++ .../src/main/asciidoc/index.adoc | 1 + .../CachesEndpointAutoConfiguration.java | 24 +- .../autoconfigure/cache/package-info.java | 2 +- .../CachesEndpointAutoConfigurationTests.java | 18 +- .../CachesEndpointDocumentationTests.java | 123 +++++++++ .../boot/actuate/cache/CachesEndpoint.java | 195 ++++++++++---- .../cache/CachesEndpointWebExtension.java | 70 +++++ .../cache/NonUniqueCacheException.java | 50 ++++ .../endpoint/web/WebEndpointResponse.java | 7 +- .../actuate/cache/CachesEndpointTests.java | 243 ++++++++++++------ .../CachesEndpointWebIntegrationTests.java | 129 ++++++++++ .../appendix-application-properties.adoc | 4 + .../asciidoc/production-ready-features.adoc | 4 + 14 files changed, 840 insertions(+), 132 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/NonUniqueCacheException.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc new file mode 100644 index 000000000000..6342cf77c708 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc @@ -0,0 +1,102 @@ +[[caches]] += Caches (`caches`) + +The `caches` endpoint provides access to the application's caches. + + + +[[caches-all]] +== Retrieving All Caches + +To retrieve the application's caches, make a `GET` request to `/actuator/caches`, as +shown in the following curl-based example: + +include::{snippets}caches/all/curl-request.adoc[] + +The resulting response is similar to the following: + +include::{snippets}caches/all/http-response.adoc[] + + + +[[caches-all-response-structure]] +=== Response Structure + +The response contains details of the application's caches. The following table describes +the structure of the response: + +[cols="3,1,3"] +include::{snippets}caches/all/response-fields.adoc[] + + + +[[caches-named]] +== Retrieving Caches by Name + +To retrieve a cache by name, make a `GET` request to `/actuator/caches/{name}`, +as shown in the following curl-based example: + +include::{snippets}caches/named/curl-request.adoc[] + +The preceding example retrieves information about the cache named `cities`. The +resulting response is similar to the following: + +include::{snippets}caches/named/http-response.adoc[] + + + +[[caches-named-request-structure]] +=== Request Structure + +If the requested name is specific enough to identify a single cache, no extra parameter is +required. Otherwise, the `cacheManager` must be specified. The following table shows the +supported query parameters: + +[cols="2,4"] +include::{snippets}caches/named/request-parameters.adoc[] + + + +[[caches-named-response-structure]] +=== Response Structure + +The response contains details of the requested cache. The following table describes the +structure of the response: + +[cols="3,1,3"] +include::{snippets}caches/named/response-fields.adoc[] + + + +[[caches-evict-all]] +== Evict All Caches + +To clear all available caches, make a `DELETE` request to `/actuator/caches` as shown in +the following curl-based example: + +include::{snippets}caches/evict-all/curl-request.adoc[] + + + +[[caches-evict-named]] +== Evict a Cache by Name + +To evict a particular cache, make a `DELETE` request to `/actuator/caches/{name}` as shown +in the following curl-based example: + +include::{snippets}caches/evict-named/curl-request.adoc[] + +NOTE: As there are two caches named `countries`, the `cacheManager` has to be provided to +specify which `Cache` should be cleared. + + + +[[caches-evict-named-request-structure]] +=== Request Structure + +If the requested name is specific enough to identify a single cache, no extra parameter is +required. Otherwise, the `cacheManager` must be specified. The following table shows the +supported query parameters: + +[cols="2,4"] +include::{snippets}caches/evict-named/request-parameters.adoc[] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc index 7fb1913b299f..00ff14c4871f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/index.adoc @@ -51,6 +51,7 @@ https://en.wikipedia.org/wiki/ISO_8601[ISO 8601]. include::endpoints/auditevents.adoc[leveloffset=+1] include::endpoints/beans.adoc[leveloffset=+1] +include::endpoints/caches.adoc[leveloffset=+1] include::endpoints/conditions.adoc[leveloffset=+1] include::endpoints/configprops.adoc[leveloffset=+1] include::endpoints/env.adoc[leveloffset=+1] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java index f8f9f72003d4..6137925f7887 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java @@ -16,8 +16,13 @@ package org.springframework.boot.actuate.autoconfigure.cache; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.cache.CachesEndpoint; +import org.springframework.boot.actuate.cache.CachesEndpointWebExtension; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; @@ -25,7 +30,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cache.CacheManager; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -33,7 +37,8 @@ * {@link EnableAutoConfiguration Auto-configuration} for {@link CachesEndpoint}. * * @author Johannes Edmeier - * @since 2.0.0 + * @author Stephane Nicoll + * @since 2.1.0 */ @Configuration @ConditionalOnClass(CacheManager.class) @@ -41,11 +46,20 @@ public class CachesEndpointAutoConfiguration { @Bean - @ConditionalOnBean(CacheManager.class) @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint - public CachesEndpoint cachesEndpoint(ApplicationContext context) { - return new CachesEndpoint(context); + public CachesEndpoint cachesEndpoint( + ObjectProvider> cacheManagers) { + return new CachesEndpoint(cacheManagers.getIfAvailable(LinkedHashMap::new)); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + @ConditionalOnBean(CachesEndpoint.class) + public CachesEndpointWebExtension cachesEndpointWebExtension( + CachesEndpoint cachesEndpoint) { + return new CachesEndpointWebExtension(cachesEndpoint); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java index e1350cafb1a8..416af490e8a9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cache/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java index 9c725722553b..9d193739bc59 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,23 +32,31 @@ * Tests for {@link CachesEndpointAutoConfiguration}. * * @author Johannes Edmeier + * @author Stephane Nicoll */ public class CachesEndpointAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( - AutoConfigurations.of(CachesEndpointAutoConfiguration.class)) - .withUserConfiguration(CacheConfiguration.class); + AutoConfigurations.of(CachesEndpointAutoConfiguration.class)); @Test public void runShouldHaveEndpointBean() { - this.contextRunner - .run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class)); + this.contextRunner.withUserConfiguration(CacheConfiguration.class) + .run((context) -> + assertThat(context).hasSingleBean(CachesEndpoint.class)); + } + + @Test + public void runWithoutCacheManagerShouldHaveEndpointBean() { + this.contextRunner.run((context) -> + assertThat(context).hasSingleBean(CachesEndpoint.class)); } @Test public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { this.contextRunner.withPropertyValues("management.endpoint.caches.enabled:false") + .withUserConfiguration(CacheConfiguration.class) .run((context) -> assertThat(context) .doesNotHaveBean(CachesEndpoint.class)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java new file mode 100644 index 000000000000..117ce02993d3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2018 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.autoconfigure.endpoint.web.documentation; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.boot.actuate.cache.CachesEndpoint; +import org.springframework.boot.actuate.cache.CachesEndpointWebExtension; +import org.springframework.cache.CacheManager; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.restdocs.request.ParameterDescriptor; + +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Tests for generating documentation describing the {@link CachesEndpoint} + * @author Stephane Nicoll + */ +public class CachesEndpointDocumentationTests extends MockMvcEndpointDocumentationTests { + + private static final List levelFields = Arrays.asList( + fieldWithPath("name").description("Cache name."), + fieldWithPath("cacheManager").description("Cache manager name."), + fieldWithPath("target").description( + "Fully qualified name of the native cache.")); + + private static final List requestParameters = Collections.singletonList( + parameterWithName("cacheManager") + .description("Name of the cacheManager to qualify the cache. May be " + + "omitted if the cache name is unique.") + .optional()); + + @Test + public void allCaches() throws Exception { + this.mockMvc.perform(get("/actuator/caches")).andExpect(status().isOk()) + .andDo(MockMvcRestDocumentation.document("caches/all", responseFields( + fieldWithPath("cacheManagers") + .description("Cache managers keyed by id."), + fieldWithPath("cacheManagers.*") + .description("Caches in the application context keyed by " + + "name.")) + .andWithPrefix("cacheManagers.*.*.", fieldWithPath("target") + .description( + "Fully qualified name of the native cache.")))); + } + + @Test + public void namedCache() throws Exception { + this.mockMvc.perform(get("/actuator/caches/cities")).andExpect(status().isOk()) + .andDo(MockMvcRestDocumentation.document("caches/named", + requestParameters(requestParameters), + responseFields(levelFields))); + } + + @Test + public void evictAllCaches() throws Exception { + this.mockMvc.perform(delete("/actuator/caches")).andExpect(status().isNoContent()) + .andDo(MockMvcRestDocumentation.document("caches/evict-all")); + } + + @Test + public void evictNamedCache() throws Exception { + this.mockMvc.perform( + delete("/actuator/caches/countries?cacheManager=anotherCacheManager")) + .andExpect(status().isNoContent()).andDo( + MockMvcRestDocumentation.document("caches/evict-named", + requestParameters(requestParameters))); + } + + + @Configuration + @Import(BaseDocumentationConfiguration.class) + static class TestConfiguration { + + @Bean + public CachesEndpoint endpoint() { + Map cacheManagers = new HashMap<>(); + cacheManagers.put("cacheManager", new ConcurrentMapCacheManager( + "countries", "cities")); + cacheManagers.put("anotherCacheManager", new ConcurrentMapCacheManager( + "countries")); + return new CachesEndpoint(cacheManagers); + } + + @Bean + public CachesEndpointWebExtension endpointWebExtension() { + return new CachesEndpointWebExtension(endpoint()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 6535828b77fd..65b916db79ca 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,103 +17,202 @@ package org.springframework.boot.actuate.cache; import java.util.ArrayList; -import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; -import org.springframework.context.ApplicationContext; import org.springframework.lang.Nullable; -import static java.util.stream.Collectors.toList; - /** - * {@link Endpoint} to expose cache operations. + * {@link Endpoint} to expose available {@link Cache caches}. * * @author Johannes Edmeuer - * @since 2.0.2 + * @author Stephane Nicoll + * @since 2.1.0 */ @Endpoint(id = "caches") public class CachesEndpoint { - private final ApplicationContext context; - public CachesEndpoint(ApplicationContext context) { - this.context = context; + private final Map cacheManagers; + + /** + * Create a new endpoint with the {@link CacheManager} instances to use. + * @param cacheManagers the cache managers to use, indexed by name + */ + public CachesEndpoint(Map cacheManagers) { + this.cacheManagers = new LinkedHashMap<>(cacheManagers); + } + + /** + * Return a {@link CachesReport} of all available {@link Cache caches}. + * @return a caches reports + */ + @ReadOperation + public CachesReport caches() { + Map> descriptors = new LinkedHashMap<>(); + getCacheEntries((name) -> true, (cacheManager) -> true).forEach((entry) -> { + Map cmDescriptors = descriptors.computeIfAbsent( + entry.getCacheManager(), (key) -> new LinkedHashMap<>()); + String cache = entry.getName(); + cmDescriptors.put(cache, new CacheDescriptor(entry.getTarget())); + }); + return new CachesReport(descriptors); } + /** + * Return a {@link CacheDescriptor} for the specified cache. + * @param cache then name of the cache + * @param cacheManager the name of the cacheManager (can be {@code null} + * @return the descriptor of the cache or {@code null} if no such cache exists + * @throws NonUniqueCacheException if more than one cache with that name exist and no + * {@code cacheManager} was provided to identify a unique candidate + */ @ReadOperation - public CachesDescriptor caches() { - List caches = new ArrayList<>(); - this.context.getBeansOfType(CacheManager.class) - .forEach((name, cacheManager) -> caches.addAll( - getCacheDescriptors(name, cacheManager.getCacheNames()))); - return new CachesDescriptor(caches); + public CacheEntry cache(@Selector String cache, @Nullable String cacheManager) { + return extractUniqueCacheEntry(cache, getCacheEntries( + (name) -> name.equals(cache), safeEqual(cacheManager))); } - private Collection getCacheDescriptors(String cacheManager, - Collection cacheNames) { - return cacheNames.stream().map(cacheName -> new CacheDescriptor(cacheName, cacheManager)).collect(toList()); + /** + * Clear all the available {@link Cache caches}. + */ + @DeleteOperation + public void clearCaches() { + getCacheEntries((name) -> true, (cacheManagerName) -> true) + .forEach(this::clearCache); } + /** + * Clear the specific {@link Cache}. + * @param cache then name of the cache + * @param cacheManager the name of the cacheManager (can be {@code null} + * @return {@code true} if the cache was cleared or {@code false} if no such cache exists + * @throws NonUniqueCacheException if more than one cache with that name exist and no + */ @DeleteOperation - public void clearCaches(@Nullable String cacheManager, @Nullable String cacheName) { - if (cacheManager == null) { - this.context.getBeansOfType(CacheManager.class) - .forEach((name, manager) -> this.clearCaches(manager, cacheName)); - } else { - this.clearCaches(this.context.getBean(cacheManager, CacheManager.class), cacheName); + public boolean clearCache(@Selector String cache, @Nullable String cacheManager) { + CacheEntry entry = extractUniqueCacheEntry(cache, getCacheEntries( + (name) -> name.equals(cache), safeEqual(cacheManager))); + return (entry != null && clearCache(entry)); + } + + private List getCacheEntries( + Predicate cacheNamePredicate, + Predicate cacheManagerNamePredicate) { + List entries = new ArrayList<>(); + this.cacheManagers.keySet().stream().filter(cacheManagerNamePredicate) + .forEach((cacheManagerName) -> entries.addAll( + getCacheEntries(cacheManagerName, cacheNamePredicate))); + return entries; + } + + private List getCacheEntries(String cacheManagerName, + Predicate cacheNamePredicate) { + CacheManager cacheManager = this.cacheManagers.get(cacheManagerName); + List entries = new ArrayList<>(); + cacheManager.getCacheNames().stream().filter(cacheNamePredicate) + .map(cacheManager::getCache).filter(Objects::nonNull) + .forEach((cache) -> entries.add( + new CacheEntry(cache, cacheManagerName))); + return entries; + } + + private CacheEntry extractUniqueCacheEntry(String cache, + List entries) { + if (entries.size() > 1) { + throw new NonUniqueCacheException(cache, entries.stream() + .map(CacheEntry::getCacheManager).distinct() + .collect(Collectors.toList())); + } + return (entries.isEmpty() ? null : entries.get(0)); + } + + private boolean clearCache(CacheEntry entry) { + String cacheName = entry.getName(); + Cache cache = this.cacheManagers.get(entry.getCacheManager()).getCache(cacheName); + if (cache != null) { + cache.clear(); + return true; } + return false; } - private void clearCaches(CacheManager cacheManager, String cacheName) { - if (cacheName == null) { - cacheManager.getCacheNames().forEach(cn -> cacheManager.getCache(cn).clear()); - } else { - Cache cache = cacheManager.getCache(cacheName); - if (cache != null) { - cache.clear(); - } + private Predicate safeEqual(String name) { + return (name != null ? ((requested) -> requested.equals(name)) + : ((requested) -> true)); + } + + /** + * A report of available {@link Cache caches}, primarily intended for serialization + * to JSON. + */ + public static final class CachesReport { + + private final Map> cacheManagers; + + public CachesReport(Map> cacheManagers) { + this.cacheManagers = cacheManagers; + } + + public Map> getCacheManagers() { + return this.cacheManagers; } + } /** - * Description of an application context's caches, primarily - * intended for serialization to JSON. + * Basic description of a {@link Cache}, primarily intended for serialization to JSON. */ - public static final class CachesDescriptor { - private final List caches; + public static class CacheDescriptor { + + private final String target; - private CachesDescriptor(List caches) { - this.caches = caches; + public CacheDescriptor(String target) { + this.target = target; } - public List getCaches() { - return this.caches; + /** + * Return the fully qualified name of the native cache. + * @return the fully qualified name of the native cache + */ + public String getTarget() { + return this.target; } + } /** - * Description of a {@link Cache}, primarily intended for serialization to - * JSON. + * Description of a {@link Cache}, primarily intended for serialization to JSON. */ - public static final class CacheDescriptor { + public static final class CacheEntry extends CacheDescriptor { + private final String name; + private final String cacheManager; - public CacheDescriptor(String name, String cacheManager) { - this.name = name; + public CacheEntry(Cache cache, String cacheManager) { + super(cache.getNativeCache().getClass().getName()); + this.name = cache.getName(); this.cacheManager = cacheManager; } public String getName() { - return name; + return this.name; } public String getCacheManager() { - return cacheManager; + return this.cacheManager; } + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java new file mode 100644 index 000000000000..8258ead0bc96 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2018 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.cache; + +import org.springframework.boot.actuate.cache.CachesEndpoint.CacheEntry; +import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; +import org.springframework.lang.Nullable; + +/** + * {@link EndpointWebExtension} for the {@link CachesEndpoint}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@EndpointWebExtension(endpoint = CachesEndpoint.class) +public class CachesEndpointWebExtension { + + private final CachesEndpoint delegate; + + public CachesEndpointWebExtension(CachesEndpoint delegate) { + this.delegate = delegate; + } + + @ReadOperation + public WebEndpointResponse cache(@Selector String cache, + @Nullable String cacheManager) { + try { + CacheEntry entry = this.delegate.cache(cache, cacheManager); + int status = (entry != null ? WebEndpointResponse.STATUS_OK + : WebEndpointResponse.STATUS_NOT_FOUND); + return new WebEndpointResponse<>(entry, status); + } + catch (NonUniqueCacheException ex) { + return new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST); + } + } + + @DeleteOperation + public WebEndpointResponse clearCache(@Selector String cache, + @Nullable String cacheManager) { + try { + boolean cleared = this.delegate.clearCache(cache, cacheManager); + int status = (cleared ? WebEndpointResponse.STATUS_NO_CONTENT + : WebEndpointResponse.STATUS_NOT_FOUND); + return new WebEndpointResponse<>(status); + } + catch (NonUniqueCacheException ex) { + return new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/NonUniqueCacheException.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/NonUniqueCacheException.java new file mode 100644 index 000000000000..9a8adcc155b0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/NonUniqueCacheException.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2018 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.cache; + +import java.util.Collection; +import java.util.Collections; + +/** + * Exception thrown when multiple caches exist with the same name. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class NonUniqueCacheException extends RuntimeException { + + private final String cacheName; + + private final Collection cacheManagerNames; + + public NonUniqueCacheException(String cacheName, + Collection cacheManagerNames) { + super(String.format("Multiple caches named %s found, specify the 'cacheManager' " + + "to use: %s", cacheName, cacheManagerNames)); + this.cacheName = cacheName; + this.cacheManagerNames = Collections.unmodifiableCollection(cacheManagerNames); + } + + public String getCacheName() { + return this.cacheName; + } + + public Collection getCacheManagerNames() { + return this.cacheManagerNames; + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponse.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponse.java index ba66c7625105..1c4c6abd3ac8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponse.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -36,6 +36,11 @@ public final class WebEndpointResponse { */ public static final int STATUS_OK = 200; + /** + * {@code 204 No Content}. + */ + public static final int STATUS_NO_CONTENT = 204; + /** * {@code 400 Bad Request}. */ diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java index fe6a051bf724..beed1adc3239 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java @@ -16,102 +16,201 @@ package org.springframework.boot.actuate.cache; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.actuate.cache.CachesEndpoint.CacheDescriptor; +import org.springframework.boot.actuate.cache.CachesEndpoint.CacheEntry; import org.springframework.cache.Cache; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.concurrent.ConcurrentMapCache; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.cache.support.SimpleCacheManager; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; /** * Tests for {@link CachesEndpoint}. * - * @author Johannes Edmeier + * @author Stephane Nicoll */ public class CachesEndpointTests { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of(CacheAutoConfiguration.class)); + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void allCachesWithSingleCacheManager() { + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", new ConcurrentMapCacheManager("a", "b"))); + Map> allDescriptors = endpoint.caches() + .getCacheManagers(); + assertThat(allDescriptors).containsOnlyKeys("test"); + Map descriptors = allDescriptors.get("test"); + assertThat(descriptors).containsOnlyKeys("a", "b"); + assertThat(descriptors.get("a").getTarget()).isEqualTo( + ConcurrentHashMap.class.getName()); + assertThat(descriptors.get("b").getTarget()).isEqualTo( + ConcurrentHashMap.class.getName()); + } + + @Test + public void allCachesWithSeveralCacheManagers() { + Map cacheManagers = new LinkedHashMap<>(); + cacheManagers.put("test", new ConcurrentMapCacheManager("a", "b")); + cacheManagers.put("another", new ConcurrentMapCacheManager("a", "c")); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + Map> allDescriptors = endpoint.caches() + .getCacheManagers(); + assertThat(allDescriptors).containsOnlyKeys("test", "another"); + assertThat(allDescriptors.get("test")).containsOnlyKeys("a", "b"); + assertThat(allDescriptors.get("another")).containsOnlyKeys("a", "c"); + } + + @Test + public void namedCacheWithSingleCacheManager() { + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", new ConcurrentMapCacheManager("b", "a"))); + CacheEntry entry = endpoint.cache("a", null); + assertThat(entry).isNotNull(); + assertThat(entry.getCacheManager()).isEqualTo("test"); + assertThat(entry.getName()).isEqualTo("a"); + assertThat(entry.getTarget()).isEqualTo(ConcurrentHashMap.class.getName()); + } + + @Test + public void namedCacheWithSeveralCacheManagers() { + Map cacheManagers = new LinkedHashMap<>(); + cacheManagers.put("test", new ConcurrentMapCacheManager("b", "dupe-cache")); + cacheManagers.put("another", new ConcurrentMapCacheManager("c", "dupe-cache")); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + this.thrown.expect(NonUniqueCacheException.class); + this.thrown.expectMessage("dupe-cache"); + this.thrown.expectMessage("test"); + this.thrown.expectMessage("another"); + endpoint.cache("dupe-cache", null); + } + + @Test + public void namedCacheWithUnknownCache() { + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", new ConcurrentMapCacheManager("b", "a"))); + CacheEntry entry = endpoint.cache("unknown", null); + assertThat(entry).isNull(); + } + + @Test + public void namedCacheWithWrongCacheManager() { + Map cacheManagers = new LinkedHashMap<>(); + cacheManagers.put("test", new ConcurrentMapCacheManager("b", "a")); + cacheManagers.put("another", new ConcurrentMapCacheManager("c", "a")); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + CacheEntry entry = endpoint.cache("c", "test"); + assertThat(entry).isNull(); + } + + @Test + public void namedCacheWithSeveralCacheManagersWithCacheManagerFilter() { + Map cacheManagers = new LinkedHashMap<>(); + cacheManagers.put("test", new ConcurrentMapCacheManager("b", "a")); + cacheManagers.put("another", new ConcurrentMapCacheManager("c", "a")); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + CacheEntry entry = endpoint.cache("a", "test"); + assertThat(entry).isNotNull(); + assertThat(entry.getCacheManager()).isEqualTo("test"); + assertThat(entry.getName()).isEqualTo("a"); + } + + @Test + public void clearAllCaches() { + Cache a = mockCache("a"); + Cache b = mockCache("b"); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", cacheManager(a, b))); + endpoint.clearCaches(); + verify(a).clear(); + verify(b).clear(); + } + + @Test + public void clearCache() { + Cache a = mockCache("a"); + Cache b = mockCache("b"); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", cacheManager(a, b))); + assertThat(endpoint.clearCache("a", null)).isTrue(); + verify(a).clear(); + verify(b, never()).clear(); + } @Test - public void cacheReportIsReturned() { - //@formatter:off - this.contextRunner.withUserConfiguration(Config.class) - .run(context -> assertThat(context.getBean(CachesEndpoint.class).caches().getCaches()) - .hasSize(2) - .anySatisfy(cache -> { - assertThat(cache.getName()).isEqualTo("first"); - assertThat(cache.getCacheManager()).isEqualTo("cacheManager"); - }).anySatisfy(cache -> { - assertThat(cache.getName()).isEqualTo("second"); - assertThat(cache.getCacheManager()).isEqualTo("cacheManager"); - }) - ); - //@formatter:on + public void clearCacheWithSeveralCacheManagers() { + Map cacheManagers = new LinkedHashMap<>(); + cacheManagers.put("test", cacheManager(mockCache("dupe-cache"), mockCache("b"))); + cacheManagers.put("another", cacheManager(mockCache("dupe-cache"))); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + + this.thrown.expectMessage("dupe-cache"); + this.thrown.expectMessage("test"); + this.thrown.expectMessage("another"); + endpoint.clearCache("dupe-cache", null); } @Test - public void cacheIsCleared() { - this.contextRunner.withUserConfiguration(Config.class).run((context) -> { - Cache firstCache = context.getBean("firstCache", Cache.class); - firstCache.put("key", "vale"); - Cache secondCache = context.getBean("secondCache", Cache.class); - secondCache.put("key", "value"); - context.getBean(CachesEndpoint.class).clearCaches(null, null); - assertThat(firstCache.get("key", String.class)).isNull(); - assertThat(secondCache.get("key", String.class)).isNull(); - }); + public void clearCacheWithSeveralCacheManagersWithCacheManagerFilter() { + Map cacheManagers = new LinkedHashMap<>(); + Cache a = mockCache("a"); + Cache b = mockCache("b"); + cacheManagers.put("test", cacheManager(a, b)); + Cache anotherA = mockCache("a"); + cacheManagers.put("another", cacheManager(anotherA)); + CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); + assertThat(endpoint.clearCache("a", "another")).isTrue(); + verify(a, never()).clear(); + verify(anotherA).clear(); + verify(b, never()).clear(); } @Test - public void namedCacheIsCleared() { - this.contextRunner.withUserConfiguration(Config.class).run((context) -> { - Cache firstCache = context.getBean("firstCache", Cache.class); - firstCache.put("key", "value"); - Cache secondCache = context.getBean("secondCache", Cache.class); - secondCache.put("key", "value"); - context.getBean(CachesEndpoint.class).clearCaches(null, "first"); - assertThat(firstCache.get("key", String.class)).isNull(); - assertThat(secondCache.get("key", String.class)).isEqualTo("value"); - }); + public void clearCacheWithUnknownCache() { + Cache a = mockCache("a"); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", cacheManager(a))); + assertThat(endpoint.clearCache("unknown", null)).isFalse(); + verify(a, never()).clear(); } @Test - public void unknwonCache() { - this.contextRunner.withUserConfiguration(Config.class).run((context) -> { - Cache firstCache = context.getBean("firstCache", Cache.class); - firstCache.put("key", "value"); - Cache secondCache = context.getBean("secondCache", Cache.class); - secondCache.put("key", "value"); - context.getBean(CachesEndpoint.class).clearCaches(null, "UNKNWON"); - assertThat(firstCache.get("key", String.class)).isEqualTo("value"); - assertThat(secondCache.get("key", String.class)).isEqualTo("value"); - }); + public void clearCacheWithUnknownCacheManager() { + Cache a = mockCache("a"); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( + "test", cacheManager(a))); + assertThat(endpoint.clearCache("a", "unknown")).isFalse(); + verify(a, never()).clear(); + } + + private CacheManager cacheManager(Cache... caches) { + SimpleCacheManager cacheManager = new SimpleCacheManager(); + cacheManager.setCaches(Arrays.asList(caches)); + cacheManager.afterPropertiesSet(); + return cacheManager; } - @Configuration - @EnableCaching - public static class Config { - @Bean - public Cache firstCache() { - return new ConcurrentMapCache("first"); - } - - @Bean - public Cache secondCache() { - return new ConcurrentMapCache("second"); - } - - @Bean - public CachesEndpoint endpoint(ApplicationContext context) { - return new CachesEndpoint(context); - } + private Cache mockCache(String name) { + Cache cache = mock(Cache.class); + given(cache.getName()).willReturn(name); + given(cache.getNativeCache()).willReturn(new Object()); + return cache; } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java new file mode 100644 index 000000000000..e10dc27b34d3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2018 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.cache; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.actuate.endpoint.web.test.WebEndpointRunners; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.web.reactive.server.WebTestClient; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link CachesEndpoint} exposed by Jersey, Spring MVC, and WebFlux. + * + * @author Stephane Nicoll + */ +@RunWith(WebEndpointRunners.class) +public class CachesEndpointWebIntegrationTests { + + private static WebTestClient client; + + private static ConfigurableApplicationContext context; + + @Test + public void allCaches() { + client.get().uri("/actuator/caches").exchange().expectStatus().isOk().expectBody() + .jsonPath("cacheManagers.one.a.target").isEqualTo( + ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.one.b.target").isEqualTo( + ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.two.a.target").isEqualTo( + ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.two.c.target").isEqualTo( + ConcurrentHashMap.class.getName()); + } + + @Test + public void namedCache() { + client.get().uri("/actuator/caches/b").exchange().expectStatus().isOk() + .expectBody() + .jsonPath("name").isEqualTo("b") + .jsonPath("cacheManager").isEqualTo("one") + .jsonPath("target").isEqualTo(ConcurrentHashMap.class.getName()); + } + + @Test + public void namedCacheWithUnknownName() { + client.get().uri("/actuator/caches/does-not-exist").exchange().expectStatus() + .isNotFound(); + } + + @Test + public void namedCacheWithNonUniqueName() { + client.get().uri("/actuator/caches/a").exchange().expectStatus() + .isBadRequest(); + } + + @Test + public void clearNamedCache() { + Cache b = context.getBean("one", CacheManager.class).getCache("b"); + b.put("test", "value"); + client.delete().uri("/actuator/caches/b").exchange().expectStatus().isNoContent(); + assertThat(b.get("test")).isNull(); + } + + @Test + public void cleanNamedCacheWithUnknownName() { + client.delete().uri("/actuator/caches/does-not-exist").exchange().expectStatus() + .isNotFound(); + } + + @Test + public void clearNamedCacheWithNonUniqueName() { + client.get().uri("/actuator/caches/a").exchange().expectStatus() + .isBadRequest(); + } + + + @Configuration + static class TestConfiguration { + + @Bean + public CacheManager one() { + return new ConcurrentMapCacheManager("a", "b"); + } + + @Bean + public CacheManager two() { + return new ConcurrentMapCacheManager("a", "c"); + } + + @Bean + public CachesEndpoint endpoint(Map cacheManagers) { + return new CachesEndpoint(cacheManagers); + } + + @Bean + public CachesEndpointWebExtension cachesEndpointWebExtension( + CachesEndpoint endpoint) { + return new CachesEndpointWebExtension(endpoint); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 158f1113fb85..ab2b83c17d3e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1182,6 +1182,10 @@ content into your application. Rather, pick only the properties that you need. management.endpoint.beans.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.beans.enabled=true # Whether to enable the beans endpoint. + # CACHES ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/cache/CachesEndpoint.{sc-ext}[CachesEndpoint]) + management.endpoint.caches.cache.time-to-live=0ms # Maximum time that a response can be cached. + management.endpoint.caches.enabled=true # Whether to enable the caches endpoint. + # CONDITIONS REPORT ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/condition/ConditionsReportEndpoint.{sc-ext}[ConditionsReportEndpoint]) management.endpoint.conditions.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.conditions.enabled=true # Whether to enable the conditions endpoint. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 5ec53b503103..2e1bfa61d3c2 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -75,6 +75,10 @@ The following technology-agnostic endpoints are available: |Displays a complete list of all the Spring beans in your application. |Yes +|`caches` +|Exposes available caches. +|Yes + |`conditions` |Shows the conditions that were evaluated on configuration and auto-configuration classes and the reasons why they did or did not match. From 8cf34238d362326387ecc532f31544dc316280be Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 1 May 2018 15:33:52 -0400 Subject: [PATCH 027/701] Start building against Spring Kafka 2.2.0 snapshots Closes gh-13007 --- .../ConcurrentKafkaListenerContainerFactoryConfigurer.java | 2 +- .../boot/autoconfigure/kafka/KafkaProperties.java | 2 +- .../boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java index d4b460abe5a5..5a12fad006e2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java @@ -23,7 +23,7 @@ import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.listener.config.ContainerProperties; +import org.springframework.kafka.listener.ContainerProperties; import org.springframework.kafka.support.converter.RecordMessageConverter; /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index 4dce8a9526a6..a3bbf4115e92 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -35,7 +35,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.convert.DurationUnit; import org.springframework.core.io.Resource; -import org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode; +import org.springframework.kafka.listener.ContainerProperties.AckMode; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.util.CollectionUtils; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index e716e8ab7033..7d841a650dea 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -43,7 +43,7 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaAdmin; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode; +import org.springframework.kafka.listener.ContainerProperties.AckMode; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.kafka.support.converter.MessagingMessageConverter; import org.springframework.kafka.support.converter.RecordMessageConverter; diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index a809677951db..bfdf521f399d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -113,7 +113,7 @@ 4.12 5.1.0 1.1.0 - 1.0.1 + 1.1.0 1.2.41 5.0.3.RELEASE 3.5.5 @@ -157,7 +157,7 @@ Kay-BUILD-SNAPSHOT 0.24.0.RELEASE 5.0.5.BUILD-SNAPSHOT - 2.1.6.BUILD-SNAPSHOT + 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE 1.2.0.RELEASE 2.0.1.RELEASE From 7b120c1c978eae7e3e333443881035ae7e838f95 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 4 May 2018 16:36:21 -0700 Subject: [PATCH 028/701] Formatting --- .../condition/OnEnabledEndpointCondition.java | 7 ++- ...grationGraphEndpointAutoConfiguration.java | 4 +- .../WebClientMetricsAutoConfiguration.java | 19 ++++---- .../WebFluxMetricsAutoConfiguration.java | 4 +- .../CachesEndpointAutoConfigurationTests.java | 9 ++-- .../ConditionalOnEnabledEndpointTests.java | 31 ++++++------- .../CachesEndpointDocumentationTests.java | 38 ++++++++-------- ...rationGraphEndpointDocumentationTests.java | 7 +-- ...onGraphEndpointAutoConfigurationTests.java | 4 +- ...ibernateMetricsAutoConfigurationTests.java | 7 +-- ...TemplateMetricsAutoConfigurationTests.java | 40 +++++++++-------- ...ebClientMetricsAutoConfigurationTests.java | 1 + .../WebFluxMetricsAutoConfigurationTests.java | 2 + .../boot/actuate/cache/CachesEndpoint.java | 34 +++++++------- .../DefaultWebClientExchangeTagsProvider.java | 1 + .../MetricsWebClientFilterFunction.java | 7 ++- .../client/WebClientExchangeTags.java | 17 +++---- .../client/WebClientExchangeTagsProvider.java | 4 +- .../web/reactive/client/package-info.java | 4 +- .../actuate/cache/CachesEndpointTests.java | 36 +++++++-------- .../CachesEndpointWebIntegrationTests.java | 33 +++++++------- ...ationGraphEndpointWebIntegrationTests.java | 14 +++--- ...ultWebClientExchangeTagsProviderTests.java | 45 ++++++++++--------- .../MetricsWebClientCustomizerTests.java | 1 + .../client/WebClientExchangeTagsTests.java | 20 +++++---- .../couchbase/CouchbaseConfiguration.java | 16 +++---- .../DispatcherServletAutoConfiguration.java | 2 +- .../boot/maven/AbstractRunMojo.java | 1 + .../springframework/boot/maven/RunMojo.java | 3 +- .../springframework/boot/maven/StartMojo.java | 3 +- .../boot/maven/EnvVariablesTests.java | 4 +- 31 files changed, 212 insertions(+), 206 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java index dc48b1ef5ea6..ef25e29311e4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnEnabledEndpointCondition.java @@ -97,10 +97,9 @@ private AnnotationAttributes getEndpointAttributes(ConditionContext context, return getEndpointAttributes(endpointType); } - private Class getEndpointType(ConditionContext context, - MethodMetadata metadata) { - Map attributes = metadata.getAnnotationAttributes( - ConditionalOnEnabledEndpoint.class.getName()); + private Class getEndpointType(ConditionContext context, MethodMetadata metadata) { + Map attributes = metadata + .getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName()); if (attributes != null && attributes.containsKey("endpoint")) { Class target = (Class) attributes.get("endpoint"); if (target != Void.class) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java index ddc838a6bc49..e6b29a8a2e92 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java @@ -30,7 +30,8 @@ import org.springframework.integration.support.management.graph.IntegrationGraphServer; /** - * {@link EnableAutoConfiguration Auto-configuration} for the {@link IntegrationGraphEndpoint}. + * {@link EnableAutoConfiguration Auto-configuration} for the + * {@link IntegrationGraphEndpoint}. * * @author Tim Ysewyn * @author Stephane Nicoll @@ -58,4 +59,3 @@ public IntegrationGraphServer integrationGraphServer() { } } - diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java index dc7d24a8077a..a0d0de491c65 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java @@ -37,20 +37,21 @@ import org.springframework.web.reactive.function.client.WebClient; /** - * {@link EnableAutoConfiguration Auto-configuration} for instrumentation - * of {@link org.springframework.web.reactive.function.client.WebClient}. + * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of + * {@link org.springframework.web.reactive.function.client.WebClient}. * - *

This is reusing the {@link io.micrometer.core.instrument.config.MeterFilter} - * defined in {@link RestTemplateMetricsAutoConfiguration} for limiting the - * cardinality of "uri" tags. + *

+ * This is reusing the {@link io.micrometer.core.instrument.config.MeterFilter} defined in + * {@link RestTemplateMetricsAutoConfiguration} for limiting the cardinality of "uri" + * tags. * * @author Brian Clozel * @since 2.1.0 */ @Configuration @ConditionalOnClass(WebClient.class) -@AutoConfigureAfter({MetricsAutoConfiguration.class, - SimpleMetricsExportAutoConfiguration.class}) +@AutoConfigureAfter({ MetricsAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) @AutoConfigureBefore(WebClientAutoConfiguration.class) @ConditionalOnBean(MeterRegistry.class) public class WebClientMetricsAutoConfiguration { @@ -62,8 +63,8 @@ public WebClientExchangeTagsProvider defaultWebClientExchangeTagsProvider() { } @Bean - public MetricsWebClientCustomizer metricsWebClientCustomizer(MeterRegistry meterRegistry, - WebClientExchangeTagsProvider tagsProvider, + public MetricsWebClientCustomizer metricsWebClientCustomizer( + MeterRegistry meterRegistry, WebClientExchangeTagsProvider tagsProvider, MetricsProperties properties) { return new MetricsWebClientCustomizer(meterRegistry, tagsProvider, properties.getWeb().getClient().getRequestsMetricName()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java index 86d957096b6d..9828805672bb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfiguration.java @@ -33,8 +33,8 @@ import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-configuration} for instrumentation - * of Spring WebFlux applications. + * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring + * WebFlux applications. * * @author Jon Schneider * @since 2.0.0 diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java index 9d193739bc59..033783a751a2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfigurationTests.java @@ -42,15 +42,14 @@ public class CachesEndpointAutoConfigurationTests { @Test public void runShouldHaveEndpointBean() { - this.contextRunner.withUserConfiguration(CacheConfiguration.class) - .run((context) -> - assertThat(context).hasSingleBean(CachesEndpoint.class)); + this.contextRunner.withUserConfiguration(CacheConfiguration.class).run( + (context) -> assertThat(context).hasSingleBean(CachesEndpoint.class)); } @Test public void runWithoutCacheManagerShouldHaveEndpointBean() { - this.contextRunner.run((context) -> - assertThat(context).hasSingleBean(CachesEndpoint.class)); + this.contextRunner.run( + (context) -> assertThat(context).hasSingleBean(CachesEndpoint.class)); } @Test diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java index efccbf99bd5b..a83516afc2e9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpointTests.java @@ -104,9 +104,10 @@ public void outcomeWhenNoPropertiesAndExtensionAnnotationIsNotEnabledByDefaultSh @Test public void outcomeWithReferenceWhenNoPropertiesShouldMatch() { - this.contextRunner.withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, - ComponentEnabledIfEndpointIsEnabledConfiguration.class).run((context) -> - assertThat(context).hasBean("fooComponent")); + this.contextRunner + .withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, + ComponentEnabledIfEndpointIsEnabledConfiguration.class) + .run((context) -> assertThat(context).hasBean("fooComponent")); } @Test @@ -114,8 +115,7 @@ public void outcomeWithReferenceWhenEndpointEnabledPropertyIsTrueShouldMatch() { this.contextRunner.withPropertyValues("management.endpoint.foo.enabled=true") .withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, ComponentEnabledIfEndpointIsEnabledConfiguration.class) - .run((context) -> - assertThat(context).hasBean("fooComponent")); + .run((context) -> assertThat(context).hasBean("fooComponent")); } @Test @@ -123,22 +123,23 @@ public void outcomeWithReferenceWhenEndpointEnabledPropertyIsFalseShouldNotMatch this.contextRunner.withPropertyValues("management.endpoint.foo.enabled=false") .withUserConfiguration(FooEndpointEnabledByDefaultTrue.class, ComponentEnabledIfEndpointIsEnabledConfiguration.class) - .run((context) -> - assertThat(context).doesNotHaveBean("fooComponent")); + .run((context) -> assertThat(context).doesNotHaveBean("fooComponent")); } @Test public void outcomeWithNoReferenceShouldFail() { - this.contextRunner.withUserConfiguration( - ComponentWithNoEndpointReferenceConfiguration.class).run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure().getCause().getMessage()).contains( - "No endpoint is specified and the return type of the @Bean method " - + "is neither an @Endpoint, nor an @EndpointExtension"); - }); + this.contextRunner + .withUserConfiguration( + ComponentWithNoEndpointReferenceConfiguration.class) + .run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure().getCause().getMessage()) + .contains( + "No endpoint is specified and the return type of the @Bean method " + + "is neither an @Endpoint, nor an @EndpointExtension"); + }); } - @Endpoint(id = "foo", enableByDefault = true) static class FooEndpointEnabledByDefaultTrue { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java index 117ce02993d3..8bff0fa75563 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java @@ -45,6 +45,7 @@ /** * Tests for generating documentation describing the {@link CachesEndpoint} + * * @author Stephane Nicoll */ public class CachesEndpointDocumentationTests extends MockMvcEndpointDocumentationTests { @@ -52,11 +53,11 @@ public class CachesEndpointDocumentationTests extends MockMvcEndpointDocumentati private static final List levelFields = Arrays.asList( fieldWithPath("name").description("Cache name."), fieldWithPath("cacheManager").description("Cache manager name."), - fieldWithPath("target").description( - "Fully qualified name of the native cache.")); + fieldWithPath("target") + .description("Fully qualified name of the native cache.")); - private static final List requestParameters = Collections.singletonList( - parameterWithName("cacheManager") + private static final List requestParameters = Collections + .singletonList(parameterWithName("cacheManager") .description("Name of the cacheManager to qualify the cache. May be " + "omitted if the cache name is unique.") .optional()); @@ -67,12 +68,11 @@ public void allCaches() throws Exception { .andDo(MockMvcRestDocumentation.document("caches/all", responseFields( fieldWithPath("cacheManagers") .description("Cache managers keyed by id."), - fieldWithPath("cacheManagers.*") - .description("Caches in the application context keyed by " - + "name.")) - .andWithPrefix("cacheManagers.*.*.", fieldWithPath("target") - .description( - "Fully qualified name of the native cache.")))); + fieldWithPath("cacheManagers.*").description( + "Caches in the application context keyed by " + "name.")) + .andWithPrefix("cacheManagers.*.*.", + fieldWithPath("target").description( + "Fully qualified name of the native cache.")))); } @Test @@ -91,14 +91,14 @@ public void evictAllCaches() throws Exception { @Test public void evictNamedCache() throws Exception { - this.mockMvc.perform( - delete("/actuator/caches/countries?cacheManager=anotherCacheManager")) - .andExpect(status().isNoContent()).andDo( - MockMvcRestDocumentation.document("caches/evict-named", + this.mockMvc + .perform(delete( + "/actuator/caches/countries?cacheManager=anotherCacheManager")) + .andExpect(status().isNoContent()) + .andDo(MockMvcRestDocumentation.document("caches/evict-named", requestParameters(requestParameters))); } - @Configuration @Import(BaseDocumentationConfiguration.class) static class TestConfiguration { @@ -106,10 +106,10 @@ static class TestConfiguration { @Bean public CachesEndpoint endpoint() { Map cacheManagers = new HashMap<>(); - cacheManagers.put("cacheManager", new ConcurrentMapCacheManager( - "countries", "cities")); - cacheManagers.put("anotherCacheManager", new ConcurrentMapCacheManager( - "countries")); + cacheManagers.put("cacheManager", + new ConcurrentMapCacheManager("countries", "cities")); + cacheManagers.put("anotherCacheManager", + new ConcurrentMapCacheManager("countries")); return new CachesEndpoint(cacheManagers); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java index 1e16977b7919..d8587e1c9ed6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java @@ -35,7 +35,8 @@ * * @author Tim Ysewyn */ -public class IntegrationGraphEndpointDocumentationTests extends MockMvcEndpointDocumentationTests { +public class IntegrationGraphEndpointDocumentationTests + extends MockMvcEndpointDocumentationTests { @Test public void graph() throws Exception { @@ -45,8 +46,8 @@ public void graph() throws Exception { @Test public void rebuild() throws Exception { - this.mockMvc.perform(post("/actuator/integrationgraph")).andExpect(status() - .isNoContent()) + this.mockMvc.perform(post("/actuator/integrationgraph")) + .andExpect(status().isNoContent()) .andDo(MockMvcRestDocumentation.document("integrationgraph/rebuild")); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java index 3d34e6b77666..1263f04e4537 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java @@ -59,8 +59,8 @@ public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() { @Test public void runWhenSpringIntegrationIsNotEnabledShouldNotHaveEndpointBean() { ApplicationContextRunner noSpringIntegrationRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - IntegrationGraphEndpointAutoConfiguration.class)); + .withConfiguration(AutoConfigurations + .of(IntegrationGraphEndpointAutoConfiguration.class)); noSpringIntegrationRunner.run((context) -> { assertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class); assertThat(context).doesNotHaveBean(IntegrationGraphServer.class); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java index beff4b296468..fe123f35aae7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -90,8 +90,9 @@ public void autoConfiguredEntityManagerFactoryWithoutStatsIsNotInstrumented() { @Test public void entityManagerFactoryInstrumentationCanBeDisabled() { - this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false", - "spring.jpa.properties.hibernate.generate_statistics:true") + this.contextRunner + .withPropertyValues("management.metrics.enable.hibernate=false", + "spring.jpa.properties.hibernate.generate_statistics:true") .run((context) -> { context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class); @@ -130,7 +131,7 @@ public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFa // ensure EntityManagerFactory is not an Hibernate SessionFactory assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class)) - .isInstanceOf(PersistenceException.class); + .isInstanceOf(PersistenceException.class); MeterRegistry registry = context.getBean(MeterRegistry.class); assertThat(registry.find("hibernate.statements").meter()).isNull(); }); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java index 0bd8cb5b336b..62abdf3b6edb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java @@ -78,25 +78,27 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { this.contextRunner .withPropertyValues("management.metrics.web.client.max-uri-tags=10") .run((context) -> { - MetricsProperties properties = context.getBean(MetricsProperties.class); - int maxUriTags = properties.getWeb().getClient().getMaxUriTags(); - MeterRegistry registry = context.getBean(MeterRegistry.class); - RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class) - .build(); - MockRestServiceServer server = MockRestServiceServer - .createServer(restTemplate); - for (int i = 0; i < maxUriTags + 10; i++) { - server.expect(requestTo("/test/" + i)) - .andRespond(withStatus(HttpStatus.OK)); - } - for (int i = 0; i < maxUriTags + 10; i++) { - restTemplate.getForObject("/test/" + i, String.class); - } - assertThat(registry.get("http.client.requests").meters()).hasSize(maxUriTags); - assertThat(this.out.toString()) - .contains("Reached the maximum number of URI tags " - + "for 'http.client.requests'"); - }); + MetricsProperties properties = context + .getBean(MetricsProperties.class); + int maxUriTags = properties.getWeb().getClient().getMaxUriTags(); + MeterRegistry registry = context.getBean(MeterRegistry.class); + RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class) + .build(); + MockRestServiceServer server = MockRestServiceServer + .createServer(restTemplate); + for (int i = 0; i < maxUriTags + 10; i++) { + server.expect(requestTo("/test/" + i)) + .andRespond(withStatus(HttpStatus.OK)); + } + for (int i = 0; i < maxUriTags + 10; i++) { + restTemplate.getForObject("/test/" + i, String.class); + } + assertThat(registry.get("http.client.requests").meters()) + .hasSize(maxUriTags); + assertThat(this.out.toString()) + .contains("Reached the maximum number of URI tags " + + "for 'http.client.requests'"); + }); } private void validateRestTemplate(RestTemplate restTemplate, MeterRegistry registry) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java index 0f2b726c6dfa..16b036329eac 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java @@ -116,6 +116,7 @@ protected static class CustomTagsProviderConfig { public WebClientExchangeTagsProvider customTagProvider() { return mock(WebClientExchangeTagsProvider.class); } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java index 5b025d23b1a4..b1760fa64d85 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java @@ -65,5 +65,7 @@ protected static class CustomWebFluxTagsProviderConfig { public WebFluxTagsProvider customWebFluxTagsProvider() { return mock(WebFluxTagsProvider.class); } + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 65b916db79ca..7f51bd42292e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -78,8 +78,8 @@ public CachesReport caches() { */ @ReadOperation public CacheEntry cache(@Selector String cache, @Nullable String cacheManager) { - return extractUniqueCacheEntry(cache, getCacheEntries( - (name) -> name.equals(cache), safeEqual(cacheManager))); + return extractUniqueCacheEntry(cache, + getCacheEntries((name) -> name.equals(cache), safeEqual(cacheManager))); } /** @@ -95,23 +95,23 @@ public void clearCaches() { * Clear the specific {@link Cache}. * @param cache then name of the cache * @param cacheManager the name of the cacheManager (can be {@code null} - * @return {@code true} if the cache was cleared or {@code false} if no such cache exists + * @return {@code true} if the cache was cleared or {@code false} if no such cache + * exists * @throws NonUniqueCacheException if more than one cache with that name exist and no */ @DeleteOperation public boolean clearCache(@Selector String cache, @Nullable String cacheManager) { - CacheEntry entry = extractUniqueCacheEntry(cache, getCacheEntries( - (name) -> name.equals(cache), safeEqual(cacheManager))); + CacheEntry entry = extractUniqueCacheEntry(cache, + getCacheEntries((name) -> name.equals(cache), safeEqual(cacheManager))); return (entry != null && clearCache(entry)); } - private List getCacheEntries( - Predicate cacheNamePredicate, + private List getCacheEntries(Predicate cacheNamePredicate, Predicate cacheManagerNamePredicate) { List entries = new ArrayList<>(); this.cacheManagers.keySet().stream().filter(cacheManagerNamePredicate) - .forEach((cacheManagerName) -> entries.addAll( - getCacheEntries(cacheManagerName, cacheNamePredicate))); + .forEach((cacheManagerName) -> entries + .addAll(getCacheEntries(cacheManagerName, cacheNamePredicate))); return entries; } @@ -121,17 +121,15 @@ private List getCacheEntries(String cacheManagerName, List entries = new ArrayList<>(); cacheManager.getCacheNames().stream().filter(cacheNamePredicate) .map(cacheManager::getCache).filter(Objects::nonNull) - .forEach((cache) -> entries.add( - new CacheEntry(cache, cacheManagerName))); + .forEach((cache) -> entries.add(new CacheEntry(cache, cacheManagerName))); return entries; } - private CacheEntry extractUniqueCacheEntry(String cache, - List entries) { + private CacheEntry extractUniqueCacheEntry(String cache, List entries) { if (entries.size() > 1) { - throw new NonUniqueCacheException(cache, entries.stream() - .map(CacheEntry::getCacheManager).distinct() - .collect(Collectors.toList())); + throw new NonUniqueCacheException(cache, + entries.stream().map(CacheEntry::getCacheManager).distinct() + .collect(Collectors.toList())); } return (entries.isEmpty() ? null : entries.get(0)); } @@ -152,8 +150,8 @@ private Predicate safeEqual(String name) { } /** - * A report of available {@link Cache caches}, primarily intended for serialization - * to JSON. + * A report of available {@link Cache caches}, primarily intended for serialization to + * JSON. */ public static final class CachesReport { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java index b0ad69866ba8..d747703b33d8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProvider.java @@ -47,4 +47,5 @@ public Iterable tags(ClientRequest request, ClientResponse response, WebClientExchangeTags.status(throwable)); } } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java index 4946f46186cc..89468ff2467f 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java @@ -29,8 +29,8 @@ import org.springframework.web.reactive.function.client.ExchangeFunction; /** - * {@link ExchangeFilterFunction} applied via a - * {@link MetricsWebClientCustomizer} to record metrics. + * {@link ExchangeFilterFunction} applied via a {@link MetricsWebClientCustomizer} to + * record metrics. * * @author Brian Clozel * @since 2.1.0 @@ -58,8 +58,7 @@ public Mono filter(ClientRequest clientRequest, .doOnSuccessOrError((clientResponse, throwable) -> { Iterable tags = this.tagProvider.tags(clientRequest, clientResponse, throwable); - Timer.builder(this.metricName) - .tags(tags) + Timer.builder(this.metricName).tags(tags) .description("Timer of WebClient operation") .register(this.meterRegistry) .record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index 8987632c99bb..ca852e3d6bf4 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -34,7 +34,8 @@ */ public final class WebClientExchangeTags { - private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + + ".uriTemplate"; private static final Tag IO_ERROR = Tag.of("status", "IO_ERROR"); @@ -44,8 +45,8 @@ private WebClientExchangeTags() { } /** - * Creates a {@code method} {@code Tag} for the - * {@link ClientHttpRequest#getMethod() method} of the given {@code request}. + * Creates a {@code method} {@code Tag} for the {@link ClientHttpRequest#getMethod() + * method} of the given {@code request}. * @param request the request * @return the method tag */ @@ -80,8 +81,8 @@ public static Tag status(ClientResponse response) { } /** - * Creates a {@code status} {@code Tag} derived from the - * exception thrown by the client. + * Creates a {@code status} {@code Tag} derived from the exception thrown by the + * client. * @param throwable the exception * @return the status tag */ @@ -90,9 +91,9 @@ public static Tag status(Throwable throwable) { } /** - * Create a {@code clientName} {@code Tag} derived from - * the {@link java.net.URI#getHost host} - * of the {@link ClientRequest#url() URL} of the given {@code request}. + * Create a {@code clientName} {@code Tag} derived from the + * {@link java.net.URI#getHost host} of the {@link ClientRequest#url() URL} of the + * given {@code request}. * @param request the request * @return the clientName tag */ diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java index 7444c332f951..ce1a443839b3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsProvider.java @@ -38,5 +38,7 @@ public interface WebClientExchangeTagsProvider { * @param throwable the exception (may be {@code null}) * @return tags to associate with metrics for the request and response exchange */ - Iterable tags(ClientRequest request, ClientResponse response, Throwable throwable); + Iterable tags(ClientRequest request, ClientResponse response, + Throwable throwable); + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java index 74592677574f..7722c644a161 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/package-info.java @@ -15,7 +15,7 @@ */ /** - * Actuator support for - * {@link org.springframework.web.reactive.function.client.WebClient} metrics. + * Actuator support for {@link org.springframework.web.reactive.function.client.WebClient} + * metrics. */ package org.springframework.boot.actuate.metrics.web.reactive.client; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java index beed1adc3239..7a269126682c 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java @@ -51,17 +51,17 @@ public class CachesEndpointTests { @Test public void allCachesWithSingleCacheManager() { - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", new ConcurrentMapCacheManager("a", "b"))); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap("test", + new ConcurrentMapCacheManager("a", "b"))); Map> allDescriptors = endpoint.caches() .getCacheManagers(); assertThat(allDescriptors).containsOnlyKeys("test"); Map descriptors = allDescriptors.get("test"); assertThat(descriptors).containsOnlyKeys("a", "b"); - assertThat(descriptors.get("a").getTarget()).isEqualTo( - ConcurrentHashMap.class.getName()); - assertThat(descriptors.get("b").getTarget()).isEqualTo( - ConcurrentHashMap.class.getName()); + assertThat(descriptors.get("a").getTarget()) + .isEqualTo(ConcurrentHashMap.class.getName()); + assertThat(descriptors.get("b").getTarget()) + .isEqualTo(ConcurrentHashMap.class.getName()); } @Test @@ -79,8 +79,8 @@ public void allCachesWithSeveralCacheManagers() { @Test public void namedCacheWithSingleCacheManager() { - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", new ConcurrentMapCacheManager("b", "a"))); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap("test", + new ConcurrentMapCacheManager("b", "a"))); CacheEntry entry = endpoint.cache("a", null); assertThat(entry).isNotNull(); assertThat(entry.getCacheManager()).isEqualTo("test"); @@ -103,8 +103,8 @@ public void namedCacheWithSeveralCacheManagers() { @Test public void namedCacheWithUnknownCache() { - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", new ConcurrentMapCacheManager("b", "a"))); + CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap("test", + new ConcurrentMapCacheManager("b", "a"))); CacheEntry entry = endpoint.cache("unknown", null); assertThat(entry).isNull(); } @@ -135,8 +135,8 @@ public void namedCacheWithSeveralCacheManagersWithCacheManagerFilter() { public void clearAllCaches() { Cache a = mockCache("a"); Cache b = mockCache("b"); - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", cacheManager(a, b))); + CachesEndpoint endpoint = new CachesEndpoint( + Collections.singletonMap("test", cacheManager(a, b))); endpoint.clearCaches(); verify(a).clear(); verify(b).clear(); @@ -146,8 +146,8 @@ public void clearAllCaches() { public void clearCache() { Cache a = mockCache("a"); Cache b = mockCache("b"); - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", cacheManager(a, b))); + CachesEndpoint endpoint = new CachesEndpoint( + Collections.singletonMap("test", cacheManager(a, b))); assertThat(endpoint.clearCache("a", null)).isTrue(); verify(a).clear(); verify(b, never()).clear(); @@ -184,8 +184,8 @@ public void clearCacheWithSeveralCacheManagersWithCacheManagerFilter() { @Test public void clearCacheWithUnknownCache() { Cache a = mockCache("a"); - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", cacheManager(a))); + CachesEndpoint endpoint = new CachesEndpoint( + Collections.singletonMap("test", cacheManager(a))); assertThat(endpoint.clearCache("unknown", null)).isFalse(); verify(a, never()).clear(); } @@ -193,8 +193,8 @@ public void clearCacheWithUnknownCache() { @Test public void clearCacheWithUnknownCacheManager() { Cache a = mockCache("a"); - CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap( - "test", cacheManager(a))); + CachesEndpoint endpoint = new CachesEndpoint( + Collections.singletonMap("test", cacheManager(a))); assertThat(endpoint.clearCache("a", "unknown")).isFalse(); verify(a, never()).clear(); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java index e10dc27b34d3..95a664a35100 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java @@ -34,7 +34,8 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for {@link CachesEndpoint} exposed by Jersey, Spring MVC, and WebFlux. + * Integration tests for {@link CachesEndpoint} exposed by Jersey, Spring MVC, and + * WebFlux. * * @author Stephane Nicoll */ @@ -48,23 +49,22 @@ public class CachesEndpointWebIntegrationTests { @Test public void allCaches() { client.get().uri("/actuator/caches").exchange().expectStatus().isOk().expectBody() - .jsonPath("cacheManagers.one.a.target").isEqualTo( - ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.one.b.target").isEqualTo( - ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.two.a.target").isEqualTo( - ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.two.c.target").isEqualTo( - ConcurrentHashMap.class.getName()); + .jsonPath("cacheManagers.one.a.target") + .isEqualTo(ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.one.b.target") + .isEqualTo(ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.two.a.target") + .isEqualTo(ConcurrentHashMap.class.getName()) + .jsonPath("cacheManagers.two.c.target") + .isEqualTo(ConcurrentHashMap.class.getName()); } @Test public void namedCache() { client.get().uri("/actuator/caches/b").exchange().expectStatus().isOk() - .expectBody() - .jsonPath("name").isEqualTo("b") - .jsonPath("cacheManager").isEqualTo("one") - .jsonPath("target").isEqualTo(ConcurrentHashMap.class.getName()); + .expectBody().jsonPath("name").isEqualTo("b").jsonPath("cacheManager") + .isEqualTo("one").jsonPath("target") + .isEqualTo(ConcurrentHashMap.class.getName()); } @Test @@ -75,8 +75,7 @@ public void namedCacheWithUnknownName() { @Test public void namedCacheWithNonUniqueName() { - client.get().uri("/actuator/caches/a").exchange().expectStatus() - .isBadRequest(); + client.get().uri("/actuator/caches/a").exchange().expectStatus().isBadRequest(); } @Test @@ -95,11 +94,9 @@ public void cleanNamedCacheWithUnknownName() { @Test public void clearNamedCacheWithNonUniqueName() { - client.get().uri("/actuator/caches/a").exchange().expectStatus() - .isBadRequest(); + client.get().uri("/actuator/caches/a").exchange().expectStatus().isBadRequest(); } - @Configuration static class TestConfiguration { diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java index 9fc6fe21034e..00a62969b9f8 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java @@ -28,7 +28,8 @@ import org.springframework.test.web.reactive.server.WebTestClient; /** - * Integration tests for {@link IntegrationGraphEndpoint} exposed by Jersey, Spring MVC, and WebFlux. + * Integration tests for {@link IntegrationGraphEndpoint} exposed by Jersey, Spring MVC, + * and WebFlux. * * @author Tim Ysewyn */ @@ -39,8 +40,8 @@ public class IntegrationGraphEndpointWebIntegrationTests { @Test public void graph() { - client.get().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange() - .expectStatus().isOk().expectBody() + client.get().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isOk().expectBody() .jsonPath("contentDescriptor.providerVersion").isNotEmpty() .jsonPath("contentDescriptor.providerFormatVersion").isEqualTo(1.0f) .jsonPath("contentDescriptor.provider").isEqualTo("spring-integration"); @@ -48,8 +49,8 @@ public void graph() { @Test public void rebuild() { - client.post().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON).exchange() - .expectStatus().isNoContent(); + client.post().uri("/actuator/integrationgraph").accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isNoContent(); } @Configuration @@ -57,7 +58,8 @@ public void rebuild() { public static class TestConfiguration { @Bean - public IntegrationGraphEndpoint endpoint(IntegrationGraphServer integrationGraphServer) { + public IntegrationGraphEndpoint endpoint( + IntegrationGraphServer integrationGraphServer) { return new IntegrationGraphEndpoint(integrationGraphServer); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java index 6c43347295b8..61edf696a7e1 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/DefaultWebClientExchangeTagsProviderTests.java @@ -16,7 +16,6 @@ package org.springframework.boot.actuate.metrics.web.reactive.client; - import java.io.IOException; import java.net.URI; @@ -41,7 +40,8 @@ */ public class DefaultWebClientExchangeTagsProviderTests { - private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + + ".uriTemplate"; private WebClientExchangeTagsProvider tagsProvider = new DefaultWebClientExchangeTagsProvider(); @@ -52,8 +52,10 @@ public class DefaultWebClientExchangeTagsProviderTests { @Before public void setup() { this.request = ClientRequest - .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) - .attribute(URI_TEMPLATE_ATTRIBUTE, "http://example.org/projects/{project}") + .create(HttpMethod.GET, + URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, + "http://example.org/projects/{project}") .build(); this.response = mock(ClientResponse.class); given(this.response.statusCode()).willReturn(HttpStatus.OK); @@ -62,38 +64,37 @@ public void setup() { @Test public void tagsShouldBePopulated() { Iterable tags = this.tagsProvider.tags(this.request, this.response, null); - assertThat(tags).containsExactlyInAnyOrder( - Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), - Tag.of("clientName", "example.org"), Tag.of("status", "200")); + assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), + Tag.of("uri", "/projects/{project}"), Tag.of("clientName", "example.org"), + Tag.of("status", "200")); } @Test public void tagsWhenNoUriTemplateShouldProvideUriPath() { - ClientRequest request = ClientRequest - .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) - .build(); + ClientRequest request = ClientRequest.create(HttpMethod.GET, + URI.create("http://example.org/projects/spring-boot")).build(); Iterable tags = this.tagsProvider.tags(request, this.response, null); - assertThat(tags).containsExactlyInAnyOrder( - Tag.of("method", "GET"), Tag.of("uri", "/projects/spring-boot"), + assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), + Tag.of("uri", "/projects/spring-boot"), Tag.of("clientName", "example.org"), Tag.of("status", "200")); } @Test public void tagsWhenIoExceptionShouldReturnIoErrorStatus() { - Iterable tags = this.tagsProvider.tags(this.request, - null, new IOException()); - assertThat(tags).containsExactlyInAnyOrder( - Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), - Tag.of("clientName", "example.org"), Tag.of("status", "IO_ERROR")); + Iterable tags = this.tagsProvider.tags(this.request, null, + new IOException()); + assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), + Tag.of("uri", "/projects/{project}"), Tag.of("clientName", "example.org"), + Tag.of("status", "IO_ERROR")); } @Test public void tagsWhenExceptionShouldReturnClientErrorStatus() { - Iterable tags = this.tagsProvider.tags(this.request, - null, new IllegalArgumentException()); - assertThat(tags).containsExactlyInAnyOrder( - Tag.of("method", "GET"), Tag.of("uri", "/projects/{project}"), - Tag.of("clientName", "example.org"), Tag.of("status", "CLIENT_ERROR")); + Iterable tags = this.tagsProvider.tags(this.request, null, + new IllegalArgumentException()); + assertThat(tags).containsExactlyInAnyOrder(Tag.of("method", "GET"), + Tag.of("uri", "/projects/{project}"), Tag.of("clientName", "example.org"), + Tag.of("status", "CLIENT_ERROR")); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java index 173cfdbdf17a..31f5e5324dad 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientCustomizerTests.java @@ -60,4 +60,5 @@ public void customizeShouldNotAddDuplicateFilterFunction() { this.clientBuilder.filters((filters) -> assertThat(filters).hasSize(1).first() .isInstanceOf(MetricsWebClientFilterFunction.class)); } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java index f3dce2b13dbd..ac8d88520f6a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTagsTests.java @@ -40,7 +40,8 @@ */ public class WebClientExchangeTagsTests { - private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + ".uriTemplate"; + private static final String URI_TEMPLATE_ATTRIBUTE = WebClient.class.getName() + + ".uriTemplate"; private ClientRequest request; @@ -49,8 +50,10 @@ public class WebClientExchangeTagsTests { @Before public void setup() { this.request = ClientRequest - .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) - .attribute(URI_TEMPLATE_ATTRIBUTE, "http://example.org/projects/{project}") + .create(HttpMethod.GET, + URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, + "http://example.org/projects/{project}") .build(); this.response = mock(ClientResponse.class); given(this.response.statusCode()).willReturn(HttpStatus.OK); @@ -71,18 +74,17 @@ public void uriWhenAbsoluteTemplateIsAvailableShouldReturnTemplate() { @Test public void uriWhenRelativeTemplateIsAvailableShouldReturnTemplate() { this.request = ClientRequest - .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) - .attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}") - .build(); + .create(HttpMethod.GET, + URI.create("http://example.org/projects/spring-boot")) + .attribute(URI_TEMPLATE_ATTRIBUTE, "/projects/{project}").build(); assertThat(WebClientExchangeTags.uri(this.request)) .isEqualTo(Tag.of("uri", "/projects/{project}")); } @Test public void uriWhenTemplateIsMissingShouldReturnPath() { - this.request = ClientRequest - .create(HttpMethod.GET, URI.create("http://example.org/projects/spring-boot")) - .build(); + this.request = ClientRequest.create(HttpMethod.GET, + URI.create("http://example.org/projects/spring-boot")).build(); assertThat(WebClientExchangeTags.uri(this.request)) .isEqualTo(Tag.of("uri", "/projects/spring-boot")); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java index ac5c688ef1b9..567cddc869f6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java @@ -59,8 +59,7 @@ public DefaultCouchbaseEnvironment couchbaseEnvironment() { @Bean @Primary public Cluster couchbaseCluster() { - return CouchbaseCluster.create(couchbaseEnvironment(), - determineBootstrapHosts()); + return CouchbaseCluster.create(couchbaseEnvironment(), determineBootstrapHosts()); } /** @@ -75,10 +74,8 @@ protected List determineBootstrapHosts() { @Primary @DependsOn("couchbaseClient") public ClusterInfo couchbaseClusterInfo() { - return couchbaseCluster() - .clusterManager(this.properties.getBucket().getName(), - this.properties.getBucket().getPassword()) - .info(); + return couchbaseCluster().clusterManager(this.properties.getBucket().getName(), + this.properties.getBucket().getPassword()).info(); } @Bean @@ -113,8 +110,8 @@ protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder( builder = builder.viewServiceConfig(getViewServiceConfig(endpoints)); } if (timeouts.getSocketConnect() != null) { - builder = builder.socketConnectTimeout( - (int) timeouts.getSocketConnect().toMillis()); + builder = builder + .socketConnectTimeout((int) timeouts.getSocketConnect().toMillis()); } if (timeouts.getView() != null) { builder = builder.viewTimeout(timeouts.getView().toMillis()); @@ -147,8 +144,7 @@ private ViewServiceConfig getViewServiceConfig(Endpoints endpoints) { private T getServiceConfig(CouchbaseService service, Integer fallback, BiFunction factory) { if (service.getMinEndpoints() != 1 || service.getMaxEndpoints() != 1) { - return factory.apply(service.getMinEndpoints(), - service.getMaxEndpoints()); + return factory.apply(service.getMinEndpoints(), service.getMaxEndpoints()); } int endpoints = (fallback != null ? fallback : 1); return factory.apply(endpoints, endpoints); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java index cd2ac0dd333e..61e0a1a4e595 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index a13283350187..2bc4280bc8f7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -578,6 +578,7 @@ public static String format(Object key, Object value) { } return String.format("-D%s=\"%s\"", key, value); } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index cf75bd6b50ac..9da8315a5bf4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -67,8 +67,7 @@ protected void logDisabledFork() { @Override protected void runWithForkedJvm(File workingDirectory, List args, - Map environmentVariables) - throws MojoExecutionException { + Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 151981c6c275..14da020d5009 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -103,8 +103,7 @@ protected void runWithForkedJvm(File workingDirectory, List args, } private RunProcess runProcess(File workingDirectory, List args, - Map environmentVariables) - throws MojoExecutionException { + Map environmentVariables) throws MojoExecutionException { try { RunProcess runProcess = new RunProcess(workingDirectory, new JavaExecutable().toString()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java index 21242e19b7f4..e574cd1b3f5a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java @@ -39,8 +39,8 @@ public void asNull() { @Test public void asArray() { - assertThat(new EnvVariables(getTestArgs()).asArray()) - .contains("key=My Value", "key1= tt ", "key2= ", "key3="); + assertThat(new EnvVariables(getTestArgs()).asArray()).contains("key=My Value", + "key1= tt ", "key2= ", "key3="); } @Test From c578a30e9040693802e151215bc1e6abb99d8e3e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 4 May 2018 22:43:22 -0700 Subject: [PATCH 029/701] Polish --- .../src/main/asciidoc/endpoints/caches.adoc | 8 ----- .../asciidoc/endpoints/integrationgraph.adoc | 3 -- .../WebClientMetricsAutoConfiguration.java | 1 - .../boot/actuate/cache/CachesEndpoint.java | 35 +++++++++++-------- .../integration/IntegrationGraphEndpoint.java | 5 +-- .../IntegrationGraphEndpointTests.java | 9 +++-- 6 files changed, 27 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc index 6342cf77c708..7c795aca1e75 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc @@ -7,7 +7,6 @@ The `caches` endpoint provides access to the application's caches. [[caches-all]] == Retrieving All Caches - To retrieve the application's caches, make a `GET` request to `/actuator/caches`, as shown in the following curl-based example: @@ -21,7 +20,6 @@ include::{snippets}caches/all/http-response.adoc[] [[caches-all-response-structure]] === Response Structure - The response contains details of the application's caches. The following table describes the structure of the response: @@ -32,7 +30,6 @@ include::{snippets}caches/all/response-fields.adoc[] [[caches-named]] == Retrieving Caches by Name - To retrieve a cache by name, make a `GET` request to `/actuator/caches/{name}`, as shown in the following curl-based example: @@ -47,7 +44,6 @@ include::{snippets}caches/named/http-response.adoc[] [[caches-named-request-structure]] === Request Structure - If the requested name is specific enough to identify a single cache, no extra parameter is required. Otherwise, the `cacheManager` must be specified. The following table shows the supported query parameters: @@ -59,7 +55,6 @@ include::{snippets}caches/named/request-parameters.adoc[] [[caches-named-response-structure]] === Response Structure - The response contains details of the requested cache. The following table describes the structure of the response: @@ -70,7 +65,6 @@ include::{snippets}caches/named/response-fields.adoc[] [[caches-evict-all]] == Evict All Caches - To clear all available caches, make a `DELETE` request to `/actuator/caches` as shown in the following curl-based example: @@ -80,7 +74,6 @@ include::{snippets}caches/evict-all/curl-request.adoc[] [[caches-evict-named]] == Evict a Cache by Name - To evict a particular cache, make a `DELETE` request to `/actuator/caches/{name}` as shown in the following curl-based example: @@ -93,7 +86,6 @@ specify which `Cache` should be cleared. [[caches-evict-named-request-structure]] === Request Structure - If the requested name is specific enough to identify a single cache, no extra parameter is required. Otherwise, the `cacheManager` must be specified. The following table shows the supported query parameters: diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc index 8d0e3a19cc16..469cfa6f780d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/integrationgraph.adoc @@ -8,7 +8,6 @@ components. [[integrationgraph-retrieving]] == Retrieving the Spring Integration graph - To retrieve the information about the application, make a `GET` request to `/actuator/integrationgraph`, as shown in the following curl-based example: @@ -22,7 +21,6 @@ include::{snippets}integrationgraph/graph/http-response.adoc[] [[integrationgraph-retrieving-response-structure]] === Response Structure - The response contains all Spring Integration components used within the application, as well as the links between them. More information about the structure can be found in the https://docs.spring.io/spring-integration/reference/html/system-management-chapter.html#integration-graph[reference @@ -32,7 +30,6 @@ documentation]. [[integrationgraph-rebuilding]] == Rebuilding the Spring Integration graph - To rebuild the exposed graph, make a `POST` request to `/actuator/integrationgraph`, as shown in the following curl-based example: diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java index a0d0de491c65..c156497214e0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java @@ -39,7 +39,6 @@ /** * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of * {@link org.springframework.web.reactive.function.client.WebClient}. - * *

* This is reusing the {@link io.micrometer.core.instrument.config.MeterFilter} defined in * {@link RestTemplateMetricsAutoConfiguration} for limiting the cardinality of "uri" diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 7f51bd42292e..8e9c20a57716 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -59,11 +59,13 @@ public CachesEndpoint(Map cacheManagers) { @ReadOperation public CachesReport caches() { Map> descriptors = new LinkedHashMap<>(); - getCacheEntries((name) -> true, (cacheManager) -> true).forEach((entry) -> { - Map cmDescriptors = descriptors.computeIfAbsent( - entry.getCacheManager(), (key) -> new LinkedHashMap<>()); - String cache = entry.getName(); - cmDescriptors.put(cache, new CacheDescriptor(entry.getTarget())); + getCacheEntries(matchAll(), matchAll()).forEach((entry) -> { + String cacheName = entry.getName(); + String cacheManager = entry.getCacheManager(); + Map cacheManagerDescriptors = descriptors + .computeIfAbsent(cacheManager, (key) -> new LinkedHashMap<>()); + cacheManagerDescriptors.put(cacheName, + new CacheDescriptor(entry.getTarget())); }); return new CachesReport(descriptors); } @@ -79,7 +81,7 @@ public CachesReport caches() { @ReadOperation public CacheEntry cache(@Selector String cache, @Nullable String cacheManager) { return extractUniqueCacheEntry(cache, - getCacheEntries((name) -> name.equals(cache), safeEqual(cacheManager))); + getCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager))); } /** @@ -87,14 +89,13 @@ public CacheEntry cache(@Selector String cache, @Nullable String cacheManager) { */ @DeleteOperation public void clearCaches() { - getCacheEntries((name) -> true, (cacheManagerName) -> true) - .forEach(this::clearCache); + getCacheEntries(matchAll(), matchAll()).forEach(this::clearCache); } /** * Clear the specific {@link Cache}. * @param cache then name of the cache - * @param cacheManager the name of the cacheManager (can be {@code null} + * @param cacheManager the name of the cacheManager (can be {@code null} to match all) * @return {@code true} if the cache was cleared or {@code false} if no such cache * exists * @throws NonUniqueCacheException if more than one cache with that name exist and no @@ -102,7 +103,7 @@ public void clearCaches() { @DeleteOperation public boolean clearCache(@Selector String cache, @Nullable String cacheManager) { CacheEntry entry = extractUniqueCacheEntry(cache, - getCacheEntries((name) -> name.equals(cache), safeEqual(cacheManager))); + getCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager))); return (entry != null && clearCache(entry)); } @@ -131,12 +132,13 @@ private CacheEntry extractUniqueCacheEntry(String cache, List entrie entries.stream().map(CacheEntry::getCacheManager).distinct() .collect(Collectors.toList())); } - return (entries.isEmpty() ? null : entries.get(0)); + return (!entries.isEmpty() ? entries.get(0) : null); } private boolean clearCache(CacheEntry entry) { String cacheName = entry.getName(); - Cache cache = this.cacheManagers.get(entry.getCacheManager()).getCache(cacheName); + String cacheManager = entry.getCacheManager(); + Cache cache = this.cacheManagers.get(cacheManager).getCache(cacheName); if (cache != null) { cache.clear(); return true; @@ -144,9 +146,12 @@ private boolean clearCache(CacheEntry entry) { return false; } - private Predicate safeEqual(String name) { - return (name != null ? ((requested) -> requested.equals(name)) - : ((requested) -> true)); + private Predicate isNameMatch(String name) { + return (name != null ? ((requested) -> requested.equals(name)) : matchAll()); + } + + private Predicate matchAll() { + return (name) -> true; } /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java index f2e034e8735f..a4be984bd967 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java @@ -34,8 +34,9 @@ public class IntegrationGraphEndpoint { private final IntegrationGraphServer graphServer; /** - * Create a new {@code IntegrationGraphEndpoint} that exposes a graph containing all - * the Spring Integration components in the given {@link IntegrationGraphServer}. + * Create a new {@code IntegrationGraphEndpoint} instance that exposes a graph + * containing all the Spring Integration components in the given + * {@link IntegrationGraphServer}. * @param graphServer the integration graph server */ public IntegrationGraphEndpoint(IntegrationGraphServer graphServer) { diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java index d4f5808ae577..59c9339df28a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java @@ -26,9 +26,9 @@ import org.springframework.integration.support.management.graph.IntegrationGraphServer; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.mock; -import static org.mockito.BDDMockito.verify; -import static org.mockito.BDDMockito.when; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; /** * Tests for {@link IntegrationGraphEndpoint}. @@ -51,8 +51,7 @@ public void setUp() { @Test public void readOperationShouldReturnGraph() { Graph mockedGraph = mock(Graph.class); - when(this.integrationGraphServer.getGraph()).thenReturn(mockedGraph); - + given(this.integrationGraphServer.getGraph()).willReturn(mockedGraph); Graph graph = this.integrationGraphEndpoint.graph(); verify(this.integrationGraphServer).getGraph(); assertThat(graph).isEqualTo(mockedGraph); From 31c7102800ba57fdadfad142f964048626796d5b Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 7 May 2018 11:48:04 +0200 Subject: [PATCH 030/701] Upgrade to Reactor Californium This Reactor generation will get the Reactor Netty 0.8 upgrade, which will include important changes such as maven coordinate, package and API changes. --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b5dda58c4edc..8daeddc37c61 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -136,7 +136,7 @@ 2.3.0 4.1.4 5.1.2 - Bismuth-SR9 + Californium-BUILD-SNAPSHOT 3.0.7 1.0.2 1.3.8 From 96ce71ddc436b94a13c9e3214411fc4f83185cac Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sat, 5 May 2018 12:55:42 +0900 Subject: [PATCH 031/701] Polish Closes gh-13078 --- .../org/springframework/boot/actuate/cache/CachesEndpoint.java | 2 +- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 8e9c20a57716..4b31bdef2099 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -35,7 +35,7 @@ /** * {@link Endpoint} to expose available {@link Cache caches}. * - * @author Johannes Edmeuer + * @author Johannes Edmeier * @author Stephane Nicoll * @since 2.1.0 */ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 482c7afc410a..d614d1e6bcd1 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1194,7 +1194,7 @@ content into your application. Rather, pick only the properties that you need. management.endpoint.beans.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.beans.enabled=true # Whether to enable the beans endpoint. - # CACHES ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/cache/CachesEndpoint.{sc-ext}[CachesEndpoint]) + # CACHES ENDPOINT ({sc-spring-boot-actuator}/cache/CachesEndpoint.{sc-ext}[CachesEndpoint]) management.endpoint.caches.cache.time-to-live=0ms # Maximum time that a response can be cached. management.endpoint.caches.enabled=true # Whether to enable the caches endpoint. From 84c9a65e9d0bc8c24c8a3cfcfbdc2e46945e3174 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 7 May 2018 17:57:09 +0200 Subject: [PATCH 032/701] Auto-configure Elasticsearch REST clients This commit adds auto-configuration support for both `RestClient` and `RestHighLevelClient` which are provided by `elasticsearch-rest-client` and `elasticsearch-rest-high-level-client` dependencies respectively. `RestClient` is associated with configuration properties in the `spring.elasticsearch.rest.*` namespace, since this is the component taking care of HTTP communication with the actual Elasticsearch node. `RestHighLevelClient` wraps the first one and naturally inherits that configuration. Closes gh-12600 --- .../spring-boot-autoconfigure/pom.xml | 10 ++ .../rest/RestClientAutoConfiguration.java | 100 +++++++++++++++ .../rest/RestClientBuilderCustomizer.java | 37 ++++++ .../rest/RestClientProperties.java | 75 +++++++++++ .../elasticsearch/rest/package-info.java | 20 +++ ...itional-spring-configuration-metadata.json | 6 + .../main/resources/META-INF/spring.factories | 1 + .../jest/JestAutoConfigurationTests.java | 24 ++-- .../RestClientAutoConfigurationTests.java | 119 ++++++++++++++++++ .../spring-boot-dependencies/pom.xml | 10 ++ .../appendix-application-properties.adoc | 5 + .../main/asciidoc/spring-boot-features.adoc | 45 +++++-- 12 files changed, 429 insertions(+), 23 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 7d46adb23203..d86bef25c03d 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -305,6 +305,16 @@ ehcache true + + org.elasticsearch.client + elasticsearch-rest-client + true + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + true + org.freemarker freemarker diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java new file mode 100644 index 000000000000..39861f044a0a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -0,0 +1,100 @@ +/* + * Copyright 2012-2018 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.autoconfigure.elasticsearch.rest; + +import java.util.Collections; +import java.util.List; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-Configuration} + * for Elasticseach REST clients. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass(RestClient.class) +@EnableConfigurationProperties(RestClientProperties.class) +public class RestClientAutoConfiguration { + + + private final RestClientProperties properties; + + private final List builderCustomizers; + + public RestClientAutoConfiguration(RestClientProperties properties, + ObjectProvider> builderCustomizers) { + this.properties = properties; + this.builderCustomizers = builderCustomizers.getIfAvailable(Collections::emptyList); + } + + @Bean(destroyMethod = "close") + @ConditionalOnMissingBean + public RestClient restClient() { + RestClientBuilder builder = configureBuilder(); + return builder.build(); + } + + protected RestClientBuilder configureBuilder() { + HttpHost[] hosts = this.properties.getUris().stream() + .map(HttpHost::create).toArray(HttpHost[]::new); + RestClientBuilder builder = RestClient.builder(hosts); + PropertyMapper map = PropertyMapper.get(); + map.from(this.properties::getUsername).whenHasText().to((username) -> { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + Credentials credentials = new UsernamePasswordCredentials( + this.properties.getUsername(), this.properties.getPassword()); + credentialsProvider.setCredentials(AuthScope.ANY, credentials); + builder.setHttpClientConfigCallback(httpClientBuilder -> + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + }); + this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + return builder; + } + + @Configuration + @ConditionalOnClass(RestHighLevelClient.class) + public static class RestHighLevelClientConfiguration { + + @Bean + @ConditionalOnMissingBean + public RestHighLevelClient restHighLevelClient(RestClient restClient) { + return new RestHighLevelClient(restClient); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java new file mode 100644 index 000000000000..8ed0f1f77719 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2018 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.autoconfigure.elasticsearch.rest; + +import org.elasticsearch.client.RestClientBuilder; + +/** + * Callback interface that can be implemented by beans wishing to further customize the + * {@link org.elasticsearch.client.RestClient} via a {@link RestClientBuilder} whilst + * retaining default auto-configuration. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@FunctionalInterface +public interface RestClientBuilderCustomizer { + + /** + * Customize the {@link RestClientBuilder}. + * @param builder the builder to customize + */ + void customize(RestClientBuilder builder); +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java new file mode 100644 index 000000000000..33d876b38484 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2018 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.autoconfigure.elasticsearch.rest; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Elasticsearch REST clients. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@ConfigurationProperties(prefix = "spring.elasticsearch.rest") +public class RestClientProperties { + + /** + * Comma-separated list of the Elasticsearch instances to use. + */ + private List uris = new ArrayList<>( + Collections.singletonList("http://localhost:9200")); + + /** + * Credentials username. + */ + private String username; + + /** + * Credentials password. + */ + private String password; + + + + public List getUris() { + return this.uris; + } + + public void setUris(List uris) { + this.uris = uris; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/package-info.java new file mode 100644 index 000000000000..b6252cc58075 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Elasticsearch REST clients. + */ +package org.springframework.boot.autoconfigure.elasticsearch.rest; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5da488a05fce..fca0a274d9e1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -212,6 +212,12 @@ "http://localhost:9200" ] }, + { + "name": "spring.elasticsearch.rest.uris", + "defaultValue": [ + "http://localhost:9200" + ] + }, { "name": "spring.info.build.location", "defaultValue": "classpath:META-INF/build-info.properties" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index b140c1f7501e..a88022db1f2f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -56,6 +56,7 @@ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfigura org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\ +org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\ org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java index 533599e9d38b..58aff9a82277 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java @@ -25,10 +25,8 @@ import io.searchbox.client.JestClient; import io.searchbox.client.JestResult; import io.searchbox.client.http.JestHttpClient; +import io.searchbox.core.Get; import io.searchbox.core.Index; -import io.searchbox.core.Search; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -74,9 +72,8 @@ public void close() { @Test public void jestClientOnLocalhostByDefault() { - this.contextRunner - .run((context) -> assertThat(context.getBeansOfType(JestClient.class)) - .hasSize(1)); + this.contextRunner.run((context) -> + assertThat(context).hasSingleBean(JestClient.class)); } @Test @@ -84,8 +81,7 @@ public void customJestClient() { this.contextRunner.withUserConfiguration(CustomJestClient.class) .withPropertyValues( "spring.elasticsearch.jest.uris[0]=http://localhost:9200") - .run((context) -> assertThat(context.getBeansOfType(JestClient.class)) - .hasSize(1)); + .run((context) -> assertThat(context).hasSingleBean(JestClient.class)); } @Test @@ -134,15 +130,11 @@ public void jestCanCommunicateWithElasticsearchInstance() { Map source = new HashMap<>(); source.put("a", "alpha"); source.put("b", "bravo"); - Index index = new Index.Builder(source).index("foo").type("bar") - .build(); + Index index = new Index.Builder(source).index("foo") + .type("bar").id("1").build(); execute(client, index); - SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); - searchSourceBuilder.query(QueryBuilders.matchQuery("a", "alpha")); - assertThat(execute(client, - new Search.Builder(searchSourceBuilder.toString()) - .addIndex("foo").build()).getResponseCode()) - .isEqualTo(200); + Get getRequest = new Get.Builder("foo", "1").build(); + assertThat(execute(client, getRequest).getResponseCode()).isEqualTo(200); })); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java new file mode 100644 index 000000000000..db10850d526d --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2012-2018 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.autoconfigure.elasticsearch.rest; + + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchNodeTemplate; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ReflectionUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link RestClientAutoConfiguration} + * + * @author Brian Clozel + */ +public class RestClientAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class)); + + @Test + public void configureShouldCreateBothRestClientVariants() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class); + }); + } + + @Test + public void configureWhenCustomClientShouldBackOff() { + this.contextRunner + .withUserConfiguration(CustomRestClientConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(RestClient.class) + .hasBean("customRestClient"); + }); + } + + @Test + public void configureWhenBuilderCustomizerShouldApply() { + this.contextRunner + .withUserConfiguration(BuilderCustomizerConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(RestClient.class); + RestClient restClient = context.getBean(RestClient.class); + Field field = ReflectionUtils.findField(RestClient.class, + "maxRetryTimeoutMillis"); + ReflectionUtils.makeAccessible(field); + assertThat(ReflectionUtils.getField(field, restClient)) + .isEqualTo(42L); + }); + } + + @Test + public void restClientCanQueryElasticsearchNode() { + new ElasticsearchNodeTemplate().doWithNode((node) -> this.contextRunner + .withPropertyValues("spring.elasticsearch.rest.uris=http://localhost:" + + node.getHttpPort()) + .run((context) -> { + RestHighLevelClient client = context.getBean(RestHighLevelClient.class); + Map source = new HashMap<>(); + source.put("a", "alpha"); + source.put("b", "bravo"); + IndexRequest index = new IndexRequest("foo", "bar", "1") + .source(source); + client.index(index); + GetRequest getRequest = new GetRequest("foo", "bar", "1"); + assertThat(client.get(getRequest).isExists()).isTrue(); + })); + } + + @Configuration + static class CustomRestClientConfiguration { + + @Bean + public RestClient customRestClient() { + return mock(RestClient.class); + } + } + + @Configuration + static class BuilderCustomizerConfiguration { + + @Bean + public RestClientBuilderCustomizer myCustomizer() { + return builder -> builder.setMaxRetryTimeoutMillis(42); + } + } + +} diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8daeddc37c61..58a9ee0ca92c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1757,6 +1757,16 @@ transport-netty4-client ${elasticsearch.version} + + org.elasticsearch.client + elasticsearch-rest-client + ${elasticsearch.version} + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + ${elasticsearch.version} + org.firebirdsql.jdbc jaybird-jdk17 diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index d614d1e6bcd1..ce103d95e0fb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -717,6 +717,11 @@ content into your application. Rather, pick only the properties that you need. spring.elasticsearch.jest.uris=http://localhost:9200 # Comma-separated list of the Elasticsearch instances to use. spring.elasticsearch.jest.username= # Login username. + # Elasticsearch REST clients ({sc-spring-boot-autoconfigure}/elasticsearch/rest/RestClientProperties.{sc-ext}[RestClientProperties]) + spring.elasticsearch.rest.password= # Credentials username. + spring.elasticsearch.rest.uris=http://localhost:9200 # Comma-separated list of the Elasticsearch instances to use. + spring.elasticsearch.rest.username= # Credentials password. + # H2 Web Console ({sc-spring-boot-autoconfigure}/h2/H2ConsoleProperties.{sc-ext}[H2ConsoleProperties]) spring.h2.console.enabled=false # Whether to enable the console. spring.h2.console.path=/h2-console # Path at which the console is available. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 9e19cb9c2bb7..c464502ca25b 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4221,14 +4221,45 @@ https://projects.spring.io/spring-data-solr/[reference documentation]. [[boot-features-elasticsearch]] === Elasticsearch -http://www.elasticsearch.org/[Elasticsearch] is an open source, distributed, real-time -search and analytics engine. Spring Boot offers basic auto-configuration for -Elasticsearch and the abstractions on top of it provided by -https://github.com/spring-projects/spring-data-elasticsearch[Spring Data Elasticsearch]. -There is a `spring-boot-starter-data-elasticsearch` "`Starter`" for collecting the -dependencies in a convenient way. Spring Boot also supports -https://github.com/searchbox-io/Jest[Jest]. +https://www.elastic.co/products/elasticsearch[Elasticsearch] is an open source, +distributed, RESTful search and analytics engine. Spring Boot offers basic +auto-configuration for Elasticsearch. +Spring Boot supports several HTTP clients: + +* The official Java "Low Level" and "High Level" REST clients +* https://github.com/searchbox-io/Jest[Jest] + +The transport client is still being used by +https://github.com/spring-projects/spring-data-elasticsearch[Spring Data Elasticsearch], +which you can start using with the `spring-boot-starter-data-elasticsearch` "`Starter`". + + +[[boot-features-connecting-to-elasticsearch-rest]] +==== Connecting to Elasticsearch by REST clients +Elasticsearch ships +https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html[two different REST clients] +that you can use to query a cluster: the "Low Level" client and the "High Level" client. + +If you have the `org.elasticsearch.client:elasticsearch-rest-client` dependency on the +classpath, Spring Boot will auto-configure and register a `RestClient` bean that +by default targets `http://localhost:9200`. +You can further tune how `RestClient` is configured, as shown in the following example: + +[source,properties,indent=0] +---- + spring.elasticsearch.rest.uris=http://search.example.com:9200 + spring.elasticsearch.rest.username=user + spring.elasticsearch.rest.password=secret +---- + +You can also register an arbitrary number of beans that implement +`RestClientBuilderCustomizer` for more advanced customizations. +To take full control over the registration, define a `RestClient` bean. + +If you have the `org.elasticsearch.client:elasticsearch-rest-high-level-client` dependency +on the classpath, Spring Boot will auto-configure a `RestHighLevelClient`, which wraps +any existing `RestClient` bean, reusing its HTTP configuration. [[boot-features-connecting-to-elasticsearch-jest]] From a1bea69555845596cbcb1abc4ae74edc966d9f01 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 8 May 2018 12:12:21 +0100 Subject: [PATCH 033/701] Make Elasticsearch dependency available to javadoc generation See gh-12600 --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index eb3533c634d7..ac1356c457a0 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -492,6 +492,11 @@ http2-server true + + org.elasticsearch.client + elasticsearch-rest-high-level-client + ${elasticsearch.version} + org.flywaydb flyway-core From e4bdf4e51370abaad1530c342bb04cbede7e429e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 8 May 2018 12:14:12 +0100 Subject: [PATCH 034/701] Polish --- spring-boot-project/spring-boot-docs/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index ac1356c457a0..eb88cd8f2205 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -495,7 +495,7 @@ org.elasticsearch.client elasticsearch-rest-high-level-client - ${elasticsearch.version} + true org.flywaydb From d77c4c83a1f63eb5b771942f01134870c799878f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 9 May 2018 09:19:03 +0100 Subject: [PATCH 035/701] Polish --- .../rest/RestClientAutoConfiguration.java | 15 ++++++----- .../RestClientAutoConfigurationTests.java | 25 ++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index 39861f044a0a..3c17aaa61f7f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -39,8 +39,7 @@ import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-Configuration} - * for Elasticseach REST clients. + * {@link EnableAutoConfiguration Auto-Configuration} for Elasticseach REST clients. * * @author Brian Clozel * @since 2.1.0 @@ -50,7 +49,6 @@ @EnableConfigurationProperties(RestClientProperties.class) public class RestClientAutoConfiguration { - private final RestClientProperties properties; private final List builderCustomizers; @@ -58,7 +56,8 @@ public class RestClientAutoConfiguration { public RestClientAutoConfiguration(RestClientProperties properties, ObjectProvider> builderCustomizers) { this.properties = properties; - this.builderCustomizers = builderCustomizers.getIfAvailable(Collections::emptyList); + this.builderCustomizers = builderCustomizers + .getIfAvailable(Collections::emptyList); } @Bean(destroyMethod = "close") @@ -69,8 +68,8 @@ public RestClient restClient() { } protected RestClientBuilder configureBuilder() { - HttpHost[] hosts = this.properties.getUris().stream() - .map(HttpHost::create).toArray(HttpHost[]::new); + HttpHost[] hosts = this.properties.getUris().stream().map(HttpHost::create) + .toArray(HttpHost[]::new); RestClientBuilder builder = RestClient.builder(hosts); PropertyMapper map = PropertyMapper.get(); map.from(this.properties::getUsername).whenHasText().to((username) -> { @@ -78,8 +77,8 @@ protected RestClientBuilder configureBuilder() { Credentials credentials = new UsernamePasswordCredentials( this.properties.getUsername(), this.properties.getPassword()); credentialsProvider.setCredentials(AuthScope.ANY, credentials); - builder.setHttpClientConfigCallback(httpClientBuilder -> - httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder + .setDefaultCredentialsProvider(credentialsProvider)); }); this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); return builder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java index db10850d526d..e2bd0fed32d0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; - import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -49,26 +48,21 @@ public class RestClientAutoConfigurationTests { @Test public void configureShouldCreateBothRestClientVariants() { - this.contextRunner.run((context) -> { - assertThat(context).hasSingleBean(RestClient.class) - .hasSingleBean(RestHighLevelClient.class); - }); + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class)); } @Test public void configureWhenCustomClientShouldBackOff() { - this.contextRunner - .withUserConfiguration(CustomRestClientConfiguration.class) - .run((context) -> { - assertThat(context).hasSingleBean(RestClient.class) - .hasBean("customRestClient"); - }); + this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(RestClient.class) + .hasBean("customRestClient")); } @Test public void configureWhenBuilderCustomizerShouldApply() { - this.contextRunner - .withUserConfiguration(BuilderCustomizerConfiguration.class) + this.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class) .run((context) -> { assertThat(context).hasSingleBean(RestClient.class); RestClient restClient = context.getBean(RestClient.class); @@ -86,7 +80,8 @@ public void restClientCanQueryElasticsearchNode() { .withPropertyValues("spring.elasticsearch.rest.uris=http://localhost:" + node.getHttpPort()) .run((context) -> { - RestHighLevelClient client = context.getBean(RestHighLevelClient.class); + RestHighLevelClient client = context + .getBean(RestHighLevelClient.class); Map source = new HashMap<>(); source.put("a", "alpha"); source.put("b", "bravo"); @@ -112,7 +107,7 @@ static class BuilderCustomizerConfiguration { @Bean public RestClientBuilderCustomizer myCustomizer() { - return builder -> builder.setMaxRetryTimeoutMillis(42); + return (builder) -> builder.setMaxRetryTimeoutMillis(42); } } From c72df104d8ad8f534a422835be5d8b6f0ebf490b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 9 May 2018 11:07:37 +0200 Subject: [PATCH 036/701] Improve caches endpoint format This commit adds an intermediate "caches" element so that additional cache manager attributes can be added in the future. Closes gh-13079 --- .../CachesEndpointDocumentationTests.java | 4 +-- .../boot/actuate/cache/CachesEndpoint.java | 29 ++++++++++++++++--- .../actuate/cache/CachesEndpointTests.java | 18 ++++++------ .../CachesEndpointWebIntegrationTests.java | 8 ++--- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java index 8bff0fa75563..9f657419d143 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/CachesEndpointDocumentationTests.java @@ -68,9 +68,9 @@ public void allCaches() throws Exception { .andDo(MockMvcRestDocumentation.document("caches/all", responseFields( fieldWithPath("cacheManagers") .description("Cache managers keyed by id."), - fieldWithPath("cacheManagers.*").description( + fieldWithPath("cacheManagers.*.caches").description( "Caches in the application context keyed by " + "name.")) - .andWithPrefix("cacheManagers.*.*.", + .andWithPrefix("cacheManagers.*.caches.*.", fieldWithPath("target").description( "Fully qualified name of the native cache.")))); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 4b31bdef2099..afcdc0c8b427 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -67,7 +67,10 @@ public CachesReport caches() { cacheManagerDescriptors.put(cacheName, new CacheDescriptor(entry.getTarget())); }); - return new CachesReport(descriptors); + Map cacheManagerDescriptors = new LinkedHashMap<>(); + descriptors.forEach((name, entries) -> + cacheManagerDescriptors.put(name, new CacheManagerDescriptor(entries))); + return new CachesReport(cacheManagerDescriptors); } /** @@ -160,18 +163,36 @@ private Predicate matchAll() { */ public static final class CachesReport { - private final Map> cacheManagers; + private final Map cacheManagers; - public CachesReport(Map> cacheManagers) { + public CachesReport(Map cacheManagers) { this.cacheManagers = cacheManagers; } - public Map> getCacheManagers() { + public Map getCacheManagers() { return this.cacheManagers; } } + /** + * Description of a {@link CacheManager}, primarily intended for serialization to + * JSON. + */ + public static final class CacheManagerDescriptor { + + private final Map caches; + + public CacheManagerDescriptor(Map caches) { + this.caches = caches; + } + + public Map getCaches() { + return this.caches; + } + + } + /** * Basic description of a {@link Cache}, primarily intended for serialization to JSON. */ diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java index 7a269126682c..5777c9d73802 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointTests.java @@ -26,8 +26,8 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.boot.actuate.cache.CachesEndpoint.CacheDescriptor; import org.springframework.boot.actuate.cache.CachesEndpoint.CacheEntry; +import org.springframework.boot.actuate.cache.CachesEndpoint.CacheManagerDescriptor; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; @@ -53,14 +53,14 @@ public class CachesEndpointTests { public void allCachesWithSingleCacheManager() { CachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap("test", new ConcurrentMapCacheManager("a", "b"))); - Map> allDescriptors = endpoint.caches() + Map allDescriptors = endpoint.caches() .getCacheManagers(); assertThat(allDescriptors).containsOnlyKeys("test"); - Map descriptors = allDescriptors.get("test"); - assertThat(descriptors).containsOnlyKeys("a", "b"); - assertThat(descriptors.get("a").getTarget()) + CacheManagerDescriptor descriptors = allDescriptors.get("test"); + assertThat(descriptors.getCaches()).containsOnlyKeys("a", "b"); + assertThat(descriptors.getCaches().get("a").getTarget()) .isEqualTo(ConcurrentHashMap.class.getName()); - assertThat(descriptors.get("b").getTarget()) + assertThat(descriptors.getCaches().get("b").getTarget()) .isEqualTo(ConcurrentHashMap.class.getName()); } @@ -70,11 +70,11 @@ public void allCachesWithSeveralCacheManagers() { cacheManagers.put("test", new ConcurrentMapCacheManager("a", "b")); cacheManagers.put("another", new ConcurrentMapCacheManager("a", "c")); CachesEndpoint endpoint = new CachesEndpoint(cacheManagers); - Map> allDescriptors = endpoint.caches() + Map allDescriptors = endpoint.caches() .getCacheManagers(); assertThat(allDescriptors).containsOnlyKeys("test", "another"); - assertThat(allDescriptors.get("test")).containsOnlyKeys("a", "b"); - assertThat(allDescriptors.get("another")).containsOnlyKeys("a", "c"); + assertThat(allDescriptors.get("test").getCaches()).containsOnlyKeys("a", "b"); + assertThat(allDescriptors.get("another").getCaches()).containsOnlyKeys("a", "c"); } @Test diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java index 95a664a35100..1f547a6f5c7d 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cache/CachesEndpointWebIntegrationTests.java @@ -49,13 +49,13 @@ public class CachesEndpointWebIntegrationTests { @Test public void allCaches() { client.get().uri("/actuator/caches").exchange().expectStatus().isOk().expectBody() - .jsonPath("cacheManagers.one.a.target") + .jsonPath("cacheManagers.one.caches.a.target") .isEqualTo(ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.one.b.target") + .jsonPath("cacheManagers.one.caches.b.target") .isEqualTo(ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.two.a.target") + .jsonPath("cacheManagers.two.caches.a.target") .isEqualTo(ConcurrentHashMap.class.getName()) - .jsonPath("cacheManagers.two.c.target") + .jsonPath("cacheManagers.two.caches.c.target") .isEqualTo(ConcurrentHashMap.class.getName()); } From 5e87a3d2fa31c939e0f593f12329d628f89b347b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 11 May 2018 10:03:03 +0200 Subject: [PATCH 037/701] Polish See gh-13130 --- .../elasticsearch/rest/RestClientAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index 3c17aaa61f7f..ea68b2624dfe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-Configuration} for Elasticseach REST clients. + * {@link EnableAutoConfiguration Auto-Configuration} for Elasticsearch REST clients. * * @author Brian Clozel * @since 2.1.0 From 360f4e17c2a8baad0ba150009e15efb9f10cd255 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 11 May 2018 10:37:17 +0200 Subject: [PATCH 038/701] Add support for PageableHandlerMethodArgumentResolver in WebMvcTest Closes gh-13066 --- .../main/resources/META-INF/spring.factories | 1 + .../servlet/mockmvc/ExampleController2.java | 9 +++- .../WebMvcTestPageableIntegrationTests.java | 50 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index 783c0b603975..c0067289065d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -120,6 +120,7 @@ org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAut # AutoConfigureWebMvc auto-configuration imports org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc=\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\ org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\ org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\ org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController2.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController2.java index 68a5032cd1ba..61811296b91c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController2.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController2.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,6 +17,7 @@ package org.springframework.boot.test.autoconfigure.web.servlet.mockmvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -42,4 +43,10 @@ public String two(@PathVariable ExampleId id) { return id.getId() + "two"; } + @GetMapping("/paged") + @ResponseBody + public String paged(Pageable pageable) { + return String.format("%s:%s", pageable.getPageNumber(), pageable.getPageSize()); + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java new file mode 100644 index 000000000000..e1950a0ff6cc --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.web.servlet.mockmvc; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Integration tests for {@link WebMvcTest} and Pageable support. + * + * @author Stephane Nicoll + */ +@RunWith(SpringRunner.class) +@WebMvcTest(secure = false) +public class WebMvcTestPageableIntegrationTests { + + @Autowired + private MockMvc mvc; + + @Test + public void shouldSupportPageable() throws Exception { + this.mvc.perform(get("/paged").param("page", "2").param("size", "42")) + .andExpect(status().isOk()) + .andExpect(content().string("2:42")); + } + +} From d5e4a194461375b7bcd7432c29bdfea527a9d6a9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 11 May 2018 12:37:54 +0100 Subject: [PATCH 039/701] Upgrade to Liquibase 3.6.1 and adapt to logging changes Closes gh-13145 --- .../spring-boot-dependencies/pom.xml | 2 +- .../CommonsLoggingLiquibaseLogger.java | 138 ---------------- ...baseServiceLocatorApplicationListener.java | 3 - .../CommonsLoggingLiquibaseLoggerTests.java | 155 ------------------ 4 files changed, 1 insertion(+), 297 deletions(-) delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLogger.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLoggerTests.java diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index ee80b3d2d841..4c8287119357 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -116,7 +116,7 @@ 1.1.0 1.2.41 5.0.4.RELEASE - 3.5.5 + 3.6.1 2.10.0 1.2.3 1.16.20 diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLogger.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLogger.java deleted file mode 100644 index 105c250173cf..000000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLogger.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2012-2017 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.liquibase; - -import liquibase.logging.LogLevel; -import liquibase.logging.Logger; -import liquibase.logging.core.AbstractLogger; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Liquibase {@link Logger} that delegates to an Apache Commons {@link Log}. - * - * @author Michael Cramer - * @author Phillip Webb - * @author Andy Wilkinson - * @since 1.2.0 - */ -public class CommonsLoggingLiquibaseLogger extends AbstractLogger { - - /** - * The priority for the {@link CommonsLoggingLiquibaseLogger}. - */ - public static final int PRIORITY = 10; - - private Log logger; - - @Override - public void setName(String name) { - this.logger = createLogger(name); - } - - /** - * Factory method used to create the logger. - * @param name the name of the logger - * @return a {@link Log} instance - */ - protected Log createLogger(String name) { - return LogFactory.getLog(name); - } - - @Override - public void setLogLevel(String logLevel, String logFile) { - super.setLogLevel(logLevel); - } - - @Override - public void severe(String message) { - if (isEnabled(LogLevel.SEVERE)) { - this.logger.error(buildMessage(message)); - } - } - - @Override - public void severe(String message, Throwable e) { - if (isEnabled(LogLevel.SEVERE)) { - this.logger.error(buildMessage(message), e); - } - } - - @Override - public void warning(String message) { - if (isEnabled(LogLevel.WARNING)) { - this.logger.warn(buildMessage(message)); - } - } - - @Override - public void warning(String message, Throwable e) { - if (isEnabled(LogLevel.WARNING)) { - this.logger.warn(buildMessage(message), e); - } - } - - @Override - public void info(String message) { - if (isEnabled(LogLevel.INFO)) { - this.logger.info(buildMessage(message)); - } - } - - @Override - public void info(String message, Throwable e) { - if (isEnabled(LogLevel.INFO)) { - this.logger.info(buildMessage(message), e); - } - } - - @Override - public void debug(String message) { - if (isEnabled(LogLevel.DEBUG)) { - this.logger.debug(buildMessage(message)); - } - } - - @Override - public void debug(String message, Throwable e) { - if (isEnabled(LogLevel.DEBUG)) { - this.logger.debug(buildMessage(message), e); - } - } - - @Override - public int getPriority() { - return PRIORITY; - } - - private boolean isEnabled(LogLevel level) { - if (this.logger != null) { - switch (level) { - case DEBUG: - return this.logger.isDebugEnabled(); - case INFO: - return this.logger.isInfoEnabled(); - case WARNING: - return this.logger.isWarnEnabled(); - case SEVERE: - return this.logger.isErrorEnabled(); - } - } - return false; - } - -} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java index c0cd49d08d9a..ce479336a9f2 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java @@ -54,10 +54,7 @@ private static class LiquibasePresent { public void replaceServiceLocator() { CustomResolverServiceLocator customResolverServiceLocator = new CustomResolverServiceLocator( new SpringPackageScanClassResolver(logger)); - customResolverServiceLocator.addPackageToScan( - CommonsLoggingLiquibaseLogger.class.getPackage().getName()); ServiceLocator.setInstance(customResolverServiceLocator); - liquibase.logging.LogFactory.reset(); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLoggerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLoggerTests.java deleted file mode 100644 index a52b173b0834..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/liquibase/CommonsLoggingLiquibaseLoggerTests.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2012-2017 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.liquibase; - -import liquibase.logging.LogLevel; -import org.apache.commons.logging.Log; -import org.junit.Before; -import org.junit.Test; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -/** - * Tests for {@link CommonsLoggingLiquibaseLogger}. - * - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class CommonsLoggingLiquibaseLoggerTests { - - private Log delegate = mock(Log.class); - - private CommonsLoggingLiquibaseLogger logger; - - private Throwable ex = new Exception(); - - @Before - public void setup() { - this.logger = new MockCommonsLoggingLiquibaseLogger(); - this.logger.setName("mylog"); - } - - @Test - public void debug() { - this.logger.setLogLevel(LogLevel.DEBUG); - given(this.delegate.isDebugEnabled()).willReturn(true); - this.logger.debug("debug"); - verify(this.delegate).debug("debug"); - } - - @Test - public void debugWithException() { - this.logger.setLogLevel(LogLevel.DEBUG); - given(this.delegate.isDebugEnabled()).willReturn(true); - this.logger.debug("debug", this.ex); - verify(this.delegate).debug("debug", this.ex); - } - - @Test - public void debugWithLoggerOff() { - this.logger.setLogLevel(LogLevel.DEBUG); - given(this.delegate.isDebugEnabled()).willReturn(false); - this.logger.debug("debug"); - verify(this.delegate, never()).debug("debug"); - } - - @Test - public void info() { - this.logger.setLogLevel(LogLevel.INFO); - given(this.delegate.isInfoEnabled()).willReturn(true); - this.logger.info("info"); - verify(this.delegate).info("info"); - } - - @Test - public void infoWithException() { - this.logger.setLogLevel(LogLevel.INFO); - given(this.delegate.isInfoEnabled()).willReturn(true); - this.logger.info("info", this.ex); - verify(this.delegate).info("info", this.ex); - } - - @Test - public void infoWithLoggerOff() { - this.logger.setLogLevel(LogLevel.INFO); - given(this.delegate.isInfoEnabled()).willReturn(false); - this.logger.info("info"); - verify(this.delegate, never()).info("info"); - } - - @Test - public void warning() { - this.logger.setLogLevel(LogLevel.WARNING); - given(this.delegate.isWarnEnabled()).willReturn(true); - this.logger.warning("warning"); - verify(this.delegate).warn("warning"); - } - - @Test - public void warningWithException() { - this.logger.setLogLevel(LogLevel.WARNING); - given(this.delegate.isWarnEnabled()).willReturn(true); - this.logger.warning("warning", this.ex); - verify(this.delegate).warn("warning", this.ex); - } - - @Test - public void warningWithLoggerOff() { - this.logger.setLogLevel(LogLevel.WARNING); - given(this.delegate.isWarnEnabled()).willReturn(false); - this.logger.warning("warning"); - verify(this.delegate, never()).warn("warning"); - } - - @Test - public void severe() { - this.logger.setLogLevel(LogLevel.SEVERE); - given(this.delegate.isErrorEnabled()).willReturn(true); - this.logger.severe("severe"); - verify(this.delegate).error("severe"); - } - - @Test - public void severeWithException() { - this.logger.setLogLevel(LogLevel.SEVERE); - given(this.delegate.isErrorEnabled()).willReturn(true); - this.logger.severe("severe", this.ex); - verify(this.delegate).error("severe", this.ex); - } - - @Test - public void severeWithLoggerOff() { - this.logger.setLogLevel(LogLevel.SEVERE); - given(this.delegate.isErrorEnabled()).willReturn(false); - this.logger.severe("severe"); - verify(this.delegate, never()).error("severe"); - } - - private class MockCommonsLoggingLiquibaseLogger - extends CommonsLoggingLiquibaseLogger { - - @Override - protected Log createLogger(String name) { - return CommonsLoggingLiquibaseLoggerTests.this.delegate; - } - - } - -} From bb2864ad02b8f7f2b1a6ae1b7ba6e9e6ea03c807 Mon Sep 17 00:00:00 2001 From: "Michael J. Simons" Date: Wed, 7 Feb 2018 14:51:46 +0100 Subject: [PATCH 040/701] Auto-configure a ResourceConfig for Jersey endpoints if needed See gh-11948 --- ...ndpointManagementContextConfiguration.java | 9 ++- ...ntManagementContextConfigurationTests.java | 77 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java index 29b120a74c0a..33e99b3109bf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfiguration.java @@ -49,14 +49,21 @@ * * @author Andy Wilkinson * @author Phillip Webb + * @author Michael Simons */ @Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(ResourceConfig.class) -@ConditionalOnBean({ ResourceConfig.class, WebEndpointsSupplier.class }) +@ConditionalOnBean(WebEndpointsSupplier.class) @ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet") class JerseyWebEndpointManagementContextConfiguration { + @ConditionalOnMissingBean(ResourceConfig.class) + @Bean + public ResourceConfig resourceConfig() { + return new ResourceConfig(); + } + @Bean public ResourceConfigCustomizer webEndpointRegistrar( WebEndpointsSupplier webEndpointsSupplier, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java new file mode 100644 index 000000000000..2724259891f1 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2018 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.autoconfigure.endpoint.web.jersey; + +import java.util.Collections; + +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Michael Simons + */ +public class JerseyWebEndpointManagementContextConfigurationTests { + + private final WebApplicationContextRunner runner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(WebEndpointAutoConfiguration.class, JerseyWebEndpointManagementContextConfiguration.class)); + + @Test + public void contextShouldContainSingleResourceConfig() { + this.runner + .withUserConfiguration(WebEndpointsSupplierConfig.class) + .run(context -> assertThat(context).hasSingleBean(ResourceConfig.class)); + } + + @Test + public void contextWhenResourceConfigExistsShouldContainSingleResourceConfig() { + this.runner + .withUserConfiguration( + WebEndpointsSupplierConfig.class, + ConfigWithResourceConfig.class) + .run(context -> { + assertThat(context).hasSingleBean(ResourceConfig.class); + assertThat(context).hasBean("customResourceConfig"); + }); + } + + @Configuration + static class WebEndpointsSupplierConfig { + + @Bean + public WebEndpointsSupplier webEndpointsSupplier() { + return () -> Collections.emptyList(); + } + } + + @Configuration + static class ConfigWithResourceConfig { + + @Bean + public ResourceConfig customResourceConfig() { + return new ResourceConfig(); + } + } +} From a325b13d05d3d7c19fea064de802fdbe95df8b99 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 11 May 2018 12:48:16 +0100 Subject: [PATCH 041/701] Polish "Auto-configure a ResourceConfig for Jersey endpoints if needed" Closes gh-11948 --- ...ntManagementContextConfigurationTests.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java index 2724259891f1..17e2fbecb897 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/jersey/JerseyWebEndpointManagementContextConfigurationTests.java @@ -31,30 +31,29 @@ import static org.assertj.core.api.Assertions.assertThat; /** + * Tests for {@link JerseyWebEndpointManagementContextConfiguration}. + * * @author Michael Simons */ public class JerseyWebEndpointManagementContextConfigurationTests { private final WebApplicationContextRunner runner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(WebEndpointAutoConfiguration.class, JerseyWebEndpointManagementContextConfiguration.class)); + .withConfiguration(AutoConfigurations.of(WebEndpointAutoConfiguration.class, + JerseyWebEndpointManagementContextConfiguration.class)); @Test - public void contextShouldContainSingleResourceConfig() { - this.runner - .withUserConfiguration(WebEndpointsSupplierConfig.class) - .run(context -> assertThat(context).hasSingleBean(ResourceConfig.class)); + public void resourceConfigIsAutoConfiguredWhenNeeded() { + this.runner.withUserConfiguration(WebEndpointsSupplierConfig.class).run( + (context) -> assertThat(context).hasSingleBean(ResourceConfig.class)); } @Test - public void contextWhenResourceConfigExistsShouldContainSingleResourceConfig() { - this.runner - .withUserConfiguration( - WebEndpointsSupplierConfig.class, - ConfigWithResourceConfig.class) - .run(context -> { - assertThat(context).hasSingleBean(ResourceConfig.class); - assertThat(context).hasBean("customResourceConfig"); - }); + public void existingResourceConfigIsUsedWhenAvailable() { + this.runner.withUserConfiguration(WebEndpointsSupplierConfig.class, + ConfigWithResourceConfig.class).run((context) -> { + assertThat(context).hasSingleBean(ResourceConfig.class); + assertThat(context).hasBean("customResourceConfig"); + }); } @Configuration @@ -64,6 +63,7 @@ static class WebEndpointsSupplierConfig { public WebEndpointsSupplier webEndpointsSupplier() { return () -> Collections.emptyList(); } + } @Configuration @@ -73,5 +73,7 @@ static class ConfigWithResourceConfig { public ResourceConfig customResourceConfig() { return new ResourceConfig(); } + } + } From b88a20fabb666a97311d64d15a89342b41f6b84c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 11 May 2018 13:05:17 +0100 Subject: [PATCH 042/701] Polish --- .../liquibase/LiquibaseAutoConfigurationTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index a651f070ddf9..1e50fc083b84 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -25,6 +25,7 @@ import com.zaxxer.hikari.HikariDataSource; import liquibase.integration.spring.SpringLiquibase; +import liquibase.logging.core.Slf4jLogger; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -36,7 +37,6 @@ import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.liquibase.CommonsLoggingLiquibaseLogger; import org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -195,7 +195,7 @@ public void logging() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) .run(assertLiquibase((liquibase) -> { Object log = ReflectionTestUtils.getField(liquibase, "log"); - assertThat(log).isInstanceOf(CommonsLoggingLiquibaseLogger.class); + assertThat(log).isInstanceOf(Slf4jLogger.class); assertThat(this.outputCapture.toString()) .doesNotContain(": liquibase:"); })); From f81f50c11977407eef3cbe06d5e2ddb554e73474 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Thu, 10 May 2018 15:37:26 +0200 Subject: [PATCH 043/701] Improve LDAP auto-configuration Auto-configuration of LDAP's `LdapTemplate` is currently a part of `LdapDataAutoConfiguration` which is conditional of presence of `LdapRepository` (i.e. Spring Data LDAP). This arrangement isn't ideal since the `LdapTemplate` is a part of Spring LDAP project, and therefore should not be tied to Spring Data LDAP. This commit improves and simplifies LDAP auto-configuration by moving `LdapTemplate` configuration to `LdapAutoConfiguration`. Consequently, `LdapDataAutoConfiguration` is not needed anymore and is removed. See gh-13136 --- .../LdapHealthIndicatorAutoConfiguration.java | 6 +- .../data/ldap/LdapDataAutoConfiguration.java | 50 ---------------- .../ldap/LdapAutoConfiguration.java | 9 +++ .../main/resources/META-INF/spring.factories | 1 - .../ldap/LdapDataAutoConfigurationTests.java | 57 ------------------- ...dapRepositoriesAutoConfigurationTests.java | 4 +- .../ldap/LdapAutoConfigurationTests.java | 9 +++ .../EmbeddedLdapAutoConfigurationTests.java | 4 +- .../main/resources/META-INF/spring.factories | 1 - 9 files changed, 24 insertions(+), 117 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthIndicatorAutoConfiguration.java index 049b459ed82f..2a53cf98cd18 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/ldap/LdapHealthIndicatorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -29,7 +29,7 @@ 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.data.ldap.LdapDataAutoConfiguration; +import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.LdapOperations; @@ -46,7 +46,7 @@ @ConditionalOnBean(LdapOperations.class) @ConditionalOnEnabledHealthIndicator("ldap") @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) -@AutoConfigureAfter(LdapDataAutoConfiguration.class) +@AutoConfigureAfter(LdapAutoConfiguration.class) public class LdapHealthIndicatorAutoConfiguration extends CompositeHealthIndicatorConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java deleted file mode 100644 index 9957ef26032d..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfiguration.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2012-2017 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.autoconfigure.data.ldap; - -import javax.naming.ldap.LdapContext; - -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.ldap.repository.LdapRepository; -import org.springframework.ldap.core.ContextSource; -import org.springframework.ldap.core.LdapOperations; -import org.springframework.ldap.core.LdapTemplate; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's LDAP support. - * - * @author Eddú Meléndez - * @since 1.5.0 - */ -@Configuration -@ConditionalOnClass({ LdapContext.class, LdapRepository.class }) -@AutoConfigureAfter(LdapAutoConfiguration.class) -public class LdapDataAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(LdapOperations.class) - public LdapTemplate ldapTemplate(ContextSource contextSource) { - return new LdapTemplate(contextSource); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java index 404b030e1814..aef5bcb6c566 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java @@ -26,12 +26,15 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.LdapOperations; +import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; /** * {@link EnableAutoConfiguration Auto-configuration} for LDAP. * * @author Eddú Meléndez + * @author Vedran Pavic * @since 1.5.0 */ @Configuration @@ -62,4 +65,10 @@ public ContextSource ldapContextSource() { return source; } + @Bean + @ConditionalOnMissingBean(LdapOperations.class) + public LdapTemplate ldapTemplate(ContextSource contextSource) { + return new LdapTemplate(contextSource); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index a88022db1f2f..424c6edb5a51 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -41,7 +41,6 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfi org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ -org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java deleted file mode 100644 index 106fb7462593..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapDataAutoConfigurationTests.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-2017 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.autoconfigure.data.ldap; - -import org.junit.After; -import org.junit.Test; - -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.ldap.core.LdapTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link LdapDataAutoConfiguration} - * - * @author Eddú Meléndez - */ -public class LdapDataAutoConfigurationTests { - - private AnnotationConfigApplicationContext context; - - @After - public void close() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void templateExists() { - this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.ldap.urls:ldap://localhost:389") - .applyTo(this.context); - this.context.register(PropertyPlaceholderAutoConfiguration.class, - LdapAutoConfiguration.class, LdapDataAutoConfiguration.class); - this.context.refresh(); - assertThat(this.context.getBeanNamesForType(LdapTemplate.class)).hasSize(1); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java index 136c304ef2b0..c316bc96e30b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ldap/LdapRepositoriesAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -73,7 +73,7 @@ private void load(Class... configurationClasses) { .applyTo(this.context); this.context.register(configurationClasses); this.context.register(LdapAutoConfiguration.class, - LdapDataAutoConfiguration.class, LdapRepositoriesAutoConfiguration.class, + LdapRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java index b73414c6ab6d..c9eaf6d48c31 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -21,6 +21,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.test.util.ReflectionTestUtils; @@ -31,6 +32,7 @@ * * @author Eddú Meléndez * @author Stephane Nicoll + * @author Vedran Pavic */ public class LdapAutoConfigurationTests { @@ -96,4 +98,11 @@ public void contextSourceWithExtraCustomization() { }); } + @Test + public void templateExists() { + this.contextRunner.withPropertyValues("spring.ldap.urls:ldap://localhost:389") + .run(context -> assertThat( + context.getBeanNamesForType(LdapTemplate.class)).hasSize(1)); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java index ce2aa44cd213..3669137d514e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfigurationTests.java @@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration; import org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.util.TestPropertyValues; @@ -129,8 +128,7 @@ public void testSetLdifFile() { public void testQueryEmbeddedLdap() { this.contextRunner .withPropertyValues("spring.ldap.embedded.base-dn:dc=spring,dc=org") - .withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class, - LdapDataAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class)) .run((context) -> { assertThat(context.getBeanNamesForType(LdapTemplate.class).length) .isEqualTo(1); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index c0067289065d..26f679a72ab2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -15,7 +15,6 @@ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration # AutoConfigureDataLdap auto-configuration imports org.springframework.boot.test.autoconfigure.data.ldap.AutoConfigureDataLdap=\ -org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\ org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration From a0a0bea427e96781397bddbf5012198c23747005 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 11 May 2018 14:37:32 +0200 Subject: [PATCH 044/701] Polish "Improve LDAP auto-configuration" Closes gh-13136 --- .../boot/autoconfigure/ldap/LdapAutoConfigurationTests.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java index c9eaf6d48c31..c20bb1f947e6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -101,8 +101,7 @@ public void contextSourceWithExtraCustomization() { @Test public void templateExists() { this.contextRunner.withPropertyValues("spring.ldap.urls:ldap://localhost:389") - .run(context -> assertThat( - context.getBeanNamesForType(LdapTemplate.class)).hasSize(1)); + .run(context -> assertThat(context).hasSingleBean(LdapTemplate.class)); } } From dfceede0bc37a97a9add54c8e17cb0123880f832 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Fri, 11 May 2018 08:27:42 +0200 Subject: [PATCH 045/701] Improve LDAP auto-configuration conditions At present, auto-configuration of `LdapContextSource` is conditional on presence of a `ContextSource` bean. However, there are valid use cases which require multiple `ContextSource` bean, for instance `PooledContextSource`. With the current arrangement, the auto-configuration of `LdapContextSource` will back off if user provides a `PooledContextSource` bean, while it would still be reasonable to reuse the auto-configured `LdapContextSource`. This commit improves `LdapContextSource` factory method return value and condition to back off only if users actually provide a `LdapContextSource` bean themselves. See gh-13143 --- .../ldap/LdapAutoConfiguration.java | 2 +- .../EmbeddedLdapAutoConfiguration.java | 3 +- .../ldap/LdapAutoConfigurationTests.java | 38 ++++++++++++++++++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java index aef5bcb6c566..794414b98e79 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfiguration.java @@ -53,7 +53,7 @@ public LdapAutoConfiguration(LdapProperties properties, Environment environment) @Bean @ConditionalOnMissingBean - public ContextSource ldapContextSource() { + public LdapContextSource ldapContextSource() { LdapContextSource source = new LdapContextSource(); source.setUserDn(this.properties.getUsername()); source.setPassword(this.properties.getPassword()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java index b7b32510f009..741e377e6962 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ldap/embedded/EmbeddedLdapAutoConfiguration.java @@ -58,7 +58,6 @@ import org.springframework.core.env.PropertySource; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.support.LdapContextSource; import org.springframework.util.StringUtils; @@ -101,7 +100,7 @@ public EmbeddedLdapAutoConfiguration(EmbeddedLdapProperties embeddedProperties, @Bean @DependsOn("directoryServer") @ConditionalOnMissingBean - public ContextSource ldapContextSource() { + public LdapContextSource ldapContextSource() { LdapContextSource source = new LdapContextSource(); if (hasCredentials(this.embeddedProperties.getCredential())) { source.setUserDn(this.embeddedProperties.getCredential().getUsername()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java index c20bb1f947e6..2908d817a02b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -20,9 +20,13 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.ldap.pool2.factory.PoolConfig; +import org.springframework.ldap.pool2.factory.PooledContextSource; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -54,7 +58,8 @@ public void contextSourceWithDefaultUrl() { public void contextSourceWithSingleUrl() { this.contextRunner.withPropertyValues("spring.ldap.urls:ldap://localhost:123") .run((context) -> { - ContextSource contextSource = context.getBean(ContextSource.class); + ContextSource contextSource = context + .getBean(LdapContextSource.class); String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, "urls"); assertThat(urls).containsExactly("ldap://localhost:123"); @@ -67,7 +72,8 @@ public void contextSourceWithSeveralUrls() { .withPropertyValues( "spring.ldap.urls:ldap://localhost:123,ldap://mycompany:123") .run((context) -> { - ContextSource contextSource = context.getBean(ContextSource.class); + ContextSource contextSource = context + .getBean(LdapContextSource.class); LdapProperties ldapProperties = context.getBean(LdapProperties.class); String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, "urls"); @@ -104,4 +110,32 @@ public void templateExists() { .run(context -> assertThat(context).hasSingleBean(LdapTemplate.class)); } + @Test + public void contextSourceWithUserProvidedPooledContextSource() { + this.contextRunner.withUserConfiguration(PooledContextSourceConfig.class) + .run((context) -> { + LdapContextSource contextSource = context + .getBean(LdapContextSource.class); + String[] urls = (String[]) ReflectionTestUtils.getField(contextSource, + "urls"); + assertThat(urls).containsExactly("ldap://localhost:389"); + assertThat(contextSource.isAnonymousReadOnly()).isFalse(); + context.getBean(PooledContextSource.class); + }); + } + + @Configuration + static class PooledContextSourceConfig { + + @Bean + public PooledContextSource pooledContextSource( + LdapContextSource ldapContextSource) { + PooledContextSource pooledContextSource = new PooledContextSource( + new PoolConfig()); + pooledContextSource.setContextSource(ldapContextSource); + return pooledContextSource; + } + + } + } From 8e9a873787aeb4a87c758c892b22a8f842d4f996 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 11 May 2018 17:48:29 +0200 Subject: [PATCH 046/701] Polish "Improve LDAP auto-configuration conditions" Closes gh-13143 --- .../boot/autoconfigure/ldap/LdapAutoConfigurationTests.java | 3 ++- .../src/main/asciidoc/spring-boot-features.adoc | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java index 2908d817a02b..9e54fd144a0f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -22,6 +22,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.support.LdapContextSource; @@ -120,7 +121,6 @@ public void contextSourceWithUserProvidedPooledContextSource() { "urls"); assertThat(urls).containsExactly("ldap://localhost:389"); assertThat(contextSource.isAnonymousReadOnly()).isFalse(); - context.getBean(PooledContextSource.class); }); } @@ -128,6 +128,7 @@ public void contextSourceWithUserProvidedPooledContextSource() { static class PooledContextSourceConfig { @Bean + @Primary public PooledContextSource pooledContextSource( LdapContextSource ldapContextSource) { PooledContextSource pooledContextSource = new PooledContextSource( diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index c464502ca25b..7568434c1b13 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4539,6 +4539,11 @@ URLs of your server in your application.properties, as shown in the following ex If you need to customize connection settings, you can use the `spring.ldap.base` and `spring.ldap.base-environment` properties. +A `LdapContextSource` is auto-configured based on these settings. If you need to customize +it, for instance to use a `PooledContextSource`, you can still inject the auto-configured +`LdapContextSource`. Make sure to flag your customized `ContextSource` as `@Primary` so +that the auto-configured `LdapTemplate` uses it. + [[boot-features-ldap-spring-data-repositories]] From fb2ab67f4f6acbc2384c91122e511c99e86a10cc Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sat, 12 May 2018 01:00:40 +0900 Subject: [PATCH 047/701] Polish Closes gh-13148 --- .../boot/maven/AbstractRunMojo.java | 44 ++++++++++--------- .../apt/examples/run-env-variables.apt.vm | 2 +- .../apt/examples/run-system-properties.apt.vm | 4 +- .../maven/SystemPropertyFormatterTests.java | 2 +- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 2bc4280bc8f7..0c4d1f9d1cac 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -256,17 +256,19 @@ private void run(String startClassName) * @see #enableForkByDefault() */ protected void logDisabledFork() { - if (hasAgent()) { - getLog().warn("Fork mode disabled, ignoring agent"); - } - if (hasJvmArgs()) { - RunArguments runArguments = resolveJvmArguments(); - getLog().warn("Fork mode disabled, ignoring JVM argument(s) [" + Arrays - .stream(runArguments.asArray()).collect(Collectors.joining(" ")) - + "]"); - } - if (hasWorkingDirectorySet()) { - getLog().warn("Fork mode disabled, ignoring working directory configuration"); + if (getLog().isWarnEnabled()) { + if (hasAgent()) { + getLog().warn("Fork mode disabled, ignoring agent"); + } + if (hasJvmArgs()) { + RunArguments runArguments = resolveJvmArguments(); + getLog().warn("Fork mode disabled, ignoring JVM argument(s) [" + Arrays + .stream(runArguments.asArray()).collect(Collectors.joining(" ")) + + "]"); + } + if (hasWorkingDirectorySet()) { + getLog().warn("Fork mode disabled, ignoring working directory configuration"); + } } } @@ -338,7 +340,7 @@ private Map determineEnvironmentVariables() { * @return a {@link RunArguments} defining the JVM arguments */ protected RunArguments resolveJvmArguments() { - final StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); if (this.systemPropertyVariables != null) { stringBuilder.append(this.systemPropertyVariables.entrySet().stream() .map((e) -> SystemPropertyFormatter.format(e.getKey(), e.getValue())) @@ -358,7 +360,9 @@ private void addJvmArgs(List args) { private void addAgents(List args) { if (this.agent != null) { - getLog().info("Attaching agents: " + Arrays.asList(this.agent)); + if (getLog().isInfoEnabled()) { + getLog().info("Attaching agents: " + Arrays.asList(this.agent)); + } for (File agent : this.agent) { args.add("-javaagent:" + agent); } @@ -390,7 +394,9 @@ private void addClasspath(List args) throws MojoExecutionException { .append((classpath.length() > 0 ? File.pathSeparator : "") + new File(ele.toURI())); } - getLog().debug("Classpath for forked process: " + classpath); + if (getLog().isDebugEnabled()) { + getLog().debug("Classpath for forked process: " + classpath); + } args.add("-cp"); args.add(classpath.toString()); } @@ -468,11 +474,9 @@ private void addDependencies(List urls) } private void logArguments(String message, String[] args) { - StringBuilder sb = new StringBuilder(message); - for (String arg : args) { - sb.append(arg).append(" "); + if (getLog().isDebugEnabled()) { + getLog().debug(Arrays.stream(args).collect(Collectors.joining(" ", message, ""))); } - getLog().debug(sb.toString().trim()); } private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { @@ -569,11 +573,11 @@ public void run() { */ static class SystemPropertyFormatter { - public static String format(Object key, Object value) { + public static String format(String key, String value) { if (key == null) { return ""; } - if (value == null || String.valueOf(value).isEmpty()) { + if (value == null || value.isEmpty()) { return String.format("-D%s", key); } return String.format("-D%s=\"%s\"", key, value); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm index 0fc0f6934b4b..7a3b7e560aa5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-env-variables.apt.vm @@ -40,7 +40,7 @@ Dmytro Nosan If the value is empty or not defined (i.e. <<<>>>), the env variable is set with an empty String as the value. Maven trims values specified in the pom so it is - not possible to specify a env variable who needs to start or end with a space. + not possible to specify an env variable which needs to start or end with a space. Any String typed Maven variable can be passed as system properties. Any attempt to pass any other Maven variable type (e.g. a <<>> or a <<>> variable) will cause the diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm index 493edf8c6478..1b3cb3aa1fd4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/run-system-properties.apt.vm @@ -27,7 +27,7 @@ test ${my.value} - + ... @@ -41,7 +41,7 @@ If the value is empty or not defined (i.e. <<<>>>), the system property is set with an empty String as the value. Maven trims values specified in the pom so it - is not possible to specify a System property who needs to start or end with a space via + is not possible to specify a System property which needs to start or end with a space via this mechanism: consider using <<>> instead. Any String typed Maven variable can be passed as system properties. Any attempt to pass diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java index 8a18a8a93fd5..0919e219a74c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java @@ -49,7 +49,7 @@ public void parseKeyWithEmptyValue() { } @Test - public void parseKeyWithOnlySpace() { + public void parseKeyWithOnlySpaces() { assertThat(SystemPropertyFormatter.format("key1", " ")) .isEqualTo("-Dkey1=\" \""); } From 406192741eba6050ff774661e939c152f9c340d2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 11:19:46 +0200 Subject: [PATCH 048/701] Upgrade to Maven Exec Plugin 1.6.0 Closes gh-13101 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 45eb4ece6ada..002a287928b8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -183,7 +183,7 @@ 2.5.1 3.0.0 - 1.5.0 + 1.6.0 2.2.3 1.8 3.1.0 From 93c45cb6ece0bb0aead2ba9d383480cccc6b8b45 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 12:24:38 +0200 Subject: [PATCH 049/701] Move server.servlet.path to spring.mvc.servlet.path Closes gh-12971 --- .../servlet/StaticResourceRequest.java | 14 ++-- .../autoconfigure/web/ServerProperties.java | 67 ------------------- .../DispatcherServletAutoConfiguration.java | 17 ++--- .../web/servlet/WebMvcProperties.java | 48 +++++++++++++ .../error/ErrorMvcAutoConfiguration.java | 24 +++++-- ...itional-spring-configuration-metadata.json | 12 +++- .../servlet/StaticResourceRequestTests.java | 16 ++--- .../web/ServerPropertiesTests.java | 14 ---- ...spatcherServletAutoConfigurationTests.java | 2 +- .../web/servlet/WebMvcPropertiesTests.java | 63 +++++++++++++++++ .../RemappedErrorViewIntegrationTests.java | 4 +- .../appendix-application-properties.adoc | 2 +- .../appendix-configuration-metadata.adoc | 17 +++-- ...letPathSampleActuatorApplicationTests.java | 2 +- .../src/main/resources/application.properties | 2 +- 15 files changed, 172 insertions(+), 132 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcPropertiesTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java index 7e3d3d3f2d67..c51e6b51b6cb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java @@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.boot.autoconfigure.security.StaticResourceLocation; -import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties; import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; @@ -96,14 +96,14 @@ public StaticResourceRequestMatcher at(Set locations) { * Locations}. */ public static final class StaticResourceRequestMatcher - extends ApplicationContextRequestMatcher { + extends ApplicationContextRequestMatcher { private final Set locations; private volatile RequestMatcher delegate; private StaticResourceRequestMatcher(Set locations) { - super(ServerProperties.class); + super(WebMvcProperties.class); this.locations = locations; } @@ -134,25 +134,25 @@ public StaticResourceRequestMatcher excluding( } @Override - protected void initialized(Supplier serverProperties) { + protected void initialized(Supplier serverProperties) { this.delegate = new OrRequestMatcher( getDelegateMatchers(serverProperties.get())); } private List getDelegateMatchers( - ServerProperties serverProperties) { + WebMvcProperties serverProperties) { return getPatterns(serverProperties).map(AntPathRequestMatcher::new) .collect(Collectors.toList()); } - private Stream getPatterns(ServerProperties serverProperties) { + private Stream getPatterns(WebMvcProperties serverProperties) { return this.locations.stream().flatMap(StaticResourceLocation::getPatterns) .map(serverProperties.getServlet()::getPath); } @Override protected boolean matches(HttpServletRequest request, - Supplier context) { + Supplier context) { return this.delegate.matches(request); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 2ef354cfa6ef..1ec029bcd6e5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -22,7 +22,6 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -37,7 +36,6 @@ import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.servlet.server.Jsp; import org.springframework.boot.web.servlet.server.Session; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -214,11 +212,6 @@ public static class Servlet { */ private String applicationDisplayName = "application"; - /** - * Path of the main dispatcher servlet. - */ - private String path = "/"; - @NestedConfigurationProperty private final Jsp jsp = new Jsp(); @@ -248,15 +241,6 @@ public void setApplicationDisplayName(String displayName) { this.applicationDisplayName = displayName; } - public String getPath() { - return this.path; - } - - public void setPath(String path) { - Assert.notNull(path, "Path must not be null"); - this.path = path; - } - public Map getContextParameters() { return this.contextParameters; } @@ -269,57 +253,6 @@ public Session getSession() { return this.session; } - public String getServletMapping() { - if (this.path.equals("") || this.path.equals("/")) { - return "/"; - } - if (this.path.contains("*")) { - return this.path; - } - if (this.path.endsWith("/")) { - return this.path + "*"; - } - return this.path + "/*"; - } - - public String getPath(String path) { - String prefix = getServletPrefix(); - if (!path.startsWith("/")) { - path = "/" + path; - } - return prefix + path; - } - - public String getServletPrefix() { - String result = this.path; - int index = result.indexOf('*'); - if (index != -1) { - result = result.substring(0, index); - } - if (result.endsWith("/")) { - result = result.substring(0, result.length() - 1); - } - return result; - } - - public String[] getPathsArray(Collection paths) { - String[] result = new String[paths.size()]; - int i = 0; - for (String path : paths) { - result[i++] = getPath(path); - } - return result; - } - - public String[] getPathsArray(String[] paths) { - String[] result = new String[paths.length]; - int i = 0; - for (String path : paths) { - result[i++] = getPath(path); - } - return result; - } - } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java index 61e0a1a4e595..933adcce045d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java @@ -36,7 +36,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @@ -67,7 +66,6 @@ @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) -@EnableConfigurationProperties(ServerProperties.class) public class DispatcherServletAutoConfiguration { /* @@ -88,12 +86,8 @@ protected static class DispatcherServletConfiguration { private final WebMvcProperties webMvcProperties; - private final ServerProperties serverProperties; - - public DispatcherServletConfiguration(WebMvcProperties webMvcProperties, - ServerProperties serverProperties) { + public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) { this.webMvcProperties = webMvcProperties; - this.serverProperties = serverProperties; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) @@ -118,7 +112,7 @@ public MultipartResolver multipartResolver(MultipartResolver resolver) { @Bean public DispatcherServletPathProvider mainDispatcherServletPathProvider() { - return () -> DispatcherServletConfiguration.this.serverProperties.getServlet() + return () -> DispatcherServletConfiguration.this.webMvcProperties.getServlet() .getPath(); } @@ -131,16 +125,13 @@ public DispatcherServletPathProvider mainDispatcherServletPathProvider() { @Import(DispatcherServletConfiguration.class) protected static class DispatcherServletRegistrationConfiguration { - private final ServerProperties serverProperties; - private final WebMvcProperties webMvcProperties; private final MultipartConfigElement multipartConfig; public DispatcherServletRegistrationConfiguration( - ServerProperties serverProperties, WebMvcProperties webMvcProperties, + WebMvcProperties webMvcProperties, ObjectProvider multipartConfigProvider) { - this.serverProperties = serverProperties; this.webMvcProperties = webMvcProperties; this.multipartConfig = multipartConfigProvider.getIfAvailable(); } @@ -151,7 +142,7 @@ public ServletRegistrationBean dispatcherServletRegistration( DispatcherServlet dispatcherServlet) { ServletRegistrationBean registration = new ServletRegistrationBean<>( dispatcherServlet, - this.serverProperties.getServlet().getServletMapping()); + this.webMvcProperties.getServlet().getServletMapping()); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); registration.setLoadOnStartup( this.webMvcProperties.getServlet().getLoadOnStartup()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java index d3bdbca7197d..e32a430a5783 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java @@ -23,6 +23,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.MediaType; +import org.springframework.util.Assert; import org.springframework.validation.DefaultMessageCodesResolver; /** @@ -225,11 +226,25 @@ public void setRequestTimeout(Duration requestTimeout) { public static class Servlet { + /** + * Path of the dispatcher servlet. + */ + private String path = "/"; + /** * Load on startup priority of the dispatcher servlet. */ private int loadOnStartup = -1; + public String getPath() { + return this.path; + } + + public void setPath(String path) { + Assert.notNull(path, "Path must not be null"); + this.path = path; + } + public int getLoadOnStartup() { return this.loadOnStartup; } @@ -238,6 +253,39 @@ public void setLoadOnStartup(int loadOnStartup) { this.loadOnStartup = loadOnStartup; } + public String getServletMapping() { + if (this.path.equals("") || this.path.equals("/")) { + return "/"; + } + if (this.path.contains("*")) { + return this.path; + } + if (this.path.endsWith("/")) { + return this.path + "*"; + } + return this.path + "/*"; + } + + public String getPath(String path) { + String prefix = getServletPrefix(); + if (!path.startsWith("/")) { + path = "/" + path; + } + return prefix + path; + } + + public String getServletPrefix() { + String result = this.path; + int index = result.indexOf('*'); + if (index != -1) { + result = result.substring(0, index); + } + if (result.endsWith("/")) { + result = result.substring(0, result.length() - 1); + } + return result; + } + } public static class View { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java index 25c81e2e9f1e..6e53ce3f51d9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java @@ -50,6 +50,7 @@ import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.server.ErrorPage; import org.springframework.boot.web.server.ErrorPageRegistrar; @@ -89,16 +90,21 @@ @ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) // Load before the main WebMvcAutoConfiguration so that the error View is available @AutoConfigureBefore(WebMvcAutoConfiguration.class) -@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class }) +@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, + WebMvcProperties.class }) public class ErrorMvcAutoConfiguration { private final ServerProperties serverProperties; + private final WebMvcProperties webMvcProperties; + private final List errorViewResolvers; public ErrorMvcAutoConfiguration(ServerProperties serverProperties, + WebMvcProperties webMvcProperties, ObjectProvider> errorViewResolversProvider) { this.serverProperties = serverProperties; + this.webMvcProperties = webMvcProperties; this.errorViewResolvers = errorViewResolversProvider.getIfAvailable(); } @@ -118,7 +124,7 @@ public BasicErrorController basicErrorController(ErrorAttributes errorAttributes @Bean public ErrorPageCustomizer errorPageCustomizer() { - return new ErrorPageCustomizer(this.serverProperties); + return new ErrorPageCustomizer(this.serverProperties, this.webMvcProperties); } @Bean @@ -325,17 +331,21 @@ private String escape(Object value) { */ private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered { - private final ServerProperties properties; + private final ServerProperties serverProperties; + + private final WebMvcProperties webMvcProperties; - protected ErrorPageCustomizer(ServerProperties properties) { - this.properties = properties; + protected ErrorPageCustomizer(ServerProperties serverProperties, + WebMvcProperties webMvcProperties) { + this.serverProperties = serverProperties; + this.webMvcProperties = webMvcProperties; } @Override public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { ErrorPage errorPage = new ErrorPage( - this.properties.getServlet().getServletPrefix() - + this.properties.getError().getPath()); + this.webMvcProperties.getServlet().getServletPrefix() + + this.serverProperties.getError().getPath()); errorPageRegistry.addErrorPages(errorPage); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index fca0a274d9e1..f385ef55b267 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1069,7 +1069,17 @@ "description": "Path of the main dispatcher servlet.", "defaultValue": "/", "deprecation": { - "replacement": "server.servlet.path", + "replacement": "spring.mvc.servlet.path", + "level": "error" + } + }, + { + "name": "server.servlet.path", + "type": "java.lang.String", + "description": "Path of the main dispatcher servlet.", + "defaultValue": "/", + "deprecation": { + "replacement": "spring.mvc.servlet.path", "level": "error" } }, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java index 01ef099e3173..ee842dc7746a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java @@ -24,7 +24,7 @@ import org.junit.rules.ExpectedException; import org.springframework.boot.autoconfigure.security.StaticResourceLocation; -import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockServletContext; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -74,11 +74,11 @@ public void atLocationShouldMatchLocation() { @Test public void atLocationWhenHasServletPathShouldMatchLocation() { - ServerProperties serverProperties = new ServerProperties(); - serverProperties.getServlet().setPath("/foo"); + WebMvcProperties webMvcProperties = new WebMvcProperties(); + webMvcProperties.getServlet().setPath("/foo"); RequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS); - assertMatcher(matcher, serverProperties).matches("/foo", "/css/file.css"); - assertMatcher(matcher, serverProperties).doesNotMatch("/foo", "/js/file.js"); + assertMatcher(matcher, webMvcProperties).matches("/foo", "/css/file.css"); + assertMatcher(matcher, webMvcProperties).doesNotMatch("/foo", "/js/file.js"); } @Test @@ -97,14 +97,14 @@ public void excludeFromSetWhenSetIsNullShouldThrowException() { private RequestMatcherAssert assertMatcher(RequestMatcher matcher) { StaticWebApplicationContext context = new StaticWebApplicationContext(); - context.registerBean(ServerProperties.class); + context.registerBean(WebMvcProperties.class); return assertThat(new RequestMatcherAssert(context, matcher)); } private RequestMatcherAssert assertMatcher(RequestMatcher matcher, - ServerProperties serverProperties) { + WebMvcProperties webMvcProperties) { StaticWebApplicationContext context = new StaticWebApplicationContext(); - context.registerBean(ServerProperties.class, () -> serverProperties); + context.registerBean(WebMvcProperties.class, () -> webMvcProperties); return assertThat(new RequestMatcherAssert(context, matcher)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index c5ce34c9c5e9..771c3b646caa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -78,20 +78,6 @@ public void testConnectionTimeout() { .isEqualTo(Duration.ofMillis(60000)); } - @Test - public void testServletPathAsMapping() { - bind("server.servlet.path", "/foo/*"); - assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*"); - assertThat(this.properties.getServlet().getServletPrefix()).isEqualTo("/foo"); - } - - @Test - public void testServletPathAsPrefix() { - bind("server.servlet.path", "/foo"); - assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*"); - assertThat(this.properties.getServlet().getServletPrefix()).isEqualTo("/foo"); - } - @Test public void testTomcatBinding() { Map map = new HashMap<>(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java index c66f98f1996d..8ee4661a53ab 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java @@ -99,7 +99,7 @@ public void registrationOverrideWithAutowiredServlet() { @Test public void servletPath() { - this.contextRunner.withPropertyValues("server.servlet.path:/spring") + this.contextRunner.withPropertyValues("spring.mvc.servlet.path:/spring") .run((context) -> { assertThat(context.getBean(DispatcherServlet.class)).isNotNull(); ServletRegistrationBean registration = context diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcPropertiesTests.java new file mode 100644 index 000000000000..dbb637d27e10 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcPropertiesTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.servlet; + +import java.util.Collections; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebMvcProperties}. + * + * @author Stephane Nicoll + */ +public class WebMvcPropertiesTests { + + private final WebMvcProperties properties = new WebMvcProperties(); + + @Test + public void testServletPathAsMapping() { + bind("spring.mvc.servlet.path", "/foo/*"); + assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*"); + assertThat(this.properties.getServlet().getServletPrefix()).isEqualTo("/foo"); + } + + @Test + public void testServletPathAsPrefix() { + bind("spring.mvc.servlet.path", "/foo"); + assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*"); + assertThat(this.properties.getServlet().getServletPrefix()).isEqualTo("/foo"); + } + + private void bind(String name, String value) { + bind(Collections.singletonMap(name, value)); + } + + private void bind(Map map) { + ConfigurationPropertySource source = new MapConfigurationPropertySource(map); + new Binder(source).bind("spring.mvc", Bindable.ofInstance(this.properties)); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java index 16698fb64332..89b1176eb8bc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java @@ -47,7 +47,7 @@ * @author Dave Syer */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "server.servlet.path:/spring/*") +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.mvc.servlet.path:/spring/*") @DirtiesContext public class RemappedErrorViewIntegrationTests { @@ -93,7 +93,7 @@ public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { // For manual testing public static void main(String[] args) { new SpringApplicationBuilder(TestConfiguration.class) - .properties("server.servlet.path:spring/*").run(args); + .properties("spring.mvc.servlet.path:spring/*").run(args); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 2cd018f20ff5..fd4cfdb7bcc4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -196,7 +196,6 @@ content into your application. Rather, pick only the properties that you need. server.servlet.jsp.class-name=org.apache.jasper.servlet.JspServlet # The class name of the JSP servlet. server.servlet.jsp.init-parameters.*= # Init parameters used to configure the JSP servlet. server.servlet.jsp.registered=true # Whether the JSP servlet is registered. - server.servlet.path=/ # Path of the main dispatcher servlet. server.servlet.session.cookie.comment= # Comment for the session cookie. server.servlet.session.cookie.domain= # Domain for the session cookie. server.servlet.session.cookie.http-only= # "HttpOnly" flag for the session cookie. @@ -414,6 +413,7 @@ content into your application. Rather, pick only the properties that you need. spring.mvc.pathmatch.use-registered-suffix-pattern=false # Whether suffix pattern matching should work only against extensions registered with "spring.mvc.contentnegotiation.media-types.*". spring.mvc.pathmatch.use-suffix-pattern=false # Whether to use suffix pattern match (".*") when matching patterns to requests. spring.mvc.servlet.load-on-startup=-1 # Load on startup priority of the dispatcher servlet. + spring.mvc.servlet.path=/ # Path of the dispatcher servlet. spring.mvc.static-path-pattern=/** # Path pattern used for static resources. spring.mvc.throw-exception-if-no-handler-found=false # Whether a "NoHandlerFoundException" should be thrown if no Handler was found to process a request. spring.mvc.view.prefix= # Spring MVC view prefix. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-configuration-metadata.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-configuration-metadata.adoc index a1e911c06336..647660991d60 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-configuration-metadata.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-configuration-metadata.adoc @@ -42,10 +42,9 @@ categorized under "hints", as shown in the following example: "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties" }, { - "name": "server.servlet.path", - "type": "java.lang.String", - "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties", - "defaultValue": "/" + "name": "server.address", + "type": "java.net.InetAddress", + "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties" }, { "name": "spring.jpa.hibernate.ddl-auto", @@ -84,18 +83,18 @@ categorized under "hints", as shown in the following example: ---- Each "`property`" is a configuration item that the user specifies with a given value. -For example, `server.port` and `server.servlet.path` might be specified in +For example, `server.port` and `server.address` might be specified in `application.properties`, as follows: [source,properties,indent=0] ---- server.port=9090 - server.servlet.path=/home + server.address=127.0.0.1 ---- The "`groups`" are higher level items that do not themselves specify a value but instead provide a contextual grouping for properties. For example, the `server.port` and -`server.servlet.path` properties are part of the `server` group. +`server.address` properties are part of the `server` group. NOTE: It is not required that every "`property`" has a "`group`". Some properties might exist in their own right. @@ -163,7 +162,7 @@ in the following table: |`name` | String | The full name of the property. Names are in lower-case period-separated form (for - example, `server.servlet.path`). This attribute is mandatory. + example, `server.address`). This attribute is mandatory. |`type` | String @@ -287,7 +286,7 @@ following table: |`name` | String | The full name of the property to which this hint refers. Names are in lower-case - period-separated form (such as `server.servlet.path`). If the property refers to a map + period-separated form (such as `spring.mvc.servlet.path`). If the property refers to a map (such as `system.contexts`), the hint either applies to the _keys_ of the map (`system.context.keys`) or the _values_ (`system.context.values`) of the map. This attribute is mandatory. diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java index eb21250ea999..9fa9d8ba9208 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java @@ -38,7 +38,7 @@ */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { - "server.servlet.path=/spring" }) + "spring.mvc.servlet.path=/spring" }) public class ServletPathSampleActuatorApplicationTests { @Autowired diff --git a/spring-boot-samples/spring-boot-sample-atmosphere/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-atmosphere/src/main/resources/application.properties index 7f37a13da9f2..ccbc4ee91cbb 100644 --- a/spring-boot-samples/spring-boot-sample-atmosphere/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-atmosphere/src/main/resources/application.properties @@ -1 +1 @@ -server.servlet.path=/home/* +spring.mvc.servlet.path=/home/* From 602f52fffc63d71e4ab16e3da11c17e24aa4df69 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 13:26:01 +0200 Subject: [PATCH 050/701] Add support for configuring common tags declaratively Closes gh-12933 --- .../metrics/MetricsProperties.java | 9 ++++++++ .../metrics/PropertiesMeterFilter.java | 23 ++++++++++++++++++- ...ricsAutoConfigurationIntegrationTests.java | 13 +++++++++++ .../appendix-application-properties.adoc | 1 + .../asciidoc/production-ready-features.adoc | 15 ++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java index a69a2b50c91b..f24cce637477 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java @@ -44,6 +44,11 @@ public class MetricsProperties { */ private Map enable = new LinkedHashMap<>(); + /** + * Common tags that are applied to every meter. + */ + private final Map tags = new LinkedHashMap<>(); + private final Web web = new Web(); private final Distribution distribution = new Distribution(); @@ -65,6 +70,10 @@ public void setEnable(Map enable) { this.enable = enable; } + public Map getTags() { + return this.tags; + } + public Web getWeb() { return this.web; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java index 130b1f7db2bc..85b40cab78b4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java @@ -19,9 +19,12 @@ import java.util.Arrays; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.Meter.Id; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; @@ -35,17 +38,30 @@ * * @author Jon Schneider * @author Phillip Webb + * @author Stephane Nicoll * @since 2.0.0 */ public class PropertiesMeterFilter implements MeterFilter { private static final ServiceLevelAgreementBoundary[] EMPTY_SLA = {}; - private MetricsProperties properties; + private final MetricsProperties properties; + + private final MeterFilter mapFilter; public PropertiesMeterFilter(MetricsProperties properties) { Assert.notNull(properties, "Properties must not be null"); this.properties = properties; + this.mapFilter = createMapFilter(properties.getTags()); + } + + private static MeterFilter createMapFilter(Map tags) { + if (tags.isEmpty()) { + return new MeterFilter() { }; + } + Tags commonTags = Tags.of(tags.entrySet().stream().map((entry) -> + Tag.of(entry.getKey(), entry.getValue())).collect(Collectors.toList())); + return MeterFilter.commonTags(commonTags); } @Override @@ -54,6 +70,11 @@ public MeterFilterReply accept(Meter.Id id) { return (enabled ? MeterFilterReply.NEUTRAL : MeterFilterReply.DENY); } + @Override + public Id map(Id id) { + return this.mapFilter.map(id); + } + @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java index 0c9784b5d278..18999833803f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java @@ -55,6 +55,19 @@ public void propertyBasedMeterFilteringIsAutoConfigured() { }); } + @Test + public void propertyBasedCommonTagsIsAutoConfigured() { + this.contextRunner.withPropertyValues("management.metrics.tags.region=test", + "management.metrics.tags.origin=local") + .run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.counter("my.counter", "env", "qa"); + assertThat(registry.find("my.counter").tags("env", "qa") + .tags("region", "test").tags("origin", "local").counter()) + .isNotNull(); + }); + } + @Test public void simpleMeterRegistryIsUsedAsAFallback() { this.contextRunner diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index fd4cfdb7bcc4..74e200d07737 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1432,6 +1432,7 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.wavefront.step=10s # Step size (i.e. reporting frequency) to use. management.metrics.export.wavefront.uri=https://longboard.wavefront.com # URI to ship metrics to. management.metrics.use-global-registry=true # Whether auto-configured MeterRegistry implementations should be bound to the global static registry on Metrics. + management.metrics.tags.*= # Common tags that are applied to every meter. management.metrics.web.client.max-uri-tags=100 # Maximum number of unique URI tag values allowed. After the max number of tag values is reached, metrics with additional tag values are denied by filter. management.metrics.web.client.requests-metric-name=http.client.requests # Name of the metric for sent requests. management.metrics.web.server.auto-time-requests=true # Whether requests handled by Spring MVC or WebFlux should be automatically timed. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 52664dd22bd4..4639c986505e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1846,6 +1846,21 @@ all meter IDs beginning with `com.example`, you can do the following: include::{code-examples}/actuate/metrics/MetricsFilterBeanExample.java[tag=configuration] ---- +[[production-ready-metrics-common-tags]] +==== Common tags +Common tag are generally used for dimensional drill-down on the operating environment like +host, instance, region, stack, etc. Commons tags applied to all meters and can be +configured as shown in the following example: + +[source,properties,indent=0] +---- + management.metrics.tags.region=us-east-1 + management.metrics.tags.stack=prod +---- + +The example above adds a `region` and `stack` tags to all meters with a value of +`us-east-1` and `prod` respectively. + ==== Per-meter properties From c8dc885cc5d21960d4c273452a404a93a61b5ceb Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 13:30:40 +0200 Subject: [PATCH 051/701] Add missing note See gh-12933 --- .../src/main/asciidoc/production-ready-features.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 4639c986505e..b2097a5e4e6f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1861,6 +1861,10 @@ configured as shown in the following example: The example above adds a `region` and `stack` tags to all meters with a value of `us-east-1` and `prod` respectively. +NOTE: The order of common tags is important if you are using Graphite. As the order of +common tags cannot be guaranteed using this approach, Graphite users are advised to define +a custom `MeterFilter` instead. + ==== Per-meter properties From 08279c889c7aef924137b0e4892108dec37f24a0 Mon Sep 17 00:00:00 2001 From: Vladyslav Kiriushkin Date: Mon, 14 May 2018 11:54:59 +0300 Subject: [PATCH 052/701] Add liquibase test rollback on update property See gh-13159 --- .../liquibase/LiquibaseAutoConfiguration.java | 1 + .../liquibase/LiquibaseProperties.java | 14 +++++++++++++- .../liquibase/LiquibaseAutoConfigurationTests.java | 11 +++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java index 0ef3992e0b63..7130d9c7b323 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java @@ -129,6 +129,7 @@ public SpringLiquibase liquibase() { liquibase.setLabels(this.properties.getLabels()); liquibase.setChangeLogParameters(this.properties.getParameters()); liquibase.setRollbackFile(this.properties.getRollbackFile()); + liquibase.setTestRollbackOnUpdate(this.properties.isTestRollbackOnUpdate()); return liquibase; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java index 64e7d3f27bc3..a8cf90613a75 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -94,6 +94,11 @@ public class LiquibaseProperties { */ private File rollbackFile; + /** + * Whether rollback should be tested before update is performed. + */ + private boolean testRollbackOnUpdate; + public String getChangeLog() { return this.changeLog; } @@ -191,4 +196,11 @@ public void setRollbackFile(File rollbackFile) { this.rollbackFile = rollbackFile; } + public boolean isTestRollbackOnUpdate() { + return this.testRollbackOnUpdate; + } + + public void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) { + this.testRollbackOnUpdate = testRollbackOnUpdate; + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index 1e50fc083b84..ca8d840b08bd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -238,6 +238,17 @@ public void rollbackFile() throws IOException { }); } + @Test + public void testRollbackOnUpdate() throws IOException { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .withPropertyValues( + "spring.liquibase.test-rollback-on-update:true") + .run((context) -> { + SpringLiquibase liquibase = context.getBean(SpringLiquibase.class); + assertThat(liquibase.isTestRollbackOnUpdate()); + }); + } + @Test public void liquibaseDataSource() { this.contextRunner.withUserConfiguration(LiquibaseDataSourceConfiguration.class, From c7eec5c45e4f44bdd5913e67c2683b0281b9b6e5 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 14 May 2018 16:14:11 +0200 Subject: [PATCH 053/701] Polish "Add liquibase test rollback on update property" Closes gh-13159 --- .../liquibase/LiquibaseProperties.java | 1 + .../LiquibaseAutoConfigurationTests.java | 23 ++++++++++--------- .../appendix-application-properties.adoc | 1 + 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java index a8cf90613a75..62f906c16518 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java @@ -203,4 +203,5 @@ public boolean isTestRollbackOnUpdate() { public void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) { this.testRollbackOnUpdate = testRollbackOnUpdate; } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index ca8d840b08bd..3e9b2490ea0f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -178,6 +178,18 @@ public void overrideUser() { })); } + @Test + public void overrideTestRollbackOnUpdate() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .withPropertyValues( + "spring.liquibase.test-rollback-on-update:true") + .run((context) -> { + SpringLiquibase liquibase = context.getBean(SpringLiquibase.class); + assertThat(liquibase.isTestRollbackOnUpdate()).isTrue(); + }); + } + + @Test public void changeLogDoesNotExist() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) @@ -238,17 +250,6 @@ public void rollbackFile() throws IOException { }); } - @Test - public void testRollbackOnUpdate() throws IOException { - this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) - .withPropertyValues( - "spring.liquibase.test-rollback-on-update:true") - .run((context) -> { - SpringLiquibase liquibase = context.getBean(SpringLiquibase.class); - assertThat(liquibase.isTestRollbackOnUpdate()); - }); - } - @Test public void liquibaseDataSource() { this.contextRunner.withUserConfiguration(LiquibaseDataSourceConfiguration.class, diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 74e200d07737..c3f9721799aa 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -567,6 +567,7 @@ content into your application. Rather, pick only the properties that you need. spring.liquibase.parameters.*= # Change log parameters. spring.liquibase.password= # Login password of the database to migrate. spring.liquibase.rollback-file= # File to which rollback SQL is written when an update is performed. + spring.liquibase.test-rollback-on-update=false # Whether rollback should be tested before update is performed. spring.liquibase.url= # JDBC URL of the database to migrate. If not set, the primary configured data source is used. spring.liquibase.user= # Login user of the database to migrate. From ab7f6654d80e130275231271ca4582d60cf99988 Mon Sep 17 00:00:00 2001 From: Frank Pavageau Date: Tue, 17 Apr 2018 23:43:38 +0200 Subject: [PATCH 054/701] Manage the Mockito/JUnit 5 dependency This requires an updated Mockito dependency as well, since it was introduced in Mockito 2.17.0 but really works starting with 2.18.0. Closes gh-12890 --- spring-boot-project/spring-boot-dependencies/pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e2bde6b2dcf1..046240509c27 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -123,7 +123,7 @@ 1.16.20 2.2.3 1.0.4 - 2.15.0 + 2.18.3 1.7.1 3.6.3 6.2.2.jre8 @@ -2303,6 +2303,11 @@ mockito-inline ${mockito.version} + + org.mockito + mockito-junit-jupiter + ${mockito.version} + org.mongodb bson From 3c8e012411ecc453f9dc4e035b92c39c89885896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn?= Date: Thu, 10 Aug 2017 14:37:51 +0200 Subject: [PATCH 055/701] Allow repackage maven goal to take a source classifier Previously, the "classifier" attribute was only used to determine the target classifier of the repackaged archive, always using the main artifact as the source. This commit changes the semantic of the attribute so that an existing archive matching the "classifier" attribute can be used as source, replacing the archive the same way the goal replaces the main archive if no classifier is found. If no artifact with the specified classifier exists, the repackaged archive is still processed based on the main archive and attached to the lifecycle using the value of the classifier attribute. See gh-11061 --- .../src/it/jar-repackage-classifier/pom.xml | 66 +++++++++++++++++++ .../main/java/org/test/SampleApplication.java | 24 +++++++ .../it/jar-repackage-classifier/verify.groovy | 26 ++++++++ .../boot/maven/RepackageMojo.java | 31 ++++++++- 4 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml new file mode 100644 index 000000000000..e1e829462e40 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-repackage-classifier + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + org.apache.maven.plugins + maven-jar-plugin + @maven-jar-plugin.version@ + + + + jar + + package + + test + + + Foo + + + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + test + + + + + + + + + org.springframework + spring-context + @spring.version@ + + + javax.servlet + javax.servlet-api + @servlet-api.version@ + provided + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java new file mode 100644 index 000000000000..e8784d4593d1 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2014 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.test; + +public class SampleApplication { + + public static void main(String[] args) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy new file mode 100644 index 000000000000..8d5e781d774b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2014 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. + */ + +import java.io.*; +import org.springframework.boot.maven.*; + +File f = new File(basedir, "target/jar-repackage-classifier-0.0.1.BUILD-SNAPSHOT-test.jar"); +new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { + @Override + protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { + super.verifyZipEntries(verifier) + } +}.verify(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index d0a2289d98a5..9ea06837b3be 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -57,6 +57,7 @@ * @author Phillip Webb * @author Dave Syer * @author Stephane Nicoll + * @author Björn Lindström */ @Mojo(name = "repackage", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME) public class RepackageMojo extends AbstractDependencyFilterMojo { @@ -99,7 +100,8 @@ public class RepackageMojo extends AbstractDependencyFilterMojo { /** * Classifier to add to the artifact generated. If given, the artifact will be * attached with that classifier and the main artifact will be deployed as the main - * artifact. If this is not given (default), it will replace the main artifact and + * artifact. If an artifact with the classifier already exists, it will be used as source. + * If a classifier is not given (default), it will replace the main artifact and * only the repackaged artifact will be deployed. Attaching the artifact allows to * deploy it alongside to the original one, see artifacts = filterDependencies(this.project.getArtifacts(), @@ -225,6 +227,21 @@ private void repackage() throws MojoExecutionException { updateArtifact(source, target, repackager.getBackupFile()); } + private File getSourceFile() { + Artifact sourceArtifact = this.project.getArtifact(); + + if (this.classifier != null) { + for (Artifact attachedArtifact : this.project.getAttachedArtifacts()) { + if (this.classifier.equals(attachedArtifact.getClassifier())) { + sourceArtifact = attachedArtifact; + break; + } + } + } + + return sourceArtifact.getFile(); + } + private File getTargetFile() { String classifier = (this.classifier != null ? this.classifier.trim() : ""); if (!classifier.isEmpty() && !classifier.startsWith("-")) { @@ -233,10 +250,18 @@ private File getTargetFile() { if (!this.outputDirectory.exists()) { this.outputDirectory.mkdirs(); } - return new File(this.outputDirectory, this.finalName + classifier + "." + return new File(this.outputDirectory, this.finalName + getClassifier() + "." + this.project.getArtifact().getArtifactHandler().getExtension()); } + private String getClassifier() { + String classifier = (this.classifier == null ? "" : this.classifier.trim()); + if (classifier.length() > 0 && !classifier.startsWith("-")) { + classifier = "-" + classifier; + } + return classifier; + } + private Repackager getRepackager(File source) { Repackager repackager = new Repackager(source, this.layoutFactory); repackager.addMainClassTimeoutWarningListener( From ed02d02d19abe91f4145e4fdb92648d19efb052c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 15 May 2018 14:47:18 +0200 Subject: [PATCH 056/701] Polish "Allow repackage maven goal to take a source classifier" Closes gh-11061 --- .../src/it/jar-attach-disabled/verify.groovy | 2 +- .../it/jar-classifier-main/invoker.properties | 1 + .../src/it/jar-classifier-main/pom.xml | 57 ++++++++++++++ .../java/org/test/SampleApplication.java} | 16 ++-- .../src/it/jar-classifier-main/verify.groovy | 20 +++++ .../jar-classifier-source/invoker.properties | 1 + .../pom.xml | 2 +- .../main/java/org/test/SampleApplication.java | 0 .../it/jar-classifier-source/verify.groovy | 33 +++++++++ .../boot/maven/RepackageMojo.java | 74 ++++++++++--------- .../apt/examples/repackage-classifier.apt.vm | 59 ++++++++++++++- 11 files changed, 216 insertions(+), 49 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/invoker.properties create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/pom.xml rename spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/{jar-repackage-classifier/verify.groovy => jar-classifier-main/src/main/java/org/test/SampleApplication.java} (58%) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/verify.groovy create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/invoker.properties rename spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/{jar-repackage-classifier => jar-classifier-source}/pom.xml (97%) rename spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/{jar-repackage-classifier => jar-classifier-source}/src/main/java/org/test/SampleApplication.java (100%) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/verify.groovy diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-attach-disabled/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-attach-disabled/verify.groovy index f7fde1c94cb9..676d04c4b63a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-attach-disabled/verify.groovy +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-attach-disabled/verify.groovy @@ -13,7 +13,7 @@ assertTrue 'backup file should exist', backup.exists() def file = new File(basedir, "build.log") assertTrue 'main artifact should have been updated', - file.text.contains("Updating main artifact " + main + " to " + backup) + file.text.contains("Updating artifact " + main + " to " + backup) return file.text.contains ("Installing "+backup) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/invoker.properties b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/invoker.properties new file mode 100644 index 000000000000..c0c3f7cc079e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean install \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/pom.xml new file mode 100644 index 000000000000..6dd361c02bed --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-classifier-main + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + test + + + + + + org.apache.maven.plugins + maven-jar-plugin + @maven-jar-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring.version@ + + + javax.servlet + javax.servlet-api + @servlet-api.version@ + provided + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java similarity index 58% rename from spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy rename to spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java index 8d5e781d774b..8a5b6691293a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/verify.groovy +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2017 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. @@ -14,13 +14,11 @@ * limitations under the License. */ -import java.io.*; -import org.springframework.boot.maven.*; +package org.test; -File f = new File(basedir, "target/jar-repackage-classifier-0.0.1.BUILD-SNAPSHOT-test.jar"); -new Verify.JarArchiveVerification(f, Verify.SAMPLE_APP) { - @Override - protected void verifyZipEntries(Verify.ArchiveVerifier verifier) throws Exception { - super.verifyZipEntries(verifier) +public class SampleApplication { + + public static void main(String[] args) { } -}.verify(); + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/verify.groovy new file mode 100644 index 000000000000..c42623c3ebde --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/verify.groovy @@ -0,0 +1,20 @@ +import java.io.*; +import org.springframework.boot.maven.*; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +File repackaged = new File(basedir, "target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT-test.jar") +new Verify.JarArchiveVerification(repackaged, Verify.SAMPLE_APP).verify(); + +File main = new File( basedir, "target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT.jar") +assertTrue 'main artifact should exist', main.exists() + +File backup = new File( basedir, "target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT.jar.original") +assertFalse 'backup artifact should not exist', backup.exists() + +def file = new File(basedir, "build.log") +assertTrue 'repackaged artifact should have been attached', file.text.contains("Attaching archive " + repackaged) +assertTrue 'main artifact should have been installed', file.text.contains ("Installing "+main) +assertTrue 'repackaged artifact should have been installed', file.text.contains ("Installing "+repackaged) + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/invoker.properties b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/invoker.properties new file mode 100644 index 000000000000..c0c3f7cc079e --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/invoker.properties @@ -0,0 +1 @@ +invoker.goals=clean install \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/pom.xml similarity index 97% rename from spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml rename to spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/pom.xml index e1e829462e40..ad8143b793e5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot.maven.it - jar-repackage-classifier + jar-classifier-source 0.0.1.BUILD-SNAPSHOT UTF-8 diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java similarity index 100% rename from spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-repackage-classifier/src/main/java/org/test/SampleApplication.java rename to spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/verify.groovy b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/verify.groovy new file mode 100644 index 000000000000..7ee8a990cc0d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/verify.groovy @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2014 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. + */ + +import java.io.*; +import org.springframework.boot.maven.* + +import static org.junit.Assert.assertFalse +import static org.junit.Assert.assertTrue; + +File repackaged = new File(basedir, "target/jar-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar"); +new Verify.JarArchiveVerification(repackaged, Verify.SAMPLE_APP).verify(); + +File backup = new File( basedir, "target/jar-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar.original") +assertTrue 'backup artifact should exist', backup.exists() + +def file = new File(basedir, "build.log") +assertTrue 'repackaged artifact should have been replaced', file.text.contains("Replacing artifact with classifier test " + repackaged) +assertFalse 'backup artifact should not have been installed', file.text.contains ("Installing "+backup) +assertTrue 'repackaged artifact should have been installed', file.text.contains ("Installing "+repackaged) + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 9ea06837b3be..f43fe800addb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -98,12 +98,13 @@ public class RepackageMojo extends AbstractDependencyFilterMojo { private boolean skip; /** - * Classifier to add to the artifact generated. If given, the artifact will be - * attached with that classifier and the main artifact will be deployed as the main - * artifact. If an artifact with the classifier already exists, it will be used as source. - * If a classifier is not given (default), it will replace the main artifact and - * only the repackaged artifact will be deployed. Attaching the artifact allows to - * deploy it alongside to the original one, see the maven documentation for more details. * @since 1.0 @@ -210,9 +211,9 @@ public void execute() throws MojoExecutionException, MojoFailureException { } private void repackage() throws MojoExecutionException { - File source = getSourceFile(); + Artifact source = getSourceArtifact(); File target = getTargetFile(); - Repackager repackager = getRepackager(source); + Repackager repackager = getRepackager(source.getFile()); Set artifacts = filterDependencies(this.project.getArtifacts(), getFilters(getAdditionalFilters())); Libraries libraries = new ArtifactsLibraries(artifacts, this.requiresUnpack, @@ -227,19 +228,26 @@ private void repackage() throws MojoExecutionException { updateArtifact(source, target, repackager.getBackupFile()); } - private File getSourceFile() { - Artifact sourceArtifact = this.project.getArtifact(); + /** + * Return the source {@link Artifact} to repackage. If a classifier is specified + * and an artifact with that classifier exists, it is used. Otherwise, the main + * artifact is used. + * @return the source artifact to repackage + */ + private Artifact getSourceArtifact() { + Artifact sourceArtifact = getArtifact(this.classifier); + return (sourceArtifact != null ? sourceArtifact : this.project.getArtifact()); + } - if (this.classifier != null) { + private Artifact getArtifact(String classifier) { + if (classifier != null) { for (Artifact attachedArtifact : this.project.getAttachedArtifacts()) { - if (this.classifier.equals(attachedArtifact.getClassifier())) { - sourceArtifact = attachedArtifact; - break; + if (classifier.equals(attachedArtifact.getClassifier())) { + return attachedArtifact; } } } - - return sourceArtifact.getFile(); + return null; } private File getTargetFile() { @@ -250,18 +258,10 @@ private File getTargetFile() { if (!this.outputDirectory.exists()) { this.outputDirectory.mkdirs(); } - return new File(this.outputDirectory, this.finalName + getClassifier() + "." + return new File(this.outputDirectory, this.finalName + classifier + "." + this.project.getArtifact().getArtifactHandler().getExtension()); } - private String getClassifier() { - String classifier = (this.classifier == null ? "" : this.classifier.trim()); - if (classifier.length() > 0 && !classifier.startsWith("-")) { - classifier = "-" + classifier; - } - return classifier; - } - private Repackager getRepackager(File source) { Repackager repackager = new Repackager(source, this.layoutFactory); repackager.addMainClassTimeoutWarningListener( @@ -327,26 +327,28 @@ private void putIfMissing(Properties properties, String key, } } - private void updateArtifact(File source, File repackaged, File original) { + private void updateArtifact(Artifact source, File target, File original) { if (this.attach) { - attachArtifact(source, repackaged); + attachArtifact(source, target); } - else if (source.equals(repackaged)) { + else if (source.getFile().equals(target)) { + getLog().info("Updating artifact " + source.getFile() + " to " + original); this.project.getArtifact().setFile(original); - getLog().info("Updating main artifact " + source + " to " + original); } } - private void attachArtifact(File source, File repackaged) { - if (this.classifier != null) { - getLog().info("Attaching archive: " + repackaged + ", with classifier: " + private void attachArtifact(Artifact source, File target) { + if (this.classifier != null && !source.getFile().equals(target)) { + getLog().info("Attaching archive " + target + " with classifier " + this.classifier); this.projectHelper.attachArtifact(this.project, this.project.getPackaging(), - this.classifier, repackaged); + this.classifier, target); } - else if (!source.equals(repackaged)) { - this.project.getArtifact().setFile(repackaged); - getLog().info("Replacing main artifact " + source + " to " + repackaged); + else { + String artifactId = this.classifier != null + ? "artifact with classifier " + this.classifier : "main artifact"; + getLog().info(String.format("Replacing %s %s", artifactId, source.getFile())); + source.setFile(target); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm index d9906792822e..3d2fee3457a8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/repackage-classifier.apt.vm @@ -47,9 +47,64 @@ --- - This configuration will generate two artifacts: the original one and the repackaged counter - part produced by the repackage goal. Both will be installed/deployed transparently. + This configuration will generate two artifacts: the original one and the repackaged + counter part produced by the repackage goal. Both will be installed/deployed + transparently. + You can also use the same configuration if you want to repackage a secondary artifact + the same way the main artifact is replaced. The following configuration installs/deploys + a single <<>> classified artifact with the repackaged app: + +--- + + ... + + ... + + ... + + org.apache.maven.plugins + maven-jar-plugin + @maven-jar-plugin.version@ + + + + jar + + package + + task + + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + repackage + + + task + + + + ... + + ... + + ... + + ... + +--- + + As both the <<>> and the <<>> runs at the + same phase, it is important that the jar plugin is defined first (so that it runs before + the repackage goal). From 3dfacaa1e37d077bb37c8e595e4f3db4f8664f92 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:41:31 +0100 Subject: [PATCH 057/701] Upgrade to MongoDB 3.8.0-beta2 Closes gh-13179 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6d34aea1a514..fd67526f38a6 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -125,7 +125,7 @@ 1.0.4 2.18.3 1.7.1 - 3.6.3 + 3.8.0-beta2 6.2.2.jre8 5.1.46 5.8.1.Final From 33fadda4d9ff2e9e10397937feb855948a618361 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:42:59 +0100 Subject: [PATCH 058/701] Upgrade to Mongo Driver Reactive Streams 1.9.0-beta1 Closes gh-13180 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fd67526f38a6..1132088e6c1c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -124,7 +124,7 @@ 2.2.3 1.0.4 2.18.3 - 1.7.1 + 1.9.0-beta1 3.8.0-beta2 6.2.2.jre8 5.1.46 From 150a19523cf014fda03836eba6d3e24036f50615 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:37:19 +0100 Subject: [PATCH 059/701] Start building against Spring Data Lovelace M3 snapshots See gh-13169 --- .../data/mongo/MongoDataAutoConfiguration.java | 12 ++++++++++++ spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 14a17c33c876..63c2ad1fe97b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -18,8 +18,10 @@ import java.util.Collections; +import com.mongodb.ClientSessionOptions; import com.mongodb.DB; import com.mongodb.MongoClient; +import com.mongodb.client.ClientSession; import com.mongodb.client.MongoDatabase; import org.springframework.beans.BeanUtils; @@ -182,6 +184,16 @@ public DB getLegacyDb() { return this.mongoDbFactory.getLegacyDb(); } + @Override + public ClientSession getSession(ClientSessionOptions options) { + return this.mongoDbFactory.getSession(options); + } + + @Override + public MongoDbFactory withSession(ClientSession session) { + return this.mongoDbFactory.withSession(session); + } + } } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1132088e6c1c..d08edcf80880 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -155,7 +155,7 @@ 2.0.3.RELEASE 4.0.1.RELEASE 2.0.1.RELEASE - Kay-SR7 + Lovelace-BUILD-SNAPSHOT 0.24.0.RELEASE 5.0.5.RELEASE 2.2.0.BUILD-SNAPSHOT From 795ff45a65a9c13d496fdbcf72d4cbf69af5e7b3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:39:24 +0100 Subject: [PATCH 060/701] Upgrade to Cassandra Java Driver 3.5.0 Closes gh-13177 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d08edcf80880..62eca1edba76 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -42,7 +42,7 @@ 2.1.4 1.7.11 2.6.2 - 3.4.0 + 3.5.0 1.3.4 1.11 2.2.0 From 148997fd43507a74f26d0494e67c5dc3e5714c43 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:40:34 +0100 Subject: [PATCH 061/701] Upgrade to Elasticsearch 6.2.4 Closes gh-13178 --- .../rest/RestClientAutoConfiguration.java | 12 +++++++----- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index ea68b2624dfe..1f99a2b859e4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -62,12 +62,13 @@ public RestClientAutoConfiguration(RestClientProperties properties, @Bean(destroyMethod = "close") @ConditionalOnMissingBean - public RestClient restClient() { - RestClientBuilder builder = configureBuilder(); + public RestClient restClient(RestClientBuilder builder) { return builder.build(); } - protected RestClientBuilder configureBuilder() { + @Bean + @ConditionalOnMissingBean + public RestClientBuilder restClientBuilder() { HttpHost[] hosts = this.properties.getUris().stream().map(HttpHost::create) .toArray(HttpHost[]::new); RestClientBuilder builder = RestClient.builder(hosts); @@ -90,8 +91,9 @@ public static class RestHighLevelClientConfiguration { @Bean @ConditionalOnMissingBean - public RestHighLevelClient restHighLevelClient(RestClient restClient) { - return new RestHighLevelClient(restClient); + public RestHighLevelClient restHighLevelClient( + RestClientBuilder restClientBuilder) { + return new RestHighLevelClient(restClientBuilder); } } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 62eca1edba76..0998baf4dab0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -59,7 +59,7 @@ 2.0.3 5.0.7 2.3.28 - 5.6.9 + 6.2.4 3.0.0 2.4.15 2.8.4 From b5185fbe10984e7be5b1bef58688218e1a467cee Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:40:56 +0100 Subject: [PATCH 062/701] Upgrade to Lettuce 5.1.0.M1 Closes gh-13181 --- .../data/redis/RedisAutoConfigurationTests.java | 15 ++++++++++++--- .../spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 973204396c06..658d2f31eb7f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; @@ -231,9 +232,17 @@ public void testRedisConfigurationWithCluster() { .withPropertyValues( "spring.redis.cluster.nodes[0]:" + clusterNodes.get(0), "spring.redis.cluster.nodes[1]:" + clusterNodes.get(1)) - .run((context) -> assertThat(context - .getBean(LettuceConnectionFactory.class).getClusterConnection()) - .isNotNull()); + .run((context) -> { + RedisClusterConfiguration clusterConfiguration = context + .getBean(LettuceConnectionFactory.class) + .getClusterConfiguration(); + assertThat(clusterConfiguration.getClusterNodes()).hasSize(2); + assertThat(clusterConfiguration.getClusterNodes()) + .extracting((node) -> node.getHost() + ":" + node.getPort()) + .containsExactlyInAnyOrder("127.0.0.1:27379", + "127.0.0.1:27380"); + }); + } @Test diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0998baf4dab0..143bd6da6296 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -116,7 +116,7 @@ 1.1.0 1.1.0 1.2.41 - 5.0.4.RELEASE + 5.1.0.M1 3.6.1 2.10.0 1.2.3 From 38b491018c8c6f02f86dd192dc680206c00779f6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 15 May 2018 16:43:33 +0100 Subject: [PATCH 063/701] Upgrade to Solr 7.2.1 Closes gh-13182 --- spring-boot-project/spring-boot-dependencies/pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 143bd6da6296..beb7e00957e0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -150,7 +150,7 @@ 1.1.1 1.7.25 1.19 - 6.6.3 + 7.2.1 5.0.6.RELEASE 2.0.3.RELEASE 4.0.1.RELEASE @@ -1531,6 +1531,11 @@ solr-langid ${solr.version} + + org.apache.solr + solr-ltr + ${solr.version} + org.apache.solr solr-solrj From d8f9aad8d436873719df5e005050df646e99a4c1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 16 May 2018 10:04:35 +0100 Subject: [PATCH 064/701] Upgrade to Spring Security 5.1.0.M1 Closes gh-13185 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index beb7e00957e0..5e6ef22056e0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -163,7 +163,7 @@ 1.2.0.RELEASE 2.0.1.RELEASE 1.2.2.RELEASE - 5.0.5.RELEASE + 5.1.0.M1 Apple-SR2 3.0.1.RELEASE 3.21.0.1 From 69aa4913e345882880d1fc4496bda1b7ad635b58 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 16 May 2018 11:30:28 +0100 Subject: [PATCH 065/701] Align tests for OAuth properties adapter with changes in Spring Security Closes gh-13185 --- .../OAuth2ClientPropertiesRegistrationAdapterTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 7c5e6c765117..353c76909151 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -118,7 +118,7 @@ public void getClientRegistrationsWhenUsingCommonProviderShouldAdapt() { assertThat(adapted.getAuthorizationGrantType()).isEqualTo( org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE); assertThat(adapted.getRedirectUriTemplate()) - .isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}"); + .isEqualTo("{baseUrl}/{action}/oauth2/code/{registrationId}"); assertThat(adapted.getScopes()).containsExactly("openid", "profile", "email"); assertThat(adapted.getClientName()).isEqualTo("Google"); } @@ -201,7 +201,7 @@ public void getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationI assertThat(adapted.getAuthorizationGrantType()).isEqualTo( org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE); assertThat(adapted.getRedirectUriTemplate()) - .isEqualTo("{baseUrl}/login/oauth2/code/{registrationId}"); + .isEqualTo("{baseUrl}/{action}/oauth2/code/{registrationId}"); assertThat(adapted.getScopes()).containsExactly("openid", "profile", "email"); assertThat(adapted.getClientName()).isEqualTo("Google"); } From d829d522be8c3c6ebc3cbdfbc49aca4815e969c5 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Mon, 18 Jan 2016 21:17:55 +0100 Subject: [PATCH 066/701] Introduce HealthIndicatorRegistry This commit introduces HealthIndicatorRegistry which handles registration of HealthIndicator instances. Registering new HealthIndicator instances is now possible in runtime. See gh-4965 --- .../health/HealthEndpointConfiguration.java | 23 ++++- ...althEndpointWebExtensionConfiguration.java | 7 +- .../HealthIndicatorAutoConfiguration.java | 40 ++++++++- .../health/HealthIndicatorBeansComposite.java | 80 ----------------- ...loudFoundryWebEndpointDiscovererTests.java | 6 +- ...FoundryActuatorAutoConfigurationTests.java | 2 + ...FoundryActuatorAutoConfigurationTests.java | 4 +- .../HealthEndpointDocumentationTests.java | 8 +- .../HealthEndpointAutoConfigurationTests.java | 3 +- .../JmxEndpointIntegrationTests.java | 3 +- ...ebMvcEndpointExposureIntegrationTests.java | 4 +- .../DefaultHealthIndicatorRegistry.java | 68 ++++++++++++++ .../boot/actuate/health/HealthEndpoint.java | 22 +++-- .../health/HealthEndpointWebExtension.java | 4 +- .../health/HealthIndicatorRegistry.java | 66 ++++++++++++++ .../DefaultHealthIndicatorRegistryTest.java | 88 +++++++++++++++++++ .../actuate/health/HealthEndpointTests.java | 14 +-- .../HealthEndpointWebIntegrationTests.java | 13 ++- .../asciidoc/production-ready-features.adoc | 18 ++-- 19 files changed, 346 insertions(+), 127 deletions(-) delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansComposite.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java index e9b1fc7e5329..b059bd645138 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,10 +16,13 @@ package org.springframework.boot.actuate.autoconfigure.health; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -27,15 +30,27 @@ * Configuration for {@link HealthEndpoint}. * * @author Stephane Nicoll + * @author Vedran Pavic */ @Configuration class HealthEndpointConfiguration { + private final HealthAggregator healthAggregator; + + private final HealthIndicatorRegistry healthIndicatorRegistry; + + HealthEndpointConfiguration(ObjectProvider healthAggregator, + ObjectProvider healthIndicatorRegistry) { + this.healthAggregator = healthAggregator + .getIfAvailable(OrderedHealthAggregator::new); + this.healthIndicatorRegistry = healthIndicatorRegistry.getObject(); + } + @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint - public HealthEndpoint healthEndpoint(ApplicationContext applicationContext) { - return new HealthEndpoint(HealthIndicatorBeansComposite.get(applicationContext)); + public HealthEndpoint healthEndpoint() { + return new HealthEndpoint(this.healthAggregator, this.healthIndicatorRegistry); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java index 25b0a602c008..3da41f852ede 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java @@ -36,7 +36,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -107,11 +106,9 @@ static class ServletWebHealthConfiguration { @ConditionalOnEnabledEndpoint @ConditionalOnBean(HealthEndpoint.class) public HealthEndpointWebExtension healthEndpointWebExtension( - ApplicationContext applicationContext, + HealthEndpoint healthEndpoint, HealthWebEndpointResponseMapper responseMapper) { - return new HealthEndpointWebExtension( - HealthIndicatorBeansComposite.get(applicationContext), - responseMapper); + return new HealthEndpointWebExtension(healthEndpoint, responseMapper); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java index 0247d393b855..5e27db3b3ea7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,16 +16,23 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.util.LinkedHashMap; +import java.util.Map; + import org.springframework.boot.actuate.health.ApplicationHealthIndicator; +import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.ClassUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthIndicator}s. @@ -33,6 +40,7 @@ * @author Andy Wilkinson * @author Stephane Nicoll * @author Phillip Webb + * @author Vedran Pavic * @since 2.0.0 */ @Configuration @@ -61,4 +69,34 @@ public OrderedHealthAggregator healthAggregator() { return healthAggregator; } + @Bean + @ConditionalOnMissingBean(HealthIndicatorRegistry.class) + public HealthIndicatorRegistry healthIndicatorRegistry( + ApplicationContext applicationContext) { + HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); + Map indicators = new LinkedHashMap<>(); + indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class)); + if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) { + new ReactiveHealthIndicators().get(applicationContext) + .forEach(indicators::putIfAbsent); + } + indicators.forEach(registry::register); + return registry; + } + + private static class ReactiveHealthIndicators { + + public Map get(ApplicationContext applicationContext) { + Map indicators = new LinkedHashMap<>(); + applicationContext.getBeansOfType(ReactiveHealthIndicator.class) + .forEach((name, indicator) -> indicators.put(name, adapt(indicator))); + return indicators; + } + + private HealthIndicator adapt(ReactiveHealthIndicator indicator) { + return () -> indicator.health().block(); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansComposite.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansComposite.java deleted file mode 100644 index 502eb9ebaf62..000000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansComposite.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2012-2017 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.autoconfigure.health; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.actuate.health.CompositeHealthIndicator; -import org.springframework.boot.actuate.health.CompositeHealthIndicatorFactory; -import org.springframework.boot.actuate.health.HealthAggregator; -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.boot.actuate.health.ReactiveHealthIndicator; -import org.springframework.context.ApplicationContext; -import org.springframework.util.ClassUtils; - -/** - * Creates a {@link CompositeHealthIndicator} from beans in the - * {@link ApplicationContext}. - * - * @author Phillip Webb - */ -final class HealthIndicatorBeansComposite { - - private HealthIndicatorBeansComposite() { - } - - public static HealthIndicator get(ApplicationContext applicationContext) { - HealthAggregator healthAggregator = getHealthAggregator(applicationContext); - Map indicators = new LinkedHashMap<>(); - indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class)); - if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) { - new ReactiveHealthIndicators().get(applicationContext) - .forEach(indicators::putIfAbsent); - } - CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory(); - return factory.createHealthIndicator(healthAggregator, indicators); - } - - private static HealthAggregator getHealthAggregator( - ApplicationContext applicationContext) { - try { - return applicationContext.getBean(HealthAggregator.class); - } - catch (NoSuchBeanDefinitionException ex) { - return new OrderedHealthAggregator(); - } - } - - private static class ReactiveHealthIndicators { - - public Map get(ApplicationContext applicationContext) { - Map indicators = new LinkedHashMap<>(); - applicationContext.getBeansOfType(ReactiveHealthIndicator.class) - .forEach((name, indicator) -> indicators.put(name, adapt(indicator))); - return indicators; - } - - private HealthIndicator adapt(ReactiveHealthIndicator indicator) { - return () -> indicator.health().block(); - } - - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 31acdc80344c..085fabe106e7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -34,8 +34,9 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; +import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; -import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -109,7 +110,8 @@ public TestEndpointWebExtension testEndpointWebExtension() { @Bean public HealthEndpoint healthEndpoint() { - return new HealthEndpoint(mock(HealthIndicator.class)); + return new HealthEndpoint(mock(HealthAggregator.class), + mock(HealthIndicatorRegistry.class)); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index 111366da84f0..d1a486a5f111 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -32,6 +32,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -87,6 +88,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests { WebClientCustomizerConfig.class, WebClientAutoConfiguration.class, ManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class, HealthEndpointAutoConfiguration.class, ReactiveCloudFoundryActuatorAutoConfiguration.class)); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index 94e6afde968c..16c4bc607223 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -24,6 +24,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -270,7 +271,8 @@ public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { "vcap.application.application_id:my-app-id", "vcap.application.cf_api:http://my-cloud-controller.com") .withConfiguration( - AutoConfigurations.of(HealthEndpointAutoConfiguration.class)) + AutoConfigurations.of(HealthIndicatorAutoConfiguration.class, + HealthEndpointAutoConfiguration.class)) .run((context) -> { Collection endpoints = context .getBean("cloudFoundryWebEndpointServletHandlerMapping", diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 502e5484fb9e..28036a283dd0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -23,9 +23,10 @@ import org.junit.Test; -import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator; import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator; @@ -72,8 +73,9 @@ static class TestConfiguration { @Bean public HealthEndpoint endpoint(Map healthIndicators) { - return new HealthEndpoint(new CompositeHealthIndicator( - new OrderedHealthAggregator(), healthIndicators)); + HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); + healthIndicators.forEach(registry::register); + return new HealthEndpoint(new OrderedHealthAggregator(), registry); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java index 2600b6fb9796..bae97ee25cf7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java @@ -46,7 +46,8 @@ public class HealthEndpointAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( - AutoConfigurations.of(HealthEndpointAutoConfiguration.class)); + AutoConfigurations.of(HealthIndicatorAutoConfiguration.class, + HealthEndpointAutoConfiguration.class)); @Test public void healthEndpointShowDetailsDefault() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java index 76ffe93a8783..700f22962c6d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; @@ -47,7 +48,7 @@ public class JmxEndpointIntegrationTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, JmxEndpointAutoConfiguration.class, - HttpTraceAutoConfiguration.class)) + HttpTraceAutoConfiguration.class, HealthIndicatorAutoConfiguration.class)) .withConfiguration( AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL)); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointExposureIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointExposureIntegrationTests.java index 27788c8ad147..472af0bdafb4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointExposureIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointExposureIntegrationTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; @@ -73,7 +74,8 @@ public class WebMvcEndpointExposureIntegrationTests { ServletManagementContextAutoConfiguration.class, ManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class, - HttpTraceAutoConfiguration.class)) + HttpTraceAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)) .withConfiguration( AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL)) .withUserConfiguration(CustomMvcEndpoint.class, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java new file mode 100644 index 000000000000..55f528daa5e5 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Default implementation of {@link HealthIndicatorRegistry}. + * + * @author Vedran Pavic + * @since 2.1.0 + */ +public class DefaultHealthIndicatorRegistry implements HealthIndicatorRegistry { + + private final Map healthIndicators = new HashMap<>(); + + @Override + public void register(String name, HealthIndicator healthIndicator) { + Assert.notNull(healthIndicator, "HealthIndicator must not be null"); + synchronized (this.healthIndicators) { + if (this.healthIndicators.get(name) != null) { + throw new IllegalStateException( + "HealthIndicator with name '" + name + "' already registered"); + } + this.healthIndicators.put(name, healthIndicator); + } + } + + @Override + public HealthIndicator unregister(String name) { + synchronized (this.healthIndicators) { + return this.healthIndicators.remove(name); + } + } + + @Override + public HealthIndicator get(String name) { + synchronized (this.healthIndicators) { + return this.healthIndicators.get(name); + } + } + + @Override + public Map getAll() { + synchronized (this.healthIndicators) { + return Collections.unmodifiableMap(new HashMap<>(this.healthIndicators)); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index ce157a3404d9..59390b6a8bc5 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -26,25 +26,35 @@ * @author Dave Syer * @author Christian Dupuis * @author Andy Wilkinson + * @author Vedran Pavic * @since 2.0.0 */ @Endpoint(id = "health") public class HealthEndpoint { - private final HealthIndicator healthIndicator; + private final HealthAggregator healthAggregator; + + private final HealthIndicatorRegistry healthIndicatorRegistry; /** * Create a new {@link HealthEndpoint} instance. - * @param healthIndicator the health indicator + * @param healthAggregator the health aggregator + * @param healthIndicatorRegistry the health indicator registry */ - public HealthEndpoint(HealthIndicator healthIndicator) { - Assert.notNull(healthIndicator, "HealthIndicator must not be null"); - this.healthIndicator = healthIndicator; + public HealthEndpoint(HealthAggregator healthAggregator, + HealthIndicatorRegistry healthIndicatorRegistry) { + Assert.notNull(healthAggregator, "healthAggregator must not be null"); + Assert.notNull(healthIndicatorRegistry, "healthIndicatorRegistry must not be null"); + this.healthAggregator = healthAggregator; + this.healthIndicatorRegistry = healthIndicatorRegistry; } @ReadOperation public Health health() { - return this.healthIndicator.health(); + CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory(); + CompositeHealthIndicator healthIndicator = factory.createHealthIndicator( + this.healthAggregator, this.healthIndicatorRegistry.getAll()); + return healthIndicator.health(); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java index 4eed4b4a8cc2..420db8a56b7f 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java @@ -35,11 +35,11 @@ @EndpointWebExtension(endpoint = HealthEndpoint.class) public class HealthEndpointWebExtension { - private final HealthIndicator delegate; + private final HealthEndpoint delegate; private final HealthWebEndpointResponseMapper responseMapper; - public HealthEndpointWebExtension(HealthIndicator delegate, + public HealthEndpointWebExtension(HealthEndpoint delegate, HealthWebEndpointResponseMapper responseMapper) { this.delegate = delegate; this.responseMapper = responseMapper; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java new file mode 100644 index 000000000000..b499771bcbd7 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Map; + +/** + * A registry of {@link HealthIndicator}s. + *

+ * Implementations must be thread-safe. + * + * @author Andy Wilkinson + * @author Vedran Pavic + * @since 2.1.0 + */ +public interface HealthIndicatorRegistry { + + /** + * Registers the given {@code healthIndicator}, associating it with the given + * {@code name}. + * @param name the name of the indicator + * @param healthIndicator the indicator + * @throws IllegalStateException if an indicator with the given {@code name} is + * already registered. + */ + void register(String name, HealthIndicator healthIndicator); + + /** + * Unregisters the {@code HealthIndicator} previously registered with the given + * {@code name}. + * @param name the name of the indicator + * @return the unregistered indicator, or {@code null} if no indicator was found in + * the registry for the given {@code name}. + */ + HealthIndicator unregister(String name); + + /** + * Returns the health indicator registered with the given {@code name}. + * @param name the name of the indicator + * @return the health indicator, or {@code null} if no indicator was registered with + * the given {@code name}. + */ + HealthIndicator get(String name); + + /** + * Returns a snapshot of the registered health indicators and their names. The + * contents of the map do not reflect subsequent changes to the registry. + * @return the snapshot of registered health indicators + */ + Map getAll(); + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java new file mode 100644 index 000000000000..c24848c24e57 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2018 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.health; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link DefaultHealthIndicatorRegistry}. + * + * @author Vedran Pavic + */ +public class DefaultHealthIndicatorRegistryTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private HealthIndicator one = mock(HealthIndicator.class); + + private HealthIndicator two = mock(HealthIndicator.class); + + private DefaultHealthIndicatorRegistry registry; + + @Before + public void setUp() { + given(this.one.health()).willReturn(new Health.Builder().up().build()); + given(this.two.health()).willReturn(new Health.Builder().unknown().build()); + + this.registry = new DefaultHealthIndicatorRegistry(); + } + + @Test + public void register() { + this.registry.register("one", this.one); + this.registry.register("two", this.two); + assertThat(this.registry.getAll()).hasSize(2); + assertThat(this.registry.get("one")).isSameAs(this.one); + assertThat(this.registry.get("two")).isSameAs(this.two); + } + + @Test + public void registerAlreadyUsedName() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("HealthIndicator with name 'one' already registered"); + this.registry.register("one", this.one); + this.registry.register("one", this.two); + } + + @Test + public void unregister() { + this.registry.register("one", this.one); + this.registry.register("two", this.two); + assertThat(this.registry.getAll()).hasSize(2); + HealthIndicator two = this.registry.unregister("two"); + assertThat(two).isSameAs(this.two); + assertThat(this.registry.getAll()).hasSize(1); + } + + @Test + public void unregisterNotKnown() { + this.registry.register("one", this.one); + assertThat(this.registry.getAll()).hasSize(1); + HealthIndicator two = this.registry.unregister("two"); + assertThat(two).isNull(); + assertThat(this.registry.getAll()).hasSize(1); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index 66da11d9ae49..f9c2ccb65607 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -30,6 +30,7 @@ * @author Phillip Webb * @author Christian Dupuis * @author Andy Wilkinson + * @author Vedran Pavic */ public class HealthEndpointTests { @@ -40,8 +41,8 @@ public void statusAndFullDetailsAreExposed() { .withDetail("first", "1").build()); healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP) .withDetail("second", "2").build()); - HealthEndpoint endpoint = new HealthEndpoint( - createHealthIndicator(healthIndicators)); + HealthEndpoint endpoint = new HealthEndpoint(new OrderedHealthAggregator(), + createHealthIndicatorRegistry(healthIndicators)); Health health = endpoint.health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsOnlyKeys("up", "upAgain"); @@ -51,10 +52,11 @@ public void statusAndFullDetailsAreExposed() { assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2")); } - private HealthIndicator createHealthIndicator( + private HealthIndicatorRegistry createHealthIndicatorRegistry( Map healthIndicators) { - return new CompositeHealthIndicatorFactory() - .createHealthIndicator(new OrderedHealthAggregator(), healthIndicators); + HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); + healthIndicators.forEach(registry::register); + return registry; } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java index 6f06c212c3b6..635c94269a7c 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java @@ -35,6 +35,7 @@ * exposed by Jersey, Spring MVC, and WebFlux. * * @author Andy Wilkinson + * @author Vedran Pavic */ @RunWith(WebEndpointRunners.class) public class HealthEndpointWebIntegrationTests { @@ -66,17 +67,15 @@ public static class TestConfiguration { @Bean public HealthEndpoint healthEndpoint( Map healthIndicators) { - return new HealthEndpoint( - new CompositeHealthIndicatorFactory().createHealthIndicator( - new OrderedHealthAggregator(), healthIndicators)); + HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); + healthIndicators.forEach(registry::register); + return new HealthEndpoint(new OrderedHealthAggregator(), registry); } @Bean public HealthEndpointWebExtension healthWebEndpointExtension( - Map healthIndicators) { - return new HealthEndpointWebExtension( - new CompositeHealthIndicatorFactory().createHealthIndicator( - new OrderedHealthAggregator(), healthIndicators), + HealthEndpoint healthEndpoint) { + return new HealthEndpointWebExtension(healthEndpoint, new HealthWebEndpointResponseMapper(new HealthStatusHttpMapper(), ShowDetails.ALWAYS, new HashSet<>(Arrays.asList("ACTUATOR")))); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index b2097a5e4e6f..5a160174da65 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -726,13 +726,14 @@ configuration must permit access to the health endpoint for both authenticated a unauthenticated users. Health information is collected from all -{sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] beans -defined in your `ApplicationContext`. Spring Boot includes a number of auto-configured -`HealthIndicators`, and you can also write your own. By default, the final system state -is derived by the `HealthAggregator`, which sorts the statuses from each -`HealthIndicator` based on an ordered list of statuses. The first status in the sorted -list is used as the overall health status. If no `HealthIndicator` returns a status that -is known to the `HealthAggregator`, an `UNKNOWN` status is used. +{sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] instances +registered with {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[`HealthIndicatorRegistry`]. +Spring Boot includes a number of auto-configured `HealthIndicators` and you can also write +your own. By default, the final system state is +derived by the `HealthAggregator` which sorts the statuses from each `HealthIndicator` +based on an ordered list of statuses. The first status in the sorted list is used as the +overall health status. If no `HealthIndicator` returns a status that is known to the +`HealthAggregator`, an `UNKNOWN` status is used. @@ -818,6 +819,9 @@ NOTE: The identifier for a given `HealthIndicator` is the name of the bean witho `HealthIndicator` suffix, if it exists. In the preceding example, the health information is available in an entry named `my`. +Additionally, you can register (and unregister) `HealthIndicator` instances in runtime +using {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[`HealthIndicatorRegistry`]. + In addition to Spring Boot's predefined {sc-spring-boot-actuator}/health/Status.{sc-ext}[`Status`] types, it is also possible for `Health` to return a custom `Status` that represents a new system state. In such cases, a From 95b251590e9ed513ad6e0f7b182367d06fdd8cea Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 16 May 2018 09:08:01 +0200 Subject: [PATCH 067/701] Polish "Introduce HealthIndicatorRegistry" See gh-4965 Co-authored-by: Andy Wilkinson --- ...CompositeHealthIndicatorConfiguration.java | 11 +-- .../health/HealthEndpointConfiguration.java | 23 ++---- .../HealthIndicatorAutoConfiguration.java | 30 +------- .../health/HealthIndicatorRegistryBeans.java | 66 +++++++++++++++++ ...loudFoundryWebEndpointDiscovererTests.java | 6 +- .../HealthEndpointDocumentationTests.java | 10 +-- .../JmxEndpointIntegrationTests.java | 3 +- .../health/CompositeHealthIndicator.java | 58 ++++++++++----- .../CompositeHealthIndicatorFactory.java | 24 +++---- .../DefaultHealthIndicatorRegistry.java | 44 +++++++++--- .../boot/actuate/health/HealthAggregator.java | 5 +- .../boot/actuate/health/HealthEndpoint.java | 25 +++---- .../health/HealthIndicatorRegistry.java | 28 ++++---- .../HealthIndicatorRegistryFactory.java | 66 +++++++++++++++++ .../CompositeHealthIndicatorFactoryTests.java | 3 +- .../health/CompositeHealthIndicatorTests.java | 48 ++----------- ... DefaultHealthIndicatorRegistryTests.java} | 34 +++++++-- .../actuate/health/HealthEndpointTests.java | 12 ++-- .../HealthEndpointWebIntegrationTests.java | 71 ++++++++++--------- .../asciidoc/production-ready-features.adoc | 9 +-- 20 files changed, 354 insertions(+), 222 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryBeans.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java rename spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/{DefaultHealthIndicatorRegistryTest.java => DefaultHealthIndicatorRegistryTests.java} (73%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeHealthIndicatorConfiguration.java index e232e7007ad2..6e0cc0e110fd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeHealthIndicatorConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeHealthIndicatorConfiguration.java @@ -20,8 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.core.ResolvableType; /** @@ -42,11 +44,10 @@ protected HealthIndicator createHealthIndicator(Map beans) { if (beans.size() == 1) { return createHealthIndicator(beans.values().iterator().next()); } - CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator); - beans.forEach((name, source) -> composite.addHealthIndicator(name, - createHealthIndicator(source))); - return composite; + HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); + beans.forEach( + (name, source) -> registry.register(name, createHealthIndicator(source))); + return new CompositeHealthIndicator(this.healthAggregator, registry); } @SuppressWarnings("unchecked") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java index b059bd645138..9bb7af2fee72 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java @@ -16,13 +16,13 @@ package org.springframework.boot.actuate.autoconfigure.health; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicatorRegistry; -import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -30,27 +30,18 @@ * Configuration for {@link HealthEndpoint}. * * @author Stephane Nicoll - * @author Vedran Pavic */ @Configuration +@ConditionalOnSingleCandidate(HealthIndicatorRegistry.class) class HealthEndpointConfiguration { - private final HealthAggregator healthAggregator; - - private final HealthIndicatorRegistry healthIndicatorRegistry; - - HealthEndpointConfiguration(ObjectProvider healthAggregator, - ObjectProvider healthIndicatorRegistry) { - this.healthAggregator = healthAggregator - .getIfAvailable(OrderedHealthAggregator::new); - this.healthIndicatorRegistry = healthIndicatorRegistry.getObject(); - } - @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint - public HealthEndpoint healthEndpoint() { - return new HealthEndpoint(this.healthAggregator, this.healthIndicatorRegistry); + public HealthEndpoint healthEndpoint(HealthAggregator healthAggregator, + HealthIndicatorRegistry registry) { + return new HealthEndpoint( + new CompositeHealthIndicator(healthAggregator, registry)); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java index 5e27db3b3ea7..5be8f3ab136e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java @@ -16,11 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.health; -import java.util.LinkedHashMap; -import java.util.Map; - import org.springframework.boot.actuate.health.ApplicationHealthIndicator; -import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicatorRegistry; @@ -32,7 +28,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.util.ClassUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthIndicator}s. @@ -73,30 +68,7 @@ public OrderedHealthAggregator healthAggregator() { @ConditionalOnMissingBean(HealthIndicatorRegistry.class) public HealthIndicatorRegistry healthIndicatorRegistry( ApplicationContext applicationContext) { - HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); - Map indicators = new LinkedHashMap<>(); - indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class)); - if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) { - new ReactiveHealthIndicators().get(applicationContext) - .forEach(indicators::putIfAbsent); - } - indicators.forEach(registry::register); - return registry; - } - - private static class ReactiveHealthIndicators { - - public Map get(ApplicationContext applicationContext) { - Map indicators = new LinkedHashMap<>(); - applicationContext.getBeansOfType(ReactiveHealthIndicator.class) - .forEach((name, indicator) -> indicators.put(name, adapt(indicator))); - return indicators; - } - - private HealthIndicator adapt(ReactiveHealthIndicator indicator) { - return () -> indicator.health().block(); - } - + return HealthIndicatorRegistryBeans.get(applicationContext); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryBeans.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryBeans.java new file mode 100644 index 000000000000..87b3a103b803 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorRegistryBeans.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.autoconfigure.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.HealthIndicatorRegistryFactory; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.context.ApplicationContext; +import org.springframework.util.ClassUtils; + +/** + * Creates a {@link HealthIndicatorRegistry} from beans in the {@link ApplicationContext}. + * + * @author Phillip Webb + * @author Stephane Nicoll + */ +final class HealthIndicatorRegistryBeans { + + private HealthIndicatorRegistryBeans() { + } + + public static HealthIndicatorRegistry get(ApplicationContext applicationContext) { + Map indicators = new LinkedHashMap<>(); + indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class)); + if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) { + new ReactiveHealthIndicators().get(applicationContext) + .forEach(indicators::putIfAbsent); + } + HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory(); + return factory.createHealthIndicatorRegistry(indicators); + } + + private static class ReactiveHealthIndicators { + + public Map get(ApplicationContext applicationContext) { + Map indicators = new LinkedHashMap<>(); + applicationContext.getBeansOfType(ReactiveHealthIndicator.class) + .forEach((name, indicator) -> indicators.put(name, adapt(indicator))); + return indicators; + } + + private HealthIndicator adapt(ReactiveHealthIndicator indicator) { + return () -> indicator.health().block(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 085fabe106e7..31acdc80344c 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -34,9 +34,8 @@ import org.springframework.boot.actuate.endpoint.web.PathMapper; import org.springframework.boot.actuate.endpoint.web.WebOperation; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; -import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; -import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -110,8 +109,7 @@ public TestEndpointWebExtension testEndpointWebExtension() { @Bean public HealthEndpoint healthEndpoint() { - return new HealthEndpoint(mock(HealthAggregator.class), - mock(HealthIndicatorRegistry.class)); + return new HealthEndpoint(mock(HealthIndicator.class)); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 28036a283dd0..9d66ad8eacae 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -23,10 +23,10 @@ import org.junit.Test; -import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.actuate.health.HealthIndicatorRegistry; +import org.springframework.boot.actuate.health.HealthIndicatorRegistryFactory; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator; import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator; @@ -73,9 +73,9 @@ static class TestConfiguration { @Bean public HealthEndpoint endpoint(Map healthIndicators) { - HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); - healthIndicators.forEach(registry::register); - return new HealthEndpoint(new OrderedHealthAggregator(), registry); + return new HealthEndpoint(new CompositeHealthIndicator( + new OrderedHealthAggregator(), new HealthIndicatorRegistryFactory() + .createHealthIndicatorRegistry(healthIndicators))); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java index 700f22962c6d..d81cda552128 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/JmxEndpointIntegrationTests.java @@ -48,7 +48,8 @@ public class JmxEndpointIntegrationTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, JmxEndpointAutoConfiguration.class, - HttpTraceAutoConfiguration.class, HealthIndicatorAutoConfiguration.class)) + HealthIndicatorAutoConfiguration.class, + HttpTraceAutoConfiguration.class)) .withConfiguration( AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL)); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java index 5e5f4c2cbb1b..c7507c691a0f 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +19,6 @@ import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.util.Assert; - /** * {@link HealthIndicator} that returns health indications from all registered delegates. * @@ -31,43 +29,71 @@ */ public class CompositeHealthIndicator implements HealthIndicator { - private final Map indicators; + private final HealthIndicatorRegistry registry; - private final HealthAggregator healthAggregator; + private final HealthAggregator aggregator; /** * Create a new {@link CompositeHealthIndicator}. * @param healthAggregator the health aggregator + * @deprecated since 2.1.0 in favour of + * {@link #CompositeHealthIndicator(HealthAggregator, HealthIndicatorRegistry)} */ + @Deprecated public CompositeHealthIndicator(HealthAggregator healthAggregator) { - this(healthAggregator, new LinkedHashMap<>()); + this(healthAggregator, new DefaultHealthIndicatorRegistry()); } /** - * Create a new {@link CompositeHealthIndicator} from the specified indicators. + * Create a new {@link CompositeHealthIndicator} from the specified + * indicators. * @param healthAggregator the health aggregator - * @param indicators a map of {@link HealthIndicator}s with the key being used as an - * indicator name. + * @param indicators a map of {@link HealthIndicator HealthIndicators} with + * the key being used as an indicator name. + * @deprecated since 2.1.0 in favour of + * {@link #CompositeHealthIndicator(HealthAggregator, HealthIndicatorRegistry)} */ + @Deprecated public CompositeHealthIndicator(HealthAggregator healthAggregator, Map indicators) { - Assert.notNull(healthAggregator, "HealthAggregator must not be null"); - Assert.notNull(indicators, "Indicators must not be null"); - this.indicators = new LinkedHashMap<>(indicators); - this.healthAggregator = healthAggregator; + this(healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); } + /** + * Create a new {@link CompositeHealthIndicator} from the indicators in the + * given {@code registry}. + * @param healthAggregator the health aggregator + * @param registry the registry of {@link HealthIndicator HealthIndicators}. + */ + public CompositeHealthIndicator(HealthAggregator healthAggregator, + HealthIndicatorRegistry registry) { + this.aggregator = healthAggregator; + this.registry = registry; + } + + /** + * Adds the given {@code healthIndicator}, associating it with the given + * {@code name}. + * @param name the name of the indicator + * @param indicator the indicator + * @throws IllegalStateException if an indicator with the given {@code name} + * is already registered. + * @deprecated since 2.1.0 in favour of + * {@link HealthIndicatorRegistry#register(String, HealthIndicator)} + */ + @Deprecated public void addHealthIndicator(String name, HealthIndicator indicator) { - this.indicators.put(name, indicator); + this.registry.register(name, indicator); } @Override public Health health() { Map healths = new LinkedHashMap<>(); - for (Map.Entry entry : this.indicators.entrySet()) { + for (Map.Entry entry : this.registry.getAll() + .entrySet()) { healths.put(entry.getKey(), entry.getValue().health()); } - return this.healthAggregator.aggregate(healths); + return this.aggregator.aggregate(healths); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java index 17ab33f0be0c..8d0c44dac984 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,20 +26,23 @@ * * @author Stephane Nicoll * @since 2.0.0 + * @deprecated since 2.1.0 in favor of + * {@link CompositeHealthIndicator#CompositeHealthIndicator(HealthAggregator, HealthIndicatorRegistry)} */ +@Deprecated public class CompositeHealthIndicatorFactory { private final Function healthIndicatorNameFactory; + public CompositeHealthIndicatorFactory() { + this(new HealthIndicatorNameFactory()); + } + public CompositeHealthIndicatorFactory( Function healthIndicatorNameFactory) { this.healthIndicatorNameFactory = healthIndicatorNameFactory; } - public CompositeHealthIndicatorFactory() { - this(new HealthIndicatorNameFactory()); - } - /** * Create a {@link CompositeHealthIndicator} based on the specified health indicators. * @param healthAggregator the {@link HealthAggregator} @@ -52,13 +55,10 @@ public CompositeHealthIndicator createHealthIndicator( Map healthIndicators) { Assert.notNull(healthAggregator, "HealthAggregator must not be null"); Assert.notNull(healthIndicators, "HealthIndicators must not be null"); - CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator( - healthAggregator); - for (Map.Entry entry : healthIndicators.entrySet()) { - String name = this.healthIndicatorNameFactory.apply(entry.getKey()); - healthIndicator.addHealthIndicator(name, entry.getValue()); - } - return healthIndicator; + HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory( + this.healthIndicatorNameFactory); + return new CompositeHealthIndicator( + healthAggregator, factory.createHealthIndicatorRegistry(healthIndicators)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java index 55f528daa5e5..a1296460479c 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java @@ -17,7 +17,7 @@ package org.springframework.boot.actuate.health; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.springframework.util.Assert; @@ -26,42 +26,68 @@ * Default implementation of {@link HealthIndicatorRegistry}. * * @author Vedran Pavic + * @author Stephane Nicoll * @since 2.1.0 */ public class DefaultHealthIndicatorRegistry implements HealthIndicatorRegistry { - private final Map healthIndicators = new HashMap<>(); + private final Object monitor = new Object(); + + private final Map healthIndicators; + + /** + * Create a new {@link DefaultHealthIndicatorRegistry}. + */ + public DefaultHealthIndicatorRegistry() { + this(new LinkedHashMap<>()); + } + + /** + * Create a new {@link DefaultHealthIndicatorRegistry} from the specified + * indicators. + * @param healthIndicators a map of {@link HealthIndicator}s with the key + * being used as an indicator name. + */ + public DefaultHealthIndicatorRegistry(Map healthIndicators) { + Assert.notNull(healthIndicators, "HealthIndicators must not be null"); + this.healthIndicators = new LinkedHashMap<>(healthIndicators); + } @Override public void register(String name, HealthIndicator healthIndicator) { Assert.notNull(healthIndicator, "HealthIndicator must not be null"); - synchronized (this.healthIndicators) { - if (this.healthIndicators.get(name) != null) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { + HealthIndicator existing = this.healthIndicators.putIfAbsent(name, + healthIndicator); + if (existing != null) { throw new IllegalStateException( "HealthIndicator with name '" + name + "' already registered"); } - this.healthIndicators.put(name, healthIndicator); } } @Override public HealthIndicator unregister(String name) { - synchronized (this.healthIndicators) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { return this.healthIndicators.remove(name); } } @Override public HealthIndicator get(String name) { - synchronized (this.healthIndicators) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { return this.healthIndicators.get(name); } } @Override public Map getAll() { - synchronized (this.healthIndicators) { - return Collections.unmodifiableMap(new HashMap<>(this.healthIndicators)); + synchronized (this.monitor) { + return Collections + .unmodifiableMap(new LinkedHashMap<>(this.healthIndicators)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthAggregator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthAggregator.java index 63f340aa2837..8ea9e12fc2f2 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthAggregator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthAggregator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +19,7 @@ import java.util.Map; /** - * Strategy interface used by {@link CompositeHealthIndicator} to aggregate {@link Health} - * instances into a final one. + * Strategy interface used to aggregate {@link Health} instances into a final one. *

* This is especially useful to combine subsystem states expressed through * {@link Health#getStatus()} into one state for the entire system. The default diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index 59390b6a8bc5..69b0ee335534 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -26,35 +26,26 @@ * @author Dave Syer * @author Christian Dupuis * @author Andy Wilkinson - * @author Vedran Pavic * @since 2.0.0 */ @Endpoint(id = "health") public class HealthEndpoint { - private final HealthAggregator healthAggregator; - - private final HealthIndicatorRegistry healthIndicatorRegistry; + private final HealthIndicator healthIndicator; /** - * Create a new {@link HealthEndpoint} instance. - * @param healthAggregator the health aggregator - * @param healthIndicatorRegistry the health indicator registry + * Create a new {@link HealthEndpoint} instance that will use the given + * {@code healthIndicator} to generate its response. + * @param healthIndicator the health indicator */ - public HealthEndpoint(HealthAggregator healthAggregator, - HealthIndicatorRegistry healthIndicatorRegistry) { - Assert.notNull(healthAggregator, "healthAggregator must not be null"); - Assert.notNull(healthIndicatorRegistry, "healthIndicatorRegistry must not be null"); - this.healthAggregator = healthAggregator; - this.healthIndicatorRegistry = healthIndicatorRegistry; + public HealthEndpoint(HealthIndicator healthIndicator) { + Assert.notNull(healthIndicator, "HealthIndicator must not be null"); + this.healthIndicator = healthIndicator; } @ReadOperation public Health health() { - CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory(); - CompositeHealthIndicator healthIndicator = factory.createHealthIndicator( - this.healthAggregator, this.healthIndicatorRegistry.getAll()); - return healthIndicator.health(); + return this.healthIndicator.health(); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java index b499771bcbd7..cce483e4e9af 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java @@ -19,46 +19,48 @@ import java.util.Map; /** - * A registry of {@link HealthIndicator}s. + * A registry of {@link HealthIndicator HealthIndicators}. *

* Implementations must be thread-safe. * * @author Andy Wilkinson * @author Vedran Pavic + * @author Stephane Nicoll * @since 2.1.0 */ public interface HealthIndicatorRegistry { /** - * Registers the given {@code healthIndicator}, associating it with the given - * {@code name}. + * Registers the given {@code healthIndicator}, associating it with the + * given {@code name}. * @param name the name of the indicator * @param healthIndicator the indicator - * @throws IllegalStateException if an indicator with the given {@code name} is - * already registered. + * @throws IllegalStateException if an indicator with the given {@code name} + * is already registered. */ void register(String name, HealthIndicator healthIndicator); /** - * Unregisters the {@code HealthIndicator} previously registered with the given - * {@code name}. + * Unregisters the {@code HealthIndicator} previously registered with the + * given {@code name}. * @param name the name of the indicator - * @return the unregistered indicator, or {@code null} if no indicator was found in - * the registry for the given {@code name}. + * @return the unregistered indicator, or {@code null} if no indicator was + * found in the registry for the given {@code name}. */ HealthIndicator unregister(String name); /** * Returns the health indicator registered with the given {@code name}. * @param name the name of the indicator - * @return the health indicator, or {@code null} if no indicator was registered with - * the given {@code name}. + * @return the health indicator, or {@code null} if no indicator was + * registered with the given {@code name}. */ HealthIndicator get(String name); /** - * Returns a snapshot of the registered health indicators and their names. The - * contents of the map do not reflect subsequent changes to the registry. + * Returns a snapshot of the registered health indicators and their names. + * The contents of the map do not reflect subsequent changes to the + * registry. * @return the snapshot of registered health indicators */ Map getAll(); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java new file mode 100644 index 000000000000..6fff7a1ed2f3 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Map; +import java.util.function.Function; + +import org.springframework.util.Assert; + +/** + * Factory to create a {@link HealthIndicatorRegistry}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class HealthIndicatorRegistryFactory { + + private final Function healthIndicatorNameFactory; + + public HealthIndicatorRegistryFactory( + Function healthIndicatorNameFactory) { + this.healthIndicatorNameFactory = healthIndicatorNameFactory; + } + + public HealthIndicatorRegistryFactory() { + this(new HealthIndicatorNameFactory()); + } + + /** + * Create a {@link HealthIndicatorRegistry} based on the specified health + * indicators. + * @param healthIndicators the {@link HealthIndicator} instances mapped by + * name + * @return a {@link HealthIndicator} that delegates to the specified + * {@code healthIndicators}. + */ + public HealthIndicatorRegistry createHealthIndicatorRegistry( + Map healthIndicators) { + Assert.notNull(healthIndicators, "HealthIndicators must not be null"); + return initialize(new DefaultHealthIndicatorRegistry(), healthIndicators); + } + + protected T initialize(T registry, + Map healthIndicators) { + for (Map.Entry entry : healthIndicators.entrySet()) { + String name = this.healthIndicatorNameFactory.apply(entry.getKey()); + registry.register(name, entry.getValue()); + } + return registry; + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactoryTests.java index 869e1abe1f8b..0df3382d528a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -30,6 +30,7 @@ * @author Christian Dupuis * @author Andy Wilkinson */ +@Deprecated public class CompositeHealthIndicatorFactoryTests { @Test diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java index af571da8f7e3..69778a0c5439 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -45,9 +46,6 @@ public class CompositeHealthIndicatorTests { @Mock private HealthIndicator two; - @Mock - private HealthIndicator three; - @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -55,8 +53,6 @@ public void setup() { .willReturn(new Health.Builder().unknown().withDetail("1", "1").build()); given(this.two.health()) .willReturn(new Health.Builder().unknown().withDetail("2", "2").build()); - given(this.three.health()) - .willReturn(new Health.Builder().unknown().withDetail("3", "3").build()); this.healthAggregator = new OrderedHealthAggregator(); } @@ -67,7 +63,7 @@ public void createWithIndicators() { indicators.put("one", this.one); indicators.put("two", this.two); CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator, indicators); + this.healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); Health result = composite.health(); assertThat(result.getDetails()).hasSize(2); assertThat(result.getDetails()).containsEntry("one", @@ -76,48 +72,16 @@ public void createWithIndicators() { new Health.Builder().unknown().withDetail("2", "2").build()); } - @Test - public void createWithIndicatorsAndAdd() { - Map indicators = new HashMap<>(); - indicators.put("one", this.one); - indicators.put("two", this.two); - CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator, indicators); - composite.addHealthIndicator("three", this.three); - Health result = composite.health(); - assertThat(result.getDetails()).hasSize(3); - assertThat(result.getDetails()).containsEntry("one", - new Health.Builder().unknown().withDetail("1", "1").build()); - assertThat(result.getDetails()).containsEntry("two", - new Health.Builder().unknown().withDetail("2", "2").build()); - assertThat(result.getDetails()).containsEntry("three", - new Health.Builder().unknown().withDetail("3", "3").build()); - } - - @Test - public void createWithoutAndAdd() { - CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator); - composite.addHealthIndicator("one", this.one); - composite.addHealthIndicator("two", this.two); - Health result = composite.health(); - assertThat(result.getDetails().size()).isEqualTo(2); - assertThat(result.getDetails()).containsEntry("one", - new Health.Builder().unknown().withDetail("1", "1").build()); - assertThat(result.getDetails()).containsEntry("two", - new Health.Builder().unknown().withDetail("2", "2").build()); - } - @Test public void testSerialization() throws Exception { Map indicators = new HashMap<>(); indicators.put("db1", this.one); indicators.put("db2", this.two); CompositeHealthIndicator innerComposite = new CompositeHealthIndicator( - this.healthAggregator, indicators); + this.healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator); - composite.addHealthIndicator("db", innerComposite); + this.healthAggregator, new DefaultHealthIndicatorRegistry( + Collections.singletonMap("db", innerComposite))); Health result = composite.health(); ObjectMapper mapper = new ObjectMapper(); assertThat(mapper.writeValueAsString(result)).isEqualTo( diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTests.java similarity index 73% rename from spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java rename to spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTests.java index c24848c24e57..58e6fdcee69d 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTest.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistryTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.health; +import java.util.Map; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -29,8 +31,9 @@ * Tests for {@link DefaultHealthIndicatorRegistry}. * * @author Vedran Pavic + * @author Stephane Nicoll */ -public class DefaultHealthIndicatorRegistryTest { +public class DefaultHealthIndicatorRegistryTests { @Rule public ExpectedException thrown = ExpectedException.none(); @@ -43,9 +46,10 @@ public class DefaultHealthIndicatorRegistryTest { @Before public void setUp() { - given(this.one.health()).willReturn(new Health.Builder().up().build()); - given(this.two.health()).willReturn(new Health.Builder().unknown().build()); - + given(this.one.health()) + .willReturn(new Health.Builder().unknown().withDetail("1", "1").build()); + given(this.two.health()) + .willReturn(new Health.Builder().unknown().withDetail("2", "2").build()); this.registry = new DefaultHealthIndicatorRegistry(); } @@ -60,9 +64,9 @@ public void register() { @Test public void registerAlreadyUsedName() { + this.registry.register("one", this.one); this.thrown.expect(IllegalStateException.class); this.thrown.expectMessage("HealthIndicator with name 'one' already registered"); - this.registry.register("one", this.one); this.registry.register("one", this.two); } @@ -77,7 +81,7 @@ public void unregister() { } @Test - public void unregisterNotKnown() { + public void unregisterUnknown() { this.registry.register("one", this.one); assertThat(this.registry.getAll()).hasSize(1); HealthIndicator two = this.registry.unregister("two"); @@ -85,4 +89,22 @@ public void unregisterNotKnown() { assertThat(this.registry.getAll()).hasSize(1); } + @Test + public void getAllIsASnapshot() { + this.registry.register("one", this.one); + Map snapshot = this.registry.getAll(); + assertThat(snapshot).containsOnlyKeys("one"); + this.registry.register("two", this.two); + assertThat(snapshot).containsOnlyKeys("one"); + } + + @Test + public void getAllIsImmutable() { + this.registry.register("one", this.one); + Map snapshot = this.registry.getAll(); + + this.thrown.expect(UnsupportedOperationException.class); + snapshot.clear(); + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index f9c2ccb65607..e2fd12f3607a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -30,7 +30,6 @@ * @author Phillip Webb * @author Christian Dupuis * @author Andy Wilkinson - * @author Vedran Pavic */ public class HealthEndpointTests { @@ -41,8 +40,8 @@ public void statusAndFullDetailsAreExposed() { .withDetail("first", "1").build()); healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP) .withDetail("second", "2").build()); - HealthEndpoint endpoint = new HealthEndpoint(new OrderedHealthAggregator(), - createHealthIndicatorRegistry(healthIndicators)); + HealthEndpoint endpoint = new HealthEndpoint( + createHealthIndicator(healthIndicators)); Health health = endpoint.health(); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsOnlyKeys("up", "upAgain"); @@ -52,11 +51,10 @@ public void statusAndFullDetailsAreExposed() { assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2")); } - private HealthIndicatorRegistry createHealthIndicatorRegistry( + private HealthIndicator createHealthIndicator( Map healthIndicators) { - HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); - healthIndicators.forEach(registry::register); - return registry; + return new CompositeHealthIndicator(new OrderedHealthAggregator(), + new DefaultHealthIndicatorRegistry(healthIndicators)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java index 635c94269a7c..d8e90c59fb96 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java @@ -35,7 +35,6 @@ * exposed by Jersey, Spring MVC, and WebFlux. * * @author Andy Wilkinson - * @author Vedran Pavic */ @RunWith(WebEndpointRunners.class) public class HealthEndpointWebIntegrationTests { @@ -53,23 +52,48 @@ public void whenHealthIsUp200ResponseIsReturned() { @Test public void whenHealthIsDown503ResponseIsReturned() { - context.getBean("alphaHealthIndicator", TestHealthIndicator.class) - .setHealth(Health.down().build()); - client.get().uri("/actuator/health").exchange().expectStatus() - .isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody().jsonPath("status") - .isEqualTo("DOWN").jsonPath("details.alpha.status").isEqualTo("DOWN") - .jsonPath("details.bravo.status").isEqualTo("UP"); + HealthIndicatorRegistry registry = context.getBean(HealthIndicatorRegistry.class); + registry.register("charlie", () -> Health.down().build()); + try { + client.get().uri("/actuator/health").exchange().expectStatus() + .isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody().jsonPath("status") + .isEqualTo("DOWN").jsonPath("details.alpha.status").isEqualTo("UP") + .jsonPath("details.bravo.status").isEqualTo("UP") + .jsonPath("details.charlie.status").isEqualTo("DOWN"); + } + finally { + registry.unregister("charlie"); + } + } + + @Test + public void whenHealthIndicatorIsRemovedResponseIsAltered() { + HealthIndicatorRegistry registry = context.getBean(HealthIndicatorRegistry.class); + HealthIndicator bravo = registry.unregister("bravo"); + try { + client.get().uri("/actuator/health").exchange().expectStatus().isOk().expectBody() + .jsonPath("status").isEqualTo("UP").jsonPath("details.alpha.status") + .isEqualTo("UP").jsonPath("details.bravo.status").doesNotExist(); + } + finally { + registry.register("bravo", bravo); + } } @Configuration public static class TestConfiguration { @Bean - public HealthEndpoint healthEndpoint( + public HealthIndicatorRegistry healthIndicatorFactory( Map healthIndicators) { - HealthIndicatorRegistry registry = new DefaultHealthIndicatorRegistry(); - healthIndicators.forEach(registry::register); - return new HealthEndpoint(new OrderedHealthAggregator(), registry); + return new HealthIndicatorRegistryFactory() + .createHealthIndicatorRegistry(healthIndicators); + } + + @Bean + public HealthEndpoint healthEndpoint(HealthIndicatorRegistry registry) { + return new HealthEndpoint(new CompositeHealthIndicator( + new OrderedHealthAggregator(), registry)); } @Bean @@ -82,30 +106,13 @@ public HealthEndpointWebExtension healthWebEndpointExtension( } @Bean - public TestHealthIndicator alphaHealthIndicator() { - return new TestHealthIndicator(); + public HealthIndicator alphaHealthIndicator() { + return () -> Health.up().build(); } @Bean - public TestHealthIndicator bravoHealthIndicator() { - return new TestHealthIndicator(); - } - - } - - private static class TestHealthIndicator implements HealthIndicator { - - private Health health = Health.up().build(); - - @Override - public Health health() { - Health result = this.health; - this.health = Health.up().build(); - return result; - } - - void setHealth(Health health) { - this.health = health; + public HealthIndicator bravoHealthIndicator() { + return () -> Health.up().build(); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 5a160174da65..c46d08964424 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -727,9 +727,9 @@ unauthenticated users. Health information is collected from all {sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] instances -registered with {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[`HealthIndicatorRegistry`]. -Spring Boot includes a number of auto-configured `HealthIndicators` and you can also write -your own. By default, the final system state is +registered with {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[ +`HealthIndicatorRegistry`]. Spring Boot includes a number of auto-configured +`HealthIndicators` and you can also write your own. By default, the final system state is derived by the `HealthAggregator` which sorts the statuses from each `HealthIndicator` based on an ordered list of statuses. The first status in the sorted list is used as the overall health status. If no `HealthIndicator` returns a status that is known to the @@ -820,7 +820,8 @@ NOTE: The identifier for a given `HealthIndicator` is the name of the bean witho is available in an entry named `my`. Additionally, you can register (and unregister) `HealthIndicator` instances in runtime -using {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[`HealthIndicatorRegistry`]. +using {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[ +`HealthIndicatorRegistry`]. In addition to Spring Boot's predefined {sc-spring-boot-actuator}/health/Status.{sc-ext}[`Status`] types, it is also possible for From 2c176a3770507ac275a5ef5e99a08c28ddb104fe Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 16 May 2018 16:15:45 +0200 Subject: [PATCH 068/701] Add support for ReactiveHealthIndicatorRegistry This commit updates the initial proposal to add support for reactive use cases as well. A reactive application can use ReactiveHealthIndicatorRegistry as an alternative to HealthIndicatorRegistry. Closes gh-4965 --- ...eReactiveHealthIndicatorConfiguration.java | 9 +- ...althEndpointWebExtensionConfiguration.java | 21 ++-- .../HealthIndicatorAutoConfiguration.java | 25 ++++ ...HealthIndicatorBeansReactiveComposite.java | 57 --------- ...activeHealthEndpointWebExtensionTests.java | 19 +++ .../CompositeReactiveHealthIndicator.java | 46 ++++++-- ...mpositeReactiveHealthIndicatorFactory.java | 36 ++---- ...efaultReactiveHealthIndicatorRegistry.java | 96 +++++++++++++++ .../health/HealthIndicatorRegistry.java | 6 +- .../ReactiveHealthIndicatorRegistry.java | 68 +++++++++++ ...eactiveHealthIndicatorRegistryFactory.java | 93 +++++++++++++++ ...teReactiveHealthIndicatorFactoryTests.java | 1 + ...CompositeReactiveHealthIndicatorTests.java | 59 ++++++---- ...tReactiveHealthIndicatorRegistryTests.java | 111 ++++++++++++++++++ ...veHealthIndicatorRegistryFactoryTests.java | 59 ++++++++++ .../asciidoc/production-ready-features.adoc | 29 +++-- 16 files changed, 589 insertions(+), 146 deletions(-) delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansReactiveComposite.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactory.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java index 227b2f207ac2..5acd02925e9d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java @@ -20,8 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicator; +import org.springframework.boot.actuate.health.DefaultReactiveHealthIndicatorRegistry; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; import org.springframework.core.ResolvableType; /** @@ -41,11 +43,10 @@ protected ReactiveHealthIndicator createHealthIndicator(Map beans) { if (beans.size() == 1) { return createHealthIndicator(beans.values().iterator().next()); } - CompositeReactiveHealthIndicator composite = new CompositeReactiveHealthIndicator( - this.healthAggregator); - beans.forEach((name, source) -> composite.addHealthIndicator(name, + ReactiveHealthIndicatorRegistry registry = new DefaultReactiveHealthIndicatorRegistry(); + beans.forEach((name, source) -> registry.register(name, createHealthIndicator(source))); - return composite; + return new CompositeReactiveHealthIndicator(this.healthAggregator, registry); } @SuppressWarnings("unchecked") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java index 3da41f852ede..e140ac2e74f0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java @@ -16,23 +16,21 @@ package org.springframework.boot.actuate.autoconfigure.health; -import java.util.Collections; -import java.util.Map; - import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; -import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicatorFactory; +import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicator; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthEndpointWebExtension; -import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthStatusHttpMapper; import org.springframework.boot.actuate.health.HealthWebEndpointResponseMapper; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -70,19 +68,16 @@ public HealthWebEndpointResponseMapper healthWebEndpointResponseMapper( @Configuration @ConditionalOnWebApplication(type = Type.REACTIVE) + @ConditionalOnSingleCandidate(ReactiveHealthIndicatorRegistry.class) static class ReactiveWebHealthConfiguration { private final ReactiveHealthIndicator reactiveHealthIndicator; ReactiveWebHealthConfiguration(ObjectProvider healthAggregator, - ObjectProvider> reactiveHealthIndicators, - ObjectProvider> healthIndicators) { - this.reactiveHealthIndicator = new CompositeReactiveHealthIndicatorFactory() - .createReactiveHealthIndicator( - healthAggregator.getIfAvailable(OrderedHealthAggregator::new), - reactiveHealthIndicators - .getIfAvailable(Collections::emptyMap), - healthIndicators.getIfAvailable(Collections::emptyMap)); + ReactiveHealthIndicatorRegistry registry) { + this.reactiveHealthIndicator = new CompositeReactiveHealthIndicator( + healthAggregator.getIfAvailable(OrderedHealthAggregator::new), + registry); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java index 5be8f3ab136e..43ac74cbf98e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java @@ -16,13 +16,22 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.util.Collections; +import java.util.Map; + +import reactor.core.publisher.Flux; + +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicatorRegistry; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistryFactory; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -71,4 +80,20 @@ public HealthIndicatorRegistry healthIndicatorRegistry( return HealthIndicatorRegistryBeans.get(applicationContext); } + @Configuration + @ConditionalOnClass(Flux.class) + static class ReactiveHealthIndicatorConfiguration { + + @Bean + @ConditionalOnMissingBean + public ReactiveHealthIndicatorRegistry reactiveHealthIndicatorRegistry( + ObjectProvider> reactiveHealthIndicators, + ObjectProvider> healthIndicators) { + return new ReactiveHealthIndicatorRegistryFactory().createReactiveHealthIndicatorRegistry( + reactiveHealthIndicators.getIfAvailable(Collections::emptyMap), + healthIndicators.getIfAvailable(Collections::emptyMap)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansReactiveComposite.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansReactiveComposite.java deleted file mode 100644 index 2b08d4872a08..000000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorBeansReactiveComposite.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-2017 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.autoconfigure.health; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicator; -import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicatorFactory; -import org.springframework.boot.actuate.health.HealthAggregator; -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.boot.actuate.health.ReactiveHealthIndicator; -import org.springframework.context.ApplicationContext; - -/** - * Creates a {@link CompositeReactiveHealthIndicator} from beans in the - * {@link ApplicationContext}. - * - * @author Phillip Webb - */ -final class HealthIndicatorBeansReactiveComposite { - - private HealthIndicatorBeansReactiveComposite() { - } - - public static ReactiveHealthIndicator get(ApplicationContext applicationContext) { - HealthAggregator healthAggregator = getHealthAggregator(applicationContext); - return new CompositeReactiveHealthIndicatorFactory() - .createReactiveHealthIndicator(healthAggregator, - applicationContext.getBeansOfType(ReactiveHealthIndicator.class), - applicationContext.getBeansOfType(HealthIndicator.class)); - } - - private static HealthAggregator getHealthAggregator( - ApplicationContext applicationContext) { - try { - return applicationContext.getBean(HealthAggregator.class); - } - catch (NoSuchBeanDefinitionException ex) { - return new OrderedHealthAggregator(); - } - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java index 2282b1a9dc12..873a4a61180e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.actuate.health.HealthWebEndpointResponseMapper; import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicatorRegistry; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -217,6 +218,24 @@ public void roleCanBeCustomized() { }); } + @Test + public void registryCanBeAltered() { + this.contextRunner + .withUserConfiguration(HealthIndicatorsConfiguration.class) + .withPropertyValues("management.endpoint.health.show-details=always") + .run((context) -> { + ReactiveHealthIndicatorRegistry registry = context.getBean( + ReactiveHealthIndicatorRegistry.class); + ReactiveHealthEndpointWebExtension extension = context + .getBean(ReactiveHealthEndpointWebExtension.class); + assertThat(extension.health(null).block().getBody().getDetails()) + .containsOnlyKeys("application", "first", "second"); + assertThat(registry.unregister("second")).isNotNull(); + assertThat(extension.health(null).block().getBody().getDetails()) + .containsKeys("application", "first"); + }); + } + @Configuration static class HealthIndicatorsConfiguration { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java index 36879f06926d..a6d291fa6d98 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java @@ -25,8 +25,6 @@ import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; -import org.springframework.util.Assert; - /** * {@link ReactiveHealthIndicator} that returns health indications from all registered * delegates. Provides an alternative {@link Health} for a delegate that reaches a @@ -37,7 +35,7 @@ */ public class CompositeReactiveHealthIndicator implements ReactiveHealthIndicator { - private final Map indicators; + private final ReactiveHealthIndicatorRegistry registry; private final HealthAggregator healthAggregator; @@ -47,15 +45,42 @@ public class CompositeReactiveHealthIndicator implements ReactiveHealthIndicator private final Function, Mono> timeoutCompose; + /** + * Create a new {@link CompositeReactiveHealthIndicator}. + * @param healthAggregator the health aggregator + * @deprecated since 2.1.0 in favour of + * {@link #CompositeReactiveHealthIndicator(HealthAggregator, ReactiveHealthIndicatorRegistry)} + */ + @Deprecated public CompositeReactiveHealthIndicator(HealthAggregator healthAggregator) { this(healthAggregator, new LinkedHashMap<>()); } + /** + * Create a new {@link CompositeReactiveHealthIndicator} from the specified + * indicators. + * @param healthAggregator the health aggregator + * @param indicators a map of {@link ReactiveHealthIndicator HealthIndicators} with + * the key being used as an indicator name. + * @deprecated since 2.1.0 in favour of + * {@link #CompositeReactiveHealthIndicator(HealthAggregator, ReactiveHealthIndicatorRegistry)} + */ + @Deprecated public CompositeReactiveHealthIndicator(HealthAggregator healthAggregator, Map indicators) { - Assert.notNull(healthAggregator, "HealthAggregator must not be null"); - Assert.notNull(indicators, "Indicators must not be null"); - this.indicators = new LinkedHashMap<>(indicators); + this(healthAggregator, new DefaultReactiveHealthIndicatorRegistry(indicators)); + + } + + /** + * Create a new {@link CompositeReactiveHealthIndicator} from the indicators in the + * given {@code registry}. + * @param healthAggregator the health aggregator + * @param registry the registry of {@link ReactiveHealthIndicator HealthIndicators}. + */ + public CompositeReactiveHealthIndicator(HealthAggregator healthAggregator, + ReactiveHealthIndicatorRegistry registry) { + this.registry = registry; this.healthAggregator = healthAggregator; this.timeoutCompose = (mono) -> (this.timeout != null ? mono.timeout( Duration.ofMillis(this.timeout), Mono.just(this.timeoutHealth)) : mono); @@ -66,10 +91,15 @@ public CompositeReactiveHealthIndicator(HealthAggregator healthAggregator, * @param name the name of the health indicator * @param indicator the health indicator to add * @return this instance + * @throws IllegalStateException if an indicator with the given {@code name} + * is already registered. + * @deprecated since 2.1.0 in favour of + * {@link ReactiveHealthIndicatorRegistry#register(String, ReactiveHealthIndicator)} */ + @Deprecated public CompositeReactiveHealthIndicator addHealthIndicator(String name, ReactiveHealthIndicator indicator) { - this.indicators.put(name, indicator); + this.registry.register(name, indicator); return this; } @@ -92,7 +122,7 @@ public CompositeReactiveHealthIndicator timeoutStrategy(long timeout, @Override public Mono health() { - return Flux.fromIterable(this.indicators.entrySet()) + return Flux.fromIterable(this.registry.getAll().entrySet()) .flatMap((entry) -> Mono.zip(Mono.just(entry.getKey()), entry.getValue().health().compose(this.timeoutCompose))) .collectMap(Tuple2::getT1, Tuple2::getT2) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactory.java index 54044602561d..7fcf374622f6 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,19 +16,20 @@ package org.springframework.boot.actuate.health; -import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Function; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * Factory to create a {@link CompositeReactiveHealthIndicator}. * * @author Stephane Nicoll * @since 2.0.0 + * @deprecated since 2.1.0 in favor of + * {@link CompositeReactiveHealthIndicator#CompositeReactiveHealthIndicator(HealthAggregator, ReactiveHealthIndicatorRegistry)} */ +@Deprecated public class CompositeReactiveHealthIndicatorFactory { private final Function healthIndicatorNameFactory; @@ -62,30 +63,11 @@ public CompositeReactiveHealthIndicator createReactiveHealthIndicator( Assert.notNull(healthAggregator, "HealthAggregator must not be null"); Assert.notNull(reactiveHealthIndicators, "ReactiveHealthIndicators must not be null"); - CompositeReactiveHealthIndicator healthIndicator = new CompositeReactiveHealthIndicator( - healthAggregator); - merge(reactiveHealthIndicators, healthIndicators) - .forEach((beanName, indicator) -> { - String name = this.healthIndicatorNameFactory.apply(beanName); - healthIndicator.addHealthIndicator(name, indicator); - }); - return healthIndicator; - } - - private Map merge( - Map reactiveHealthIndicators, - Map healthIndicators) { - if (ObjectUtils.isEmpty(healthIndicators)) { - return reactiveHealthIndicators; - } - Map allIndicators = new LinkedHashMap<>( - reactiveHealthIndicators); - healthIndicators.forEach((beanName, indicator) -> { - String name = this.healthIndicatorNameFactory.apply(beanName); - allIndicators.computeIfAbsent(name, - (n) -> new HealthIndicatorReactiveAdapter(indicator)); - }); - return allIndicators; + ReactiveHealthIndicatorRegistryFactory factory = new ReactiveHealthIndicatorRegistryFactory( + this.healthIndicatorNameFactory); + return new CompositeReactiveHealthIndicator(healthAggregator, + factory.createReactiveHealthIndicatorRegistry(reactiveHealthIndicators, + healthIndicators)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java new file mode 100644 index 000000000000..1b9d9145ebcc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.util.Assert; + +/** + * Default implementation of {@link ReactiveHealthIndicatorRegistry}. + * + * @author Vedran Pavic + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class DefaultReactiveHealthIndicatorRegistry + implements ReactiveHealthIndicatorRegistry { + + private final Object monitor = new Object(); + + private final Map healthIndicators; + + /** + * Create a new {@link DefaultReactiveHealthIndicatorRegistry}. + */ + public DefaultReactiveHealthIndicatorRegistry() { + this(new LinkedHashMap<>()); + } + + /** + * Create a new {@link DefaultReactiveHealthIndicatorRegistry} from the specified + * indicators. + * @param healthIndicators a map of {@link HealthIndicator}s with the key + * being used as an indicator name. + */ + public DefaultReactiveHealthIndicatorRegistry( + Map healthIndicators) { + Assert.notNull(healthIndicators, "HealthIndicators must not be null"); + this.healthIndicators = new LinkedHashMap<>(healthIndicators); + } + + @Override + public void register(String name, ReactiveHealthIndicator healthIndicator) { + Assert.notNull(healthIndicator, "HealthIndicator must not be null"); + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { + ReactiveHealthIndicator existing = this.healthIndicators.putIfAbsent(name, + healthIndicator); + if (existing != null) { + throw new IllegalStateException( + "HealthIndicator with name '" + name + "' already registered"); + } + } + } + + @Override + public ReactiveHealthIndicator unregister(String name) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { + return this.healthIndicators.remove(name); + } + } + + @Override + public ReactiveHealthIndicator get(String name) { + Assert.notNull(name, "Name must not be null"); + synchronized (this.monitor) { + return this.healthIndicators.get(name); + } + } + + @Override + public Map getAll() { + synchronized (this.monitor) { + return Collections + .unmodifiableMap(new LinkedHashMap<>(this.healthIndicators)); + } + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java index cce483e4e9af..b466b9479e56 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java @@ -31,7 +31,7 @@ public interface HealthIndicatorRegistry { /** - * Registers the given {@code healthIndicator}, associating it with the + * Registers the given {@link HealthIndicator}, associating it with the * given {@code name}. * @param name the name of the indicator * @param healthIndicator the indicator @@ -41,7 +41,7 @@ public interface HealthIndicatorRegistry { void register(String name, HealthIndicator healthIndicator); /** - * Unregisters the {@code HealthIndicator} previously registered with the + * Unregisters the {@link HealthIndicator} previously registered with the * given {@code name}. * @param name the name of the indicator * @return the unregistered indicator, or {@code null} if no indicator was @@ -50,7 +50,7 @@ public interface HealthIndicatorRegistry { HealthIndicator unregister(String name); /** - * Returns the health indicator registered with the given {@code name}. + * Returns the {@link HealthIndicator} registered with the given {@code name}. * @param name the name of the indicator * @return the health indicator, or {@code null} if no indicator was * registered with the given {@code name}. diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java new file mode 100644 index 000000000000..1121cd332c21 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Map; + +/** + * A registry of {@link ReactiveHealthIndicator ReactiveHealthIndicators}. + *

+ * Implementations must be thread-safe. + * + * @author Andy Wilkinson + * @author Vedran Pavic + * @author Stephane Nicoll + * @since 2.1.0 + */ +public interface ReactiveHealthIndicatorRegistry { + + /** + * Registers the given {@link ReactiveHealthIndicator}, associating it with the + * given {@code name}. + * @param name the name of the indicator + * @param healthIndicator the indicator + * @throws IllegalStateException if an indicator with the given {@code name} + * is already registered. + */ + void register(String name, ReactiveHealthIndicator healthIndicator); + + /** + * Unregisters the {@link ReactiveHealthIndicator} previously registered with the + * given {@code name}. + * @param name the name of the indicator + * @return the unregistered indicator, or {@code null} if no indicator was + * found in the registry for the given {@code name}. + */ + ReactiveHealthIndicator unregister(String name); + + /** + * Returns the {@link ReactiveHealthIndicator} registered with the given {@code name}. + * @param name the name of the indicator + * @return the health indicator, or {@code null} if no indicator was + * registered with the given {@code name}. + */ + ReactiveHealthIndicator get(String name); + + /** + * Returns a snapshot of the registered health indicators and their names. + * The contents of the map do not reflect subsequent changes to the + * registry. + * @return the snapshot of registered health indicators + */ + Map getAll(); + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactory.java new file mode 100644 index 000000000000..c4a69a8edfa2 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactory.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Function; + +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * Factory to create a {@link HealthIndicatorRegistry}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class ReactiveHealthIndicatorRegistryFactory { + + private final Function healthIndicatorNameFactory; + + public ReactiveHealthIndicatorRegistryFactory( + Function healthIndicatorNameFactory) { + this.healthIndicatorNameFactory = healthIndicatorNameFactory; + } + + public ReactiveHealthIndicatorRegistryFactory() { + this(new HealthIndicatorNameFactory()); + } + + /** + * Create a {@link ReactiveHealthIndicatorRegistry} based on the specified health + * indicators. Each {@link HealthIndicator} are wrapped to a + * {@link HealthIndicatorReactiveAdapter}. If two instances share the same name, the + * reactive variant takes precedence. + * @param reactiveHealthIndicators the {@link ReactiveHealthIndicator} instances + * mapped by name + * @param healthIndicators the {@link HealthIndicator} instances mapped by name if + * any. + * @return a {@link ReactiveHealthIndicator} that delegates to the specified + * {@code reactiveHealthIndicators}. + */ + public ReactiveHealthIndicatorRegistry createReactiveHealthIndicatorRegistry( + Map reactiveHealthIndicators, + Map healthIndicators) { + Assert.notNull(reactiveHealthIndicators, + "ReactiveHealthIndicators must not be null"); + return initialize(new DefaultReactiveHealthIndicatorRegistry(), + reactiveHealthIndicators, healthIndicators); + } + + protected T initialize(T registry, + Map reactiveHealthIndicators, + Map healthIndicators) { + merge(reactiveHealthIndicators, healthIndicators) + .forEach((beanName, indicator) -> { + String name = this.healthIndicatorNameFactory.apply(beanName); + registry.register(name, indicator); + }); + return registry; + } + + private Map merge( + Map reactiveHealthIndicators, + Map healthIndicators) { + if (ObjectUtils.isEmpty(healthIndicators)) { + return reactiveHealthIndicators; + } + Map allIndicators = new LinkedHashMap<>( + reactiveHealthIndicators); + healthIndicators.forEach((beanName, indicator) -> { + String name = this.healthIndicatorNameFactory.apply(beanName); + allIndicators.computeIfAbsent(name, + (n) -> new HealthIndicatorReactiveAdapter(indicator)); + }); + return allIndicators; + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactoryTests.java index 1eff7355b4be..09f616c36b06 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorFactoryTests.java @@ -35,6 +35,7 @@ * * @author Stephane Nicoll */ +@Deprecated public class CompositeReactiveHealthIndicatorFactoryTests { private static final Health UP = new Health.Builder().status(Status.UP).build(); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java index e9d1b06cea0d..7e63f176d03e 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,6 +17,9 @@ package org.springframework.boot.actuate.health; import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import reactor.core.publisher.Mono; @@ -38,13 +41,12 @@ public class CompositeReactiveHealthIndicatorTests { private OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator(); - private CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( - this.healthAggregator); - @Test public void singleIndicator() { - this.indicator.addHealthIndicator("test", () -> Mono.just(HEALTHY)); - StepVerifier.create(this.indicator.health()).consumeNextWith((h) -> { + CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( + this.healthAggregator, new DefaultReactiveHealthIndicatorRegistry( + Collections.singletonMap("test", () -> Mono.just(HEALTHY)))); + StepVerifier.create(indicator.health()).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.UP); assertThat(h.getDetails()).containsOnlyKeys("test"); assertThat(h.getDetails().get("test")).isEqualTo(HEALTHY); @@ -53,24 +55,31 @@ public void singleIndicator() { @Test public void longHealth() { + Map indicators = new HashMap<>(); for (int i = 0; i < 50; i++) { - this.indicator.addHealthIndicator("test" + i, - new TimeoutHealth(10000, Status.UP)); + indicators.put("test" + i, new TimeoutHealth(10000, Status.UP)); } - StepVerifier.withVirtualTime(this.indicator::health).expectSubscription() + CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( + this.healthAggregator, + new DefaultReactiveHealthIndicatorRegistry(indicators)); + StepVerifier.withVirtualTime(indicator::health).expectSubscription() .thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> { - assertThat(h.getStatus()).isEqualTo(Status.UP); - assertThat(h.getDetails()).hasSize(50); - }).verifyComplete(); + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).hasSize(50); + }).verifyComplete(); } @Test public void timeoutReachedUsesFallback() { - this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP)) - .addHealthIndicator("fast", new TimeoutHealth(10, Status.UP)) + Map indicators = new HashMap<>(); + indicators.put("slow", new TimeoutHealth(10000, Status.UP)); + indicators.put("fast", new TimeoutHealth(10, Status.UP)); + CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( + this.healthAggregator, + new DefaultReactiveHealthIndicatorRegistry(indicators)) .timeoutStrategy(100, UNKNOWN_HEALTH); - StepVerifier.create(this.indicator.health()).consumeNextWith((h) -> { + StepVerifier.create(indicator.health()).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.UP); assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); assertThat(h.getDetails().get("slow")).isEqualTo(UNKNOWN_HEALTH); @@ -80,16 +89,20 @@ public void timeoutReachedUsesFallback() { @Test public void timeoutNotReached() { - this.indicator.addHealthIndicator("slow", new TimeoutHealth(10000, Status.UP)) - .addHealthIndicator("fast", new TimeoutHealth(10, Status.UP)) + Map indicators = new HashMap<>(); + indicators.put("slow", new TimeoutHealth(10000, Status.UP)); + indicators.put("fast", new TimeoutHealth(10, Status.UP)); + CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( + this.healthAggregator, + new DefaultReactiveHealthIndicatorRegistry(indicators)) .timeoutStrategy(20000, null); - StepVerifier.withVirtualTime(this.indicator::health).expectSubscription() + StepVerifier.withVirtualTime(indicator::health).expectSubscription() .thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> { - assertThat(h.getStatus()).isEqualTo(Status.UP); - assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); - assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY); - assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY); - }).verifyComplete(); + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); + assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY); + assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY); + }).verifyComplete(); } static class TimeoutHealth implements ReactiveHealthIndicator { diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java new file mode 100644 index 000000000000..e8b4adc66c67 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Map; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import reactor.core.publisher.Mono; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link DefaultReactiveHealthIndicatorRegistry}. + * + * @author Vedran Pavic + * @author Stephane Nicoll + */ +public class DefaultReactiveHealthIndicatorRegistryTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private ReactiveHealthIndicator one = mock(ReactiveHealthIndicator.class); + + private ReactiveHealthIndicator two = mock(ReactiveHealthIndicator.class); + + private DefaultReactiveHealthIndicatorRegistry registry; + + @Before + public void setUp() { + given(this.one.health()).willReturn(Mono.just( + new Health.Builder().unknown().withDetail("1", "1").build())); + given(this.two.health()).willReturn(Mono.just( + new Health.Builder().unknown().withDetail("2", "2").build())); + this.registry = new DefaultReactiveHealthIndicatorRegistry(); + } + + @Test + public void register() { + this.registry.register("one", this.one); + this.registry.register("two", this.two); + assertThat(this.registry.getAll()).hasSize(2); + assertThat(this.registry.get("one")).isSameAs(this.one); + assertThat(this.registry.get("two")).isSameAs(this.two); + } + + @Test + public void registerAlreadyUsedName() { + this.registry.register("one", this.one); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("HealthIndicator with name 'one' already registered"); + this.registry.register("one", this.two); + } + + @Test + public void unregister() { + this.registry.register("one", this.one); + this.registry.register("two", this.two); + assertThat(this.registry.getAll()).hasSize(2); + ReactiveHealthIndicator two = this.registry.unregister("two"); + assertThat(two).isSameAs(this.two); + assertThat(this.registry.getAll()).hasSize(1); + } + + @Test + public void unregisterUnknown() { + this.registry.register("one", this.one); + assertThat(this.registry.getAll()).hasSize(1); + ReactiveHealthIndicator two = this.registry.unregister("two"); + assertThat(two).isNull(); + assertThat(this.registry.getAll()).hasSize(1); + } + + @Test + public void getAllIsASnapshot() { + this.registry.register("one", this.one); + Map snapshot = this.registry.getAll(); + assertThat(snapshot).containsOnlyKeys("one"); + this.registry.register("two", this.two); + assertThat(snapshot).containsOnlyKeys("one"); + } + + @Test + public void getAllIsImmutable() { + this.registry.register("one", this.one); + Map snapshot = this.registry.getAll(); + + this.thrown.expect(UnsupportedOperationException.class); + snapshot.clear(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java new file mode 100644 index 000000000000..824d0d6180f5 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2018 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.health; + +import java.util.Collections; + +import org.junit.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveHealthIndicatorRegistryFactory}. + * + * @author Stephane Nicoll + */ +public class ReactiveHealthIndicatorRegistryFactoryTests { + + private static final Health UP = new Health.Builder().status(Status.UP).build(); + + private static final Health DOWN = new Health.Builder().status(Status.DOWN).build(); + + private final ReactiveHealthIndicatorRegistryFactory factory = new ReactiveHealthIndicatorRegistryFactory(); + + @Test + public void defaultHealthIndicatorNameFactory() { + ReactiveHealthIndicatorRegistry registry = this.factory.createReactiveHealthIndicatorRegistry( + Collections.singletonMap("myHealthIndicator", () -> Mono.just(UP)), null); + assertThat(registry.getAll()).containsOnlyKeys("my"); + } + + @Test + public void healthIndicatorIsAdapted() { + ReactiveHealthIndicatorRegistry registry = this.factory.createReactiveHealthIndicatorRegistry( + Collections.singletonMap("test", () -> Mono.just(UP)), + Collections.singletonMap("regular", () -> DOWN)); + assertThat(registry.getAll()).containsOnlyKeys("test", "regular"); + StepVerifier.create(registry.get("regular").health()).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).isEmpty(); + }).verifyComplete(); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index c46d08964424..56f22c78ef96 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -725,16 +725,20 @@ NOTE: If you have secured your application and wish to use `always`, your securi configuration must permit access to the health endpoint for both authenticated and unauthenticated users. -Health information is collected from all +Health information is collected from the content of a +{sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[ +`HealthIndicatorRegistry`] (by default all {sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] instances -registered with {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[ -`HealthIndicatorRegistry`]. Spring Boot includes a number of auto-configured +defined in your `ApplicationContext`. Spring Boot includes a number of auto-configured `HealthIndicators` and you can also write your own. By default, the final system state is derived by the `HealthAggregator` which sorts the statuses from each `HealthIndicator` based on an ordered list of statuses. The first status in the sorted list is used as the overall health status. If no `HealthIndicator` returns a status that is known to the `HealthAggregator`, an `UNKNOWN` status is used. +TIP: The `HealthIndicatorRegistry` can be used to register and unregister health +indicators at runtime. + ==== Auto-configured HealthIndicators @@ -819,10 +823,6 @@ NOTE: The identifier for a given `HealthIndicator` is the name of the bean witho `HealthIndicator` suffix, if it exists. In the preceding example, the health information is available in an entry named `my`. -Additionally, you can register (and unregister) `HealthIndicator` instances in runtime -using {sc-spring-boot-actuator}/health/HealthIndicatorRegistry.{sc-ext}[ -`HealthIndicatorRegistry`]. - In addition to Spring Boot's predefined {sc-spring-boot-actuator}/health/Status.{sc-ext}[`Status`] types, it is also possible for `Health` to return a custom `Status` that represents a new system state. In such cases, a @@ -877,10 +877,17 @@ The following table shows the default status mappings for the built-in statuses: ==== Reactive Health Indicators For reactive applications, such as those using Spring WebFlux, `ReactiveHealthIndicator` provides a non-blocking contract for getting application health. Similar to a traditional -`HealthIndicator`, health information is collected from all -{sc-spring-boot-actuator}/health/ReactiveHealthIndicator.{sc-ext}[`ReactiveHealthIndicator`] -beans defined in your `ApplicationContext`. Regular `HealthIndicator` beans that do not -check against a reactive API are included and executed on the elastic scheduler. +`HealthIndicator`, health information is collected from the content of a +{sc-spring-boot-actuator}/health/ReactiveHealthIndicatorRegistry.{sc-ext}[ +`ReactiveHealthIndicatorRegistry`] (by default all +{sc-spring-boot-actuator}/health/HealthIndicator.{sc-ext}[`HealthIndicator`] and +{sc-spring-boot-actuator}/health/ReactiveHealthIndicator.{sc-ext}[ +`ReactiveHealthIndicator`] instances defined in your `ApplicationContext`. Regular +`HealthIndicator` that do not check against a reactive API are executed on the elastic +scheduler. + +TIP: In a reactive application, The `ReactiveHealthIndicatorRegistry` can be used to +register and unregister health indicators at runtime. To provide custom health information from a reactive API, you can register Spring beans that implement the From 76ea2d9dd4bc27371f11e79eb8bd4788167fcec4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 16 May 2018 20:23:04 +0100 Subject: [PATCH 069/701] Ensure that the server tests app can resolve milestone poms --- .../src/test/resources/pom-template.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/resources/pom-template.xml b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/resources/pom-template.xml index b9f0411a4d03..965f9cc5ee63 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/resources/pom-template.xml +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/resources/pom-template.xml @@ -61,4 +61,13 @@ + + + spring-snapshots + https://repo.spring.io/libs-snapshot + + true + + + From 9f6d3bb21d35c05950942bb5ad71652ac09d07fe Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 17 May 2018 14:08:28 +0100 Subject: [PATCH 070/701] Upgrade to Spring Data Lovelace M3 Closes gh-13169 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5e6ef22056e0..f4887da8780d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -155,7 +155,7 @@ 2.0.3.RELEASE 4.0.1.RELEASE 2.0.1.RELEASE - Lovelace-BUILD-SNAPSHOT + Lovelace-M3 0.24.0.RELEASE 5.0.5.RELEASE 2.2.0.BUILD-SNAPSHOT From b51b997b70bbb7ffc5b2291fd6309acb55dd3f31 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 17 May 2018 11:49:05 +0200 Subject: [PATCH 071/701] Run specific health check This commit improves the `health` endpoint to run health check for a particular component or, if that component is itself a composite, an instance of that component. Concretely, it is now possible to issue a `GET` on `/actuator/health/{component}` and `/actuator/health/{component}/instance` to retrieve the health of a component or an instance of a composite component, respectively. If details cannot be showed for the current user, any request leads to a 404 and does not invoke the health check at all. Closes gh-8865 --- .../src/main/asciidoc/endpoints/health.adoc | 53 +++- ...loudFoundryWebEndpointDiscovererTests.java | 12 +- ...FoundryActuatorAutoConfigurationTests.java | 16 +- ...FoundryActuatorAutoConfigurationTests.java | 16 +- .../HealthEndpointDocumentationTests.java | 40 ++- .../HealthEndpointWebExtensionTests.java | 269 +++++++++++++++++- .../health/CompositeHealthIndicator.java | 9 + .../boot/actuate/health/HealthEndpoint.java | 40 +++ .../health/HealthEndpointWebExtension.java | 22 +- .../HealthWebEndpointResponseMapper.java | 38 +++ .../actuate/health/HealthEndpointTests.java | 64 ++++- .../HealthWebEndpointResponseMapperTests.java | 125 ++++++++ 12 files changed, 681 insertions(+), 23 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/health.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/health.adoc index 16bf2fdcfde5..8c3d9d246551 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/health.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/health.adoc @@ -1,13 +1,11 @@ [[health]] = Health (`health`) - The `health` endpoint provides detailed information about the health of the application. [[health-retrieving]] -== Retrieving the Health - +== Retrieving the Health of the application To retrieve the health of the application, make a `GET` request to `/actuator/health`, as shown in the following curl-based example: @@ -21,9 +19,56 @@ include::{snippets}health/http-response.adoc[] [[health-retrieving-response-structure]] === Response Structure - The response contains details of the health of the application. The following table describes the structure of the response: [cols="2,1,3"] include::{snippets}health/response-fields.adoc[] + + + +[[health-retrieving-component]] +== Retrieving the Health of a component +To retrieve the health of a particular component of the application, make a `GET` request +to `/actuator/health/{component}`, as shown in the following curl-based example: + +include::{snippets}health/component/curl-request.adoc[] + +The resulting response is similar to the following: + +include::{snippets}health/component/http-response.adoc[] + + + +[[health-retrieving-component-response-structure]] +=== Response Structure +The response contains details of the health of a particular component of the application. +The following table describes the structure of the response: + +[cols="2,1,3"] +include::{snippets}health/component/response-fields.adoc[] + + + +[[health-retrieving-component-instance]] +== Retrieving the Health of a component instance +If a particular component consists of multiple instances (as the `broker` indicator in +the example above), the health of a particular instance of that component can be retrieved +by issuing a `GET` request to `/actuator/health/{component}/{instance}`, as shown in the +following curl-based example: + +include::{snippets}health/instance/curl-request.adoc[] + +The resulting response is similar to the following: + +include::{snippets}health/instance/http-response.adoc[] + + + +[[health-retrieving-component-instance-response-structure]] +=== Response Structure +The response contains details of the health of an instance of a particular component of +the application. The following table describes the structure of the response: + +[cols="2,1,3"] +include::{snippets}health/instance/response-fields.adoc[] diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 31acdc80344c..2d381360f5f0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -58,7 +58,7 @@ public void getEndpointsShouldAddCloudFoundryHealthExtension() { assertThat(endpoints.size()).isEqualTo(2); for (ExposableWebEndpoint endpoint : endpoints) { if (endpoint.getId().equals("health")) { - WebOperation operation = endpoint.getOperations().iterator().next(); + WebOperation operation = findMainReadOperation(endpoint); assertThat(operation.invoke(new InvocationContext( mock(SecurityContext.class), Collections.emptyMap()))) .isEqualTo("cf"); @@ -67,6 +67,16 @@ public void getEndpointsShouldAddCloudFoundryHealthExtension() { }); } + private WebOperation findMainReadOperation(ExposableWebEndpoint endpoint) { + for (WebOperation operation : endpoint.getOperations()) { + if (operation.getRequestPredicate().getPath().equals("health")) { + return operation; + } + } + throw new IllegalStateException("No main read operation found from " + + endpoint.getOperations()); + } + private void load(Class configuration, Consumer consumer) { this.load((id) -> null, (id) -> id, configuration, consumer); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index d1a486a5f111..5b1d82913b0b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -284,8 +284,9 @@ public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { Collection endpoints = getHandlerMapping( context).getEndpoints(); ExposableWebEndpoint endpoint = endpoints.iterator().next(); - WebOperation webOperation = endpoint.getOperations().iterator() - .next(); + assertThat(endpoint.getOperations()).hasSize(3); + WebOperation webOperation = findOperationWithRequestPath(endpoint, + "health"); Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); assertThat(ReflectionTestUtils.getField(invoker, "target")) @@ -346,6 +347,17 @@ private CloudFoundryWebFluxEndpointHandlerMapping getHandlerMapping( CloudFoundryWebFluxEndpointHandlerMapping.class); } + private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, + String requestPath) { + for (WebOperation operation : endpoint.getOperations()) { + if (operation.getRequestPredicate().getPath().equals(requestPath)) { + return operation; + } + } + throw new IllegalStateException("No operation found with request path " + + requestPath + " from " + endpoint.getOperations()); + } + @Configuration static class TestConfiguration { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index 16c4bc607223..8179f965a555 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -279,8 +279,9 @@ public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { CloudFoundryWebEndpointServletHandlerMapping.class) .getEndpoints(); ExposableWebEndpoint endpoint = endpoints.iterator().next(); - WebOperation webOperation = endpoint.getOperations().iterator() - .next(); + assertThat(endpoint.getOperations()).hasSize(3); + WebOperation webOperation = findOperationWithRequestPath(endpoint, + "health"); Object invoker = ReflectionTestUtils.getField(webOperation, "invoker"); assertThat(ReflectionTestUtils.getField(invoker, "target")) @@ -294,6 +295,17 @@ private CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping( CloudFoundryWebEndpointServletHandlerMapping.class); } + private WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, + String requestPath) { + for (WebOperation operation : endpoint.getOperations()) { + if (operation.getRequestPredicate().getPath().equals(requestPath)) { + return operation; + } + } + throw new IllegalStateException("No operation found with request path " + + requestPath + " from " + endpoint.getOperations()); + } + @Configuration static class TestConfiguration { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 9d66ad8eacae..2e51aabb7c6e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -17,6 +17,9 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation; import java.io.File; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import javax.sql.DataSource; @@ -24,6 +27,8 @@ import org.junit.Test; import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; +import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicatorRegistryFactory; @@ -35,6 +40,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.restdocs.payload.FieldDescriptor; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -47,9 +53,17 @@ * Tests for generating documentation describing the {@link HealthEndpoint}. * * @author Andy Wilkinson + * @author Stephane Nicoll */ public class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests { + private static final List componentFields = Arrays.asList( + fieldWithPath("status") + .description("Status of a specific part of the application"), + subsectionWithPath("details").description( + "Details of the health of a specific part of the" + + " application.")); + @Test public void health() throws Exception { this.mockMvc.perform(get("/actuator/health")).andExpect(status().isOk()) @@ -66,6 +80,19 @@ public void health() throws Exception { + " application.")))); } + @Test + public void healthComponent() throws Exception { + this.mockMvc.perform(get("/actuator/health/db")).andExpect(status().isOk()) + .andDo(document("health/component", responseFields(componentFields))); + } + + @Test + public void healthComponentInstance() throws Exception { + this.mockMvc.perform(get("/actuator/health/broker/us1")) + .andExpect(status().isOk()) + .andDo(document("health/instance", responseFields(componentFields))); + } + @Configuration @Import(BaseDocumentationConfiguration.class) @ImportAutoConfiguration(DataSourceAutoConfiguration.class) @@ -84,11 +111,22 @@ public DiskSpaceHealthIndicator diskSpaceHealthIndicator() { } @Bean - public DataSourceHealthIndicator dataSourceHealthIndicator( + public DataSourceHealthIndicator dbHealthIndicator( DataSource dataSource) { return new DataSourceHealthIndicator(dataSource); } + @Bean + public CompositeHealthIndicator brokerHealthIndicator() { + Map indicators = new LinkedHashMap<>(); + indicators.put("us1", () -> Health.up().withDetail("version", "1.0.2") + .build()); + indicators.put("us2", () -> Health.up().withDetail("version", "1.0.4") + .build()); + return new CompositeHealthIndicator(new OrderedHealthAggregator(), + new DefaultHealthIndicatorRegistry(indicators)); + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java index c173c53a8ba8..13f7e612e9de 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java @@ -17,18 +17,29 @@ package org.springframework.boot.actuate.autoconfigure.health; import java.security.Principal; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import org.springframework.boot.actuate.endpoint.SecurityContext; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthEndpointWebExtension; +import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthWebEndpointResponseMapper; +import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -42,6 +53,7 @@ public class HealthEndpointWebExtensionTests { private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withUserConfiguration(HealthIndicatorsConfiguration.class) .withConfiguration( AutoConfigurations.of(HealthIndicatorAutoConfiguration.class, HealthEndpointAutoConfiguration.class)); @@ -84,7 +96,7 @@ public void unauthenticatedUsersAreNotShownDetailsByDefault() { this.contextRunner.run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertThat(extension.getHealth(mock(SecurityContext.class)).getBody() + assertThat(extension.health(mock(SecurityContext.class)).getBody() .getDetails()).isEmpty(); }); } @@ -96,7 +108,7 @@ public void authenticatedUsersAreNotShownDetailsByDefault() { .getBean(HealthEndpointWebExtension.class); SecurityContext securityContext = mock(SecurityContext.class); given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); - assertThat(extension.getHealth(securityContext).getBody().getDetails()) + assertThat(extension.health(securityContext).getBody().getDetails()) .isEmpty(); }); } @@ -113,7 +125,7 @@ public void authenticatedUsersWhenAuthorizedCanBeShownDetails() { given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); assertThat( - extension.getHealth(securityContext).getBody().getDetails()) + extension.health(securityContext).getBody().getDetails()) .isNotEmpty(); }); } @@ -125,7 +137,7 @@ public void unauthenticatedUsersCanBeShownDetails() { .run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertThat(extension.getHealth(null).getBody().getDetails()) + assertThat(extension.health(null).getBody().getDetails()) .isNotEmpty(); }); } @@ -137,7 +149,7 @@ public void detailsCanBeHiddenFromAuthenticatedUsers() { .run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertThat(extension.getHealth(mock(SecurityContext.class)).getBody() + assertThat(extension.health(mock(SecurityContext.class)).getBody() .getDetails()).isEmpty(); }); } @@ -154,7 +166,7 @@ public void detailsCanBeHiddenFromUnauthorizedUsers() { .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); assertThat( - extension.getHealth(securityContext).getBody().getDetails()) + extension.health(securityContext).getBody().getDetails()) .isEmpty(); }); } @@ -171,11 +183,233 @@ public void detailsCanBeShownToAuthorizedUsers() { .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); assertThat( - extension.getHealth(securityContext).getBody().getDetails()) + extension.health(securityContext).getBody().getDetails()) .isNotEmpty(); }); } + @Test + public void unauthenticatedUsersAreNotShownComponentByDefault() { + this.contextRunner.run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponent( + mock(SecurityContext.class), "simple")); + }); + } + + @Test + public void authenticatedUsersAreNotShownComponentByDefault() { + this.contextRunner.run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); + assertDetailsNotFound(extension.healthForComponent(securityContext, + "simple")); + }); + } + + @Test + public void authenticatedUsersWhenAuthorizedCanBeShownComponent() { + this.contextRunner + .withPropertyValues( + "management.endpoint.health.show-details=when-authorized") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + assertSimpleComponent(extension.healthForComponent( + securityContext, "simple")); + }); + } + + @Test + public void unauthenticatedUsersCanBeShownComponent() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=always") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertSimpleComponent(extension.healthForComponent(null, "simple")); + }); + } + + @Test + public void componentCanBeHiddenFromAuthenticatedUsers() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=never") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponent( + mock(SecurityContext.class), "simple")); + }); + } + + @Test + public void componentCanBeHiddenFromUnauthorizedUsers() { + this.contextRunner.withPropertyValues( + "management.endpoint.health.show-details=when-authorized", + "management.endpoint.health.roles=ACTUATOR").run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); + assertDetailsNotFound(extension.healthForComponent(securityContext, + "simple")); + }); + } + + @Test + public void componentCanBeShownToAuthorizedUsers() { + this.contextRunner.withPropertyValues( + "management.endpoint.health.show-details=when-authorized", + "management.endpoint.health.roles=ACTUATOR").run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); + assertSimpleComponent(extension.healthForComponent(securityContext, + "simple")); + }); + } + + @Test + public void componentThatDoesNotExistMapTo404() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=always") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponent(null, + "does-not-exist")); + }); + } + + @Test + public void unauthenticatedUsersAreNotShownComponentInstanceByDefault() { + this.contextRunner.run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponentInstance( + mock(SecurityContext.class), "composite", "one")); + }); + } + + @Test + public void authenticatedUsersAreNotShownComponentInstanceByDefault() { + this.contextRunner.run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); + assertDetailsNotFound(extension.healthForComponentInstance(securityContext, + "composite", "one")); + }); + } + + @Test + public void authenticatedUsersWhenAuthorizedCanBeShownComponentInstance() { + this.contextRunner + .withPropertyValues( + "management.endpoint.health.show-details=when-authorized") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + assertSimpleComponent(extension.healthForComponentInstance( + securityContext, "composite", "one")); + }); + } + + @Test + public void unauthenticatedUsersCanBeShownComponentInstance() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=always") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertSimpleComponent(extension.healthForComponentInstance(null, + "composite", "one")); + }); + } + + @Test + public void componentInstanceCanBeHiddenFromAuthenticatedUsers() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=never") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponentInstance( + mock(SecurityContext.class), "composite", "one")); + }); + } + + @Test + public void componentInstanceCanBeHiddenFromUnauthorizedUsers() { + this.contextRunner.withPropertyValues( + "management.endpoint.health.show-details=when-authorized", + "management.endpoint.health.roles=ACTUATOR").run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); + assertDetailsNotFound(extension.healthForComponentInstance(securityContext, + "composite", "one")); + }); + } + + @Test + public void componentInstanceCanBeShownToAuthorizedUsers() { + this.contextRunner.withPropertyValues( + "management.endpoint.health.show-details=when-authorized", + "management.endpoint.health.roles=ACTUATOR").run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); + assertSimpleComponent(extension.healthForComponentInstance(securityContext, + "composite", "one")); + }); + } + + @Test + public void componentInstanceThatDoesNotExistMapTo404() { + this.contextRunner + .withPropertyValues("management.endpoint.health.show-details=always") + .run((context) -> { + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + assertDetailsNotFound(extension.healthForComponentInstance(null, + "composite", "does-not-exist")); + }); + } + + private void assertDetailsNotFound(WebEndpointResponse response) { + assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(response.getBody()).isNull(); + } + + private void assertSimpleComponent(WebEndpointResponse response) { + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(response.getBody().getDetails()).containsOnly( + entry("counter", 42)); + } + @Test public void roleCanBeCustomized() { this.contextRunner.withPropertyValues( @@ -188,9 +422,28 @@ public void roleCanBeCustomized() { .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ADMIN")).willReturn(true); assertThat( - extension.getHealth(securityContext).getBody().getDetails()) + extension.health(securityContext).getBody().getDetails()) .isNotEmpty(); }); } + @Configuration + static class HealthIndicatorsConfiguration { + + @Bean + public HealthIndicator simpleHealthIndicator() { + return () -> Health.up().withDetail("counter", 42).build(); + } + + @Bean + public HealthIndicator compositeHealthIndicator() { + Map nestedIndicators = new HashMap<>(); + nestedIndicators.put("one", simpleHealthIndicator()); + nestedIndicators.put("two", () -> Health.up().build()); + return new CompositeHealthIndicator(new OrderedHealthAggregator(), + new DefaultHealthIndicatorRegistry(nestedIndicators)); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java index c7507c691a0f..04cb30f35d05 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java @@ -86,6 +86,15 @@ public void addHealthIndicator(String name, HealthIndicator indicator) { this.registry.register(name, indicator); } + /** + * Return the {@link HealthIndicatorRegistry} of this instance. + * @return the registry of nested {@link HealthIndicator health indicators} + * @since 2.1.0 + */ + public HealthIndicatorRegistry getRegistry() { + return this.registry; + } + @Override public Health health() { Map healths = new LinkedHashMap<>(); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index 69b0ee335534..8004a5520252 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -18,6 +18,7 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.util.Assert; /** @@ -26,6 +27,7 @@ * @author Dave Syer * @author Christian Dupuis * @author Andy Wilkinson + * @author Stephane Nicoll * @since 2.0.0 */ @Endpoint(id = "health") @@ -48,4 +50,42 @@ public Health health() { return this.healthIndicator.health(); } + /** + * Return the {@link Health} of a particular component or {@code null} if such + * component does not exist. + * @param component the name of a particular {@link HealthIndicator} + * @return the {@link Health} for the component or {@code null} + */ + @ReadOperation + public Health healthForComponent(@Selector String component) { + HealthIndicator indicator = getNestedHealthIndicator(this.healthIndicator, + component); + return (indicator != null ? indicator.health() : null); + } + + /** + * Return the {@link Health} of a particular {@code instance} managed by the specified + * {@code component} or {@code null} if that particular component is not a + * {@link CompositeHealthIndicator} or if such instance does not exist. + * @param component the name of a particular {@link CompositeHealthIndicator} + * @param instance the name of an instance managed by that component + * @return the {@link Health} for the component instance of {@code null} + */ + @ReadOperation + public Health healthForComponentInstance(@Selector String component, + @Selector String instance) { + HealthIndicator indicator = getNestedHealthIndicator(this.healthIndicator, + component); + HealthIndicator nestedIndicator = getNestedHealthIndicator(indicator, instance); + return (nestedIndicator != null ? nestedIndicator.health() : null); + } + + private HealthIndicator getNestedHealthIndicator(HealthIndicator healthIndicator, + String name) { + if (healthIndicator instanceof CompositeHealthIndicator) { + return ((CompositeHealthIndicator) healthIndicator).getRegistry().get(name); + } + return null; + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java index 420db8a56b7f..ae3ac45c0958 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java @@ -16,8 +16,11 @@ package org.springframework.boot.actuate.health; +import java.util.function.Supplier; + import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; @@ -30,6 +33,7 @@ * @author Phillip Webb * @author Eddú Meléndez * @author Madhura Bhave + * @author Stephane Nicoll * @since 2.0.0 */ @EndpointWebExtension(endpoint = HealthEndpoint.class) @@ -46,10 +50,26 @@ public HealthEndpointWebExtension(HealthEndpoint delegate, } @ReadOperation - public WebEndpointResponse getHealth(SecurityContext securityContext) { + public WebEndpointResponse health(SecurityContext securityContext) { return this.responseMapper.map(this.delegate.health(), securityContext); } + @ReadOperation + public WebEndpointResponse healthForComponent(SecurityContext securityContext, + @Selector String component) { + Supplier health = () -> this.delegate.healthForComponent(component); + return this.responseMapper.mapDetails(health, securityContext); + } + + @ReadOperation + public WebEndpointResponse healthForComponentInstance( + SecurityContext securityContext, @Selector String component, + @Selector String instance) { + Supplier health = () -> this.delegate.healthForComponentInstance( + component, instance); + return this.responseMapper.mapDetails(health, securityContext); + } + public WebEndpointResponse getHealth(SecurityContext securityContext, ShowDetails showDetails) { return this.responseMapper.map(this.delegate.health(), securityContext, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapper.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapper.java index b37a459d385a..78ada76360ac 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapper.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapper.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.health; import java.util.Set; +import java.util.function.Supplier; import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; @@ -43,6 +44,28 @@ public HealthWebEndpointResponseMapper(HealthStatusHttpMapper statusHttpMapper, this.authorizedRoles = authorizedRoles; } + /** + * Maps the given {@code health} details to a {@link WebEndpointResponse}, honouring + * the mapper's default {@link ShowDetails} using the given {@code securityContext}. + *

+ * If the current user does not have the right to see the details, the + * {@link Supplier} is not invoked and a 404 response is returned instead. + * @param health the provider of health details, invoked if the current user has the + * right to see them + * @param securityContext the security context + * @return the mapped response + */ + public WebEndpointResponse mapDetails(Supplier health, + SecurityContext securityContext) { + if (canSeeDetails(securityContext, this.showDetails)) { + Health healthDetails = health.get(); + if (healthDetails != null) { + return createWebEndpointResponse(healthDetails); + } + } + return new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND); + } + /** * Maps the given {@code health} to a {@link WebEndpointResponse}, honouring the * mapper's default {@link ShowDetails} using the given {@code securityContext}. @@ -71,10 +94,25 @@ public WebEndpointResponse map(Health health, SecurityContext securityCo || !isUserInRole(securityContext)))) { health = Health.status(health.getStatus()).build(); } + return createWebEndpointResponse(health); + } + + private WebEndpointResponse createWebEndpointResponse(Health health) { Integer status = this.statusHttpMapper.mapStatus(health.getStatus()); return new WebEndpointResponse<>(health, status); } + private boolean canSeeDetails(SecurityContext securityContext, + ShowDetails showDetails) { + if (showDetails == ShowDetails.NEVER + || (showDetails == ShowDetails.WHEN_AUTHORIZED + && (securityContext.getPrincipal() == null + || !isUserInRole(securityContext)))) { + return false; + } + return true; + } + private boolean isUserInRole(SecurityContext securityContext) { if (CollectionUtils.isEmpty(this.authorizedRoles)) { return true; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index e2fd12f3607a..ca387000caee 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -30,16 +31,21 @@ * @author Phillip Webb * @author Christian Dupuis * @author Andy Wilkinson + * @author Stephane Nicoll */ public class HealthEndpointTests { + private static final HealthIndicator one = () -> new Health.Builder() + .status(Status.UP).withDetail("first", "1").build(); + + private static final HealthIndicator two = () -> new Health.Builder() + .status(Status.UP).withDetail("second", "2").build(); + @Test public void statusAndFullDetailsAreExposed() { Map healthIndicators = new HashMap<>(); - healthIndicators.put("up", () -> new Health.Builder().status(Status.UP) - .withDetail("first", "1").build()); - healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP) - .withDetail("second", "2").build()); + healthIndicators.put("up", one); + healthIndicators.put("upAgain", two); HealthEndpoint endpoint = new HealthEndpoint( createHealthIndicator(healthIndicators)); Health health = endpoint.health(); @@ -51,6 +57,56 @@ public void statusAndFullDetailsAreExposed() { assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2")); } + @Test + public void statusForComponentIsExposed() { + HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( + Collections.singletonMap("test", one))); + Health health = endpoint.healthForComponent("test"); + assertThat(health).isNotNull(); + assertThat(health.getStatus()).isEqualTo(Status.UP); + assertThat(health.getDetails()).containsOnly(entry("first", "1")); + } + + @Test + public void statusForUnknownComponentReturnNull() { + HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( + Collections.emptyMap())); + Health health = endpoint.healthForComponent("does-not-exist"); + assertThat(health).isNull(); + } + + @Test + public void statusForComponentInstanceIsExposed() { + CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( + new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( + Collections.singletonMap("sub", () -> Health.down().build()))); + HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( + Collections.singletonMap("test", compositeIndicator))); + Health health = endpoint.healthForComponentInstance("test", "sub"); + assertThat(health).isNotNull(); + assertThat(health.getStatus()).isEqualTo(Status.DOWN); + assertThat(health.getDetails()).isEmpty(); + } + + @Test + public void statusForUnknownComponentInstanceReturnNull() { + CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( + new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( + Collections.singletonMap("sub", () -> Health.down().build()))); + HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( + Collections.singletonMap("test", compositeIndicator))); + Health health = endpoint.healthForComponentInstance("test", "does-not-exist"); + assertThat(health).isNull(); + } + + @Test + public void statusForComponentInstanceThatIsNotACompositeReturnNull() { + HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( + Collections.singletonMap("test", () -> Health.up().build()))); + Health health = endpoint.healthForComponentInstance("test", "does-not-exist"); + assertThat(health).isNull(); + } + private HealthIndicator createHealthIndicator( Map healthIndicators) { return new CompositeHealthIndicator(new OrderedHealthAggregator(), diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java new file mode 100644 index 000000000000..ef6de57a6114 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2012-2018 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.health; + +import java.security.Principal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +import org.junit.Test; +import org.mockito.stubbing.Answer; + +import org.springframework.boot.actuate.endpoint.SecurityContext; +import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; +import org.springframework.http.HttpStatus; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +/** + * Tests for {@link HealthWebEndpointResponseMapper}. + * + * @author Stephane Nicoll + */ +public class HealthWebEndpointResponseMapperTests { + + private final HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper(); + + private Set autorizedRoles = Collections.singleton("ACTUATOR"); + + @Test + public void mapDetailsWithDisableDetailsDoesNotInvokeSupplier() { + HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.NEVER); + Supplier supplier = mockSupplier(); + SecurityContext securityContext = mock(SecurityContext.class); + WebEndpointResponse response = mapper.mapDetails(supplier, + securityContext); + assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); + verifyZeroInteractions(supplier); + verifyZeroInteractions(securityContext); + } + + @Test + public void mapDetailsWithUnauthorizedUserDoesNotInvokeSupplier() { + HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED); + Supplier supplier = mockSupplier(); + SecurityContext securityContext = mockSecurityContext("USER"); + WebEndpointResponse response = mapper.mapDetails(supplier, + securityContext); + assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(response.getBody()).isNull(); + verifyZeroInteractions(supplier); + verify(securityContext).isUserInRole("ACTUATOR"); + } + + @Test + public void mapDetailsWithAuthorizedUserInvokeSupplier() { + HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED); + Supplier supplier = mockSupplier(); + given(supplier.get()).willReturn(Health.down().build()); + SecurityContext securityContext = mockSecurityContext("ACTUATOR"); + WebEndpointResponse response = mapper.mapDetails(supplier, + securityContext); + assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); + assertThat(response.getBody().getStatus()).isEqualTo(Status.DOWN); + verify(supplier).get(); + verify(securityContext).isUserInRole("ACTUATOR"); + } + + @Test + public void mapDetailsWithUnavailableHealth() { + HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.ALWAYS); + Supplier supplier = mockSupplier(); + SecurityContext securityContext = mock(SecurityContext.class); + WebEndpointResponse response = mapper.mapDetails(supplier, + securityContext); + assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(response.getBody()).isNull(); + verify(supplier).get(); + verifyZeroInteractions(securityContext); + } + + @SuppressWarnings("unchecked") + private Supplier mockSupplier() { + return mock(Supplier.class); + } + + private SecurityContext mockSecurityContext(String... roles) { + List associatedRoles = Arrays.asList(roles); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole(anyString())).will((Answer) invocation -> { + String expectedRole = invocation.getArgument(0); + return associatedRoles.contains(expectedRole); + }); + return securityContext; + } + + private HealthWebEndpointResponseMapper createMapper(ShowDetails showDetails) { + return new HealthWebEndpointResponseMapper(this.statusHttpMapper, showDetails, + this.autorizedRoles); + } + +} From b7fe3a5332c03579e47e497a5f2e58f6e968c85a Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 17 May 2018 19:24:11 +0900 Subject: [PATCH 072/701] Make ErrorProperties.whitelabel final Closes gh-13197 --- .../boot/autoconfigure/web/ErrorProperties.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java index c7553e3703f3..59421635dec1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java @@ -44,7 +44,7 @@ public class ErrorProperties { */ private IncludeStacktrace includeStacktrace = IncludeStacktrace.NEVER; - private Whitelabel whitelabel = new Whitelabel(); + private final Whitelabel whitelabel = new Whitelabel(); public String getPath() { return this.path; @@ -74,10 +74,6 @@ public Whitelabel getWhitelabel() { return this.whitelabel; } - public void setWhitelabel(Whitelabel whitelabel) { - this.whitelabel = whitelabel; - } - /** * Include Stacktrace attribute options. */ From d72ba70cbaff9e0b3fbb7febb6b3da8d7ca6c4af Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 11 May 2018 14:40:15 +0900 Subject: [PATCH 073/701] Use type parameter for Supplier in AggregateBinder.merge() Closes gh-13139 --- .../boot/context/properties/bind/AggregateBinder.java | 4 ++-- .../boot/context/properties/bind/ArrayBinder.java | 2 +- .../boot/context/properties/bind/CollectionBinder.java | 5 ++--- .../boot/context/properties/bind/MapBinder.java | 5 ++--- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateBinder.java index 8ab8970299ae..677b159c3ac6 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateBinder.java @@ -60,7 +60,7 @@ public final Object bind(ConfigurationPropertyName name, Bindable target, if (result == null || value == null) { return result; } - return merge(value, (T) result); + return merge((Supplier) value, (T) result); } /** @@ -79,7 +79,7 @@ protected abstract Object bindAggregate(ConfigurationPropertyName name, * @param additional the additional elements to merge * @return the merged result */ - protected abstract T merge(Supplier existing, T additional); + protected abstract T merge(Supplier existing, T additional); /** * Return the context being used by this binder. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ArrayBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ArrayBinder.java index 057542fde3cf..517438ea4590 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ArrayBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ArrayBinder.java @@ -56,7 +56,7 @@ protected Object bindAggregate(ConfigurationPropertyName name, Bindable targe } @Override - protected Object merge(Supplier existing, Object additional) { + protected Object merge(Supplier existing, Object additional) { return additional; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java index ad735cf31494..cfd887dde2bb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java @@ -55,10 +55,9 @@ protected Object bindAggregate(ConfigurationPropertyName name, Bindable targe } @Override - @SuppressWarnings("unchecked") - protected Collection merge(Supplier existing, + protected Collection merge(Supplier> existing, Collection additional) { - Collection existingCollection = (Collection) existing.get(); + Collection existingCollection = existing.get(); if (existingCollection == null) { return additional; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java index 7efdf055b487..01939e7666ed 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java @@ -83,10 +83,9 @@ private Bindable resolveTarget(Bindable target) { } @Override - @SuppressWarnings("unchecked") - protected Map merge(Supplier existing, + protected Map merge(Supplier> existing, Map additional) { - Map existingMap = (Map) existing.get(); + Map existingMap = existing.get(); if (existingMap == null) { return additional; } From 65738e63fb247866dcbf1520f0782c1d23054ecb Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 22 May 2018 08:28:09 +0200 Subject: [PATCH 074/701] Polish --- .github/ISSUE_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 19c022f10be0..3dd45a33bffa 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,5 +1,6 @@ - org.springframework.boot - spring-boot-samples - ${revision} - - spring-boot-sample-jersey1 - Spring Boot Jersey 1 Sample - Spring Boot Jersey 1 Sample - - ${basedir}/../.. - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-tomcat - - - org.springframework - spring-web - - - com.sun.jersey - jersey-servlet - 1.13 - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - com.sun.jersey - jersey-servlet - - - com.sun.jersey - jersey-server - - - com.sun.jersey - jersey-core - - - - - - - - - java9 - - [9,) - - - - javax.xml.bind - jaxb-api - - - - - diff --git a/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java b/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java deleted file mode 100644 index 9a7cec432e97..000000000000 --- a/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2017 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 sample.jersey1; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - -import com.sun.jersey.spi.container.servlet.ServletContainer; - -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; - -@SpringBootApplication -@Path("/") -public class SampleJersey1Application { - - @GET - @Produces("text/plain") - public String hello() { - return "Hello World"; - } - - @Bean - // Not needed if Spring Web MVC is also present on classpath - public TomcatServletWebServerFactory webServerFactory() { - return new TomcatServletWebServerFactory(); - } - - @Bean - public FilterRegistrationBean jersey() { - FilterRegistrationBean bean = new FilterRegistrationBean<>(); - bean.setFilter(new ServletContainer()); - bean.addInitParameter("com.sun.jersey.config.property.packages", - "com.sun.jersey;sample.jersey1"); - return bean; - } - - public static void main(String[] args) { - new SpringApplicationBuilder(SampleJersey1Application.class) - .web(WebApplicationType.SERVLET).run(args); - } - -} diff --git a/spring-boot-samples/spring-boot-sample-jersey1/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-jersey1/src/main/resources/application.properties deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java b/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java deleted file mode 100644 index 033070fd9715..000000000000 --- a/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 sample.jersey1; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class SampleJersey1ApplicationTests { - - @Autowired - private TestRestTemplate restTemplate; - - @Test - public void rootReturnsHelloWorld() { - assertThat(this.restTemplate.getForObject("/", String.class)) - .isEqualTo("Hello World"); - } - -} From 4464a5f5bde9256a46432cfcbe5dd0ba4d34091d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 22 May 2018 14:48:25 +0200 Subject: [PATCH 076/701] Remove code deprecated in 2.0 Closes gh-12962 --- .../export/statsd/StatsdProperties.java | 17 -- .../statsd/StatsdPropertiesConfigAdapter.java | 6 - .../server/RouterFunctionMetrics.java | 150 ------------------ .../couchbase/CouchbaseConfiguration.java | 21 +-- .../couchbase/CouchbaseProperties.java | 33 ---- .../orm/jpa/HibernateSettings.java | 12 -- .../CouchbaseAutoConfigurationTests.java | 20 +-- .../boot/test/util/EnvironmentTestUtils.java | 105 ------------ .../test/util/EnvironmentTestUtilsTests.java | 96 ----------- .../boot/SpringApplication.java | 24 --- .../builder/SpringApplicationBuilder.java | 13 -- .../AbstractServletWebServerFactory.java | 19 --- 12 files changed, 6 insertions(+), 510 deletions(-) delete mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java delete mode 100644 spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java delete mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/util/EnvironmentTestUtilsTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdProperties.java index 3169348aa9ba..e671c3b44826 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdProperties.java @@ -21,7 +21,6 @@ import io.micrometer.statsd.StatsdFlavor; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; /** * {@link ConfigurationProperties} for configuring StatsD metrics export. @@ -65,11 +64,6 @@ public class StatsdProperties { */ private Duration pollingFrequency = Duration.ofSeconds(10); - /** - * Maximum size of the queue of items waiting to be sent to the StatsD server. - */ - private Integer queueSize = Integer.MAX_VALUE; - /** * Whether to send unchanged meters to the StatsD server. */ @@ -123,17 +117,6 @@ public void setPollingFrequency(Duration pollingFrequency) { this.pollingFrequency = pollingFrequency; } - @Deprecated - @DeprecatedConfigurationProperty(reason = "No longer configurable and an unbounded queue will always be used") - public Integer getQueueSize() { - return this.queueSize; - } - - @Deprecated - public void setQueueSize(Integer queueSize) { - this.queueSize = queueSize; - } - public boolean isPublishUnchangedMeters() { return this.publishUnchangedMeters; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdPropertiesConfigAdapter.java index c62b2c9b84ca..c53df2e470cf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdPropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdPropertiesConfigAdapter.java @@ -73,12 +73,6 @@ public Duration pollingFrequency() { StatsdConfig.super::pollingFrequency); } - @Override - @Deprecated - public int queueSize() { - return get(StatsdProperties::getQueueSize, StatsdConfig.super::queueSize); - } - @Override public boolean publishUnchangedMeters() { return get(StatsdProperties::isPublishUnchangedMeters, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java deleted file mode 100644 index a8e7bf7c97ed..000000000000 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/RouterFunctionMetrics.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2012-2018 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.metrics.web.reactive.server; - -import java.util.concurrent.TimeUnit; -import java.util.function.BiFunction; - -import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; -import io.micrometer.core.instrument.Tags; -import reactor.core.publisher.Mono; - -import org.springframework.util.Assert; -import org.springframework.web.reactive.function.server.HandlerFilterFunction; -import org.springframework.web.reactive.function.server.HandlerFunction; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.ServerRequest; -import org.springframework.web.reactive.function.server.ServerResponse; - -/** - * Support class for WebFlux {@link RouterFunction}-related metrics. - * - * @author Jon Schneider - * @since 2.0.0 - * @deprecated in favor of the auto-configured {@link MetricsWebFilter} - */ -@Deprecated -public class RouterFunctionMetrics { - - private final MeterRegistry registry; - - private final BiFunction> defaultTags; - - public RouterFunctionMetrics(MeterRegistry registry) { - Assert.notNull(registry, "Registry must not be null"); - this.registry = registry; - this.defaultTags = this::defaultTags; - } - - private RouterFunctionMetrics(MeterRegistry registry, - BiFunction> defaultTags) { - Assert.notNull(registry, "Registry must not be null"); - Assert.notNull(defaultTags, "DefaultTags must not be null"); - this.registry = registry; - this.defaultTags = defaultTags; - } - - private Iterable defaultTags(ServerRequest request, ServerResponse response) { - if (response == null) { - return Tags.of(getMethodTag(request)); - } - return Tags.of(getMethodTag(request), getStatusTag(response)); - } - - /** - * Returns a new {@link RouterFunctionMetrics} instance with the specified default - * tags. - * @param defaultTags Generate a list of tags to apply to the timer. - * {@code ServerResponse} may be null. - * @return {@code this} for further configuration - */ - public RouterFunctionMetrics defaultTags( - BiFunction> defaultTags) { - return new RouterFunctionMetrics(this.registry, defaultTags); - } - - public HandlerFilterFunction timer(String name) { - return timer(name, Tags.empty()); - } - - public HandlerFilterFunction timer(String name, - String... tags) { - return timer(name, Tags.of(tags)); - } - - public HandlerFilterFunction timer(String name, - Iterable tags) { - return new MetricsFilter(name, Tags.of(tags)); - } - - /** - * Creates a {@code method} tag from the method of the given {@code request}. - * @param request The HTTP request. - * @return A "method" tag whose value is a capitalized method (e.g. GET). - */ - public static Tag getMethodTag(ServerRequest request) { - return Tag.of("method", request.method().toString()); - } - - /** - * Creates a {@code status} tag from the status of the given {@code response}. - * @param response The HTTP response. - * @return A "status" tag whose value is the numeric status code. - */ - public static Tag getStatusTag(ServerResponse response) { - return Tag.of("status", response.statusCode().toString()); - } - - /** - * {@link HandlerFilterFunction} to handle calling micrometer. - */ - private class MetricsFilter - implements HandlerFilterFunction { - - private final String name; - - private final Tags tags; - - MetricsFilter(String name, Tags tags) { - this.name = name; - this.tags = tags; - } - - @Override - public Mono filter(ServerRequest request, - HandlerFunction next) { - long start = System.nanoTime(); - return next.handle(request) - .doOnSuccess((response) -> timer(start, request, response)) - .doOnError((error) -> timer(start, request, null)); - } - - private Iterable getDefaultTags(ServerRequest request, - ServerResponse response) { - return RouterFunctionMetrics.this.defaultTags.apply(request, response); - } - - private void timer(long start, ServerRequest request, ServerResponse response) { - Tags allTags = this.tags.and(getDefaultTags(request, response)); - RouterFunctionMetrics.this.registry.timer(this.name, allTags) - .record(System.nanoTime() - start, TimeUnit.NANOSECONDS); - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java index 567cddc869f6..fafcb01ee5c6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.couchbase; import java.util.List; -import java.util.function.BiFunction; import com.couchbase.client.core.env.KeyValueServiceConfig; import com.couchbase.client.core.env.QueryServiceConfig; @@ -29,7 +28,6 @@ import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Endpoints; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Endpoints.CouchbaseService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; @@ -129,25 +127,14 @@ protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder( return builder; } - @SuppressWarnings("deprecation") private QueryServiceConfig getQueryServiceConfig(Endpoints endpoints) { - return getServiceConfig(endpoints.getQueryservice(), endpoints.getQuery(), - QueryServiceConfig::create); + return QueryServiceConfig.create(endpoints.getQueryservice().getMinEndpoints(), + endpoints.getQueryservice().getMaxEndpoints()); } - @SuppressWarnings("deprecation") private ViewServiceConfig getViewServiceConfig(Endpoints endpoints) { - return getServiceConfig(endpoints.getViewservice(), endpoints.getView(), - ViewServiceConfig::create); - } - - private T getServiceConfig(CouchbaseService service, Integer fallback, - BiFunction factory) { - if (service.getMinEndpoints() != 1 || service.getMaxEndpoints() != 1) { - return factory.apply(service.getMinEndpoints(), service.getMaxEndpoints()); - } - int endpoints = (fallback != null ? fallback : 1); - return factory.apply(endpoints, endpoints); + return ViewServiceConfig.create(endpoints.getViewservice().getMinEndpoints(), + endpoints.getViewservice().getMaxEndpoints()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java index 62c0b5c60558..1591b1732631 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java @@ -20,7 +20,6 @@ import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.util.StringUtils; /** @@ -128,16 +127,6 @@ public static class Endpoints { */ private final CouchbaseService viewservice = new CouchbaseService(); - /** - * Number of sockets per node against the query (N1QL) service. - */ - private Integer query; - - /** - * Number of sockets per node against the view service. - */ - private Integer view; - public int getKeyValue() { return this.keyValue; } @@ -146,32 +135,10 @@ public void setKeyValue(int keyValue) { this.keyValue = keyValue; } - @Deprecated - @DeprecatedConfigurationProperty(replacement = "spring.couchbase.env.endpoints.queryservice.max-endpoints") - public Integer getQuery() { - return this.query; - } - - @Deprecated - public void setQuery(Integer query) { - this.query = query; - } - public CouchbaseService getQueryservice() { return this.queryservice; } - @Deprecated - @DeprecatedConfigurationProperty(replacement = "spring.couchbase.env.endpoints.viewservice.max-endpoints") - public Integer getView() { - return this.view; - } - - @Deprecated - public void setView(Integer view) { - this.view = view; - } - public CouchbaseService getViewservice() { return this.viewservice; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateSettings.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateSettings.java index 8b21be88dbe0..f1f560fc12b7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateSettings.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateSettings.java @@ -37,18 +37,6 @@ public HibernateSettings ddlAuto(Supplier ddlAuto) { return this; } - /** - * Specify the default ddl auto value to use. - * @param ddlAuto the default ddl auto if none is provided - * @return this instance - * @see #ddlAuto(Supplier) - * @deprecated as of 2.0.1 in favour of {@link #ddlAuto(Supplier)} - */ - @Deprecated - public HibernateSettings ddlAuto(String ddlAuto) { - return ddlAuto(() -> ddlAuto); - } - public String getDdlAuto() { return (this.ddlAuto != null ? this.ddlAuto.get() : null); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java index 411131ea6918..9471a68249aa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java @@ -96,18 +96,6 @@ public void customizeEnvEndpoints() { "spring.couchbase.env.endpoints.viewservice.max-endpoints=6"); } - @Test - @Deprecated - public void customizeEnvEndpointsWithDeprecatedProperties() { - testCouchbaseEnv((env) -> { - assertThat(env.queryServiceConfig().minEndpoints()).isEqualTo(3); - assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(3); - assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(4); - assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(4); - }, "spring.couchbase.env.endpoints.query=3", - "spring.couchbase.env.endpoints.view=4"); - } - @Test public void customizeEnvEndpointsUsesNewInfrastructure() { testCouchbaseEnv((env) -> { @@ -115,10 +103,8 @@ public void customizeEnvEndpointsUsesNewInfrastructure() { assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(5); assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(4); assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(6); - }, "spring.couchbase.env.endpoints.query=33", - "spring.couchbase.env.endpoints.queryservice.min-endpoints=3", + }, "spring.couchbase.env.endpoints.queryservice.min-endpoints=3", "spring.couchbase.env.endpoints.queryservice.max-endpoints=5", - "spring.couchbase.env.endpoints.view=44", "spring.couchbase.env.endpoints.viewservice.min-endpoints=4", "spring.couchbase.env.endpoints.viewservice.max-endpoints=6"); } @@ -130,9 +116,7 @@ public void customizeEnvEndpointsUsesNewInfrastructureWithOnlyMax() { assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(5); assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(1); assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(6); - }, "spring.couchbase.env.endpoints.query=33", - "spring.couchbase.env.endpoints.queryservice.max-endpoints=5", - "spring.couchbase.env.endpoints.view=44", + }, "spring.couchbase.env.endpoints.queryservice.max-endpoints=5", "spring.couchbase.env.endpoints.viewservice.max-endpoints=6"); } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java deleted file mode 100644 index 0d6e87358c66..000000000000 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/util/EnvironmentTestUtils.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2012-2018 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.test.util; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; - -/** - * Test utilities for setting environment values. - * - * @author Dave Syer - * @author Stephane Nicoll - * @since 1.4.0 - * @deprecated since 2.0.0 in favor of {@link TestPropertyValues} - */ -@Deprecated -public abstract class EnvironmentTestUtils { - - /** - * Add additional (high priority) values to an {@link Environment} owned by an - * {@link ApplicationContext}. Name-value pairs can be specified with colon (":") or - * equals ("=") separators. - * @param context the context with an environment to modify - * @param pairs the name:value pairs - */ - public static void addEnvironment(ConfigurableApplicationContext context, - String... pairs) { - addEnvironment(context.getEnvironment(), pairs); - } - - /** - * Add additional (high priority) values to an {@link Environment}. Name-value pairs - * can be specified with colon (":") or equals ("=") separators. - * @param environment the environment to modify - * @param pairs the name:value pairs - */ - public static void addEnvironment(ConfigurableEnvironment environment, - String... pairs) { - addEnvironment("test", environment, pairs); - } - - /** - * Add additional (high priority) values to an {@link Environment}. Name-value pairs - * can be specified with colon (":") or equals ("=") separators. - * @param environment the environment to modify - * @param name the property source name - * @param pairs the name:value pairs - */ - public static void addEnvironment(String name, ConfigurableEnvironment environment, - String... pairs) { - MutablePropertySources sources = environment.getPropertySources(); - Map map = getOrAdd(sources, name); - for (String pair : pairs) { - int index = getSeparatorIndex(pair); - String key = (index > 0 ? pair.substring(0, index) : pair); - String value = (index > 0 ? pair.substring(index + 1) : ""); - map.put(key.trim(), value.trim()); - } - } - - @SuppressWarnings("unchecked") - private static Map getOrAdd(MutablePropertySources sources, - String name) { - if (sources.contains(name)) { - return (Map) sources.get(name).getSource(); - } - Map map = new HashMap<>(); - sources.addFirst(new MapPropertySource(name, map)); - return map; - } - - private static int getSeparatorIndex(String pair) { - int colonIndex = pair.indexOf(':'); - int equalIndex = pair.indexOf('='); - if (colonIndex == -1) { - return equalIndex; - } - if (equalIndex == -1) { - return colonIndex; - } - return Math.min(colonIndex, equalIndex); - } - -} diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/util/EnvironmentTestUtilsTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/util/EnvironmentTestUtilsTests.java deleted file mode 100644 index 4b57d281bb37..000000000000 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/util/EnvironmentTestUtilsTests.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2012-2017 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.test.util; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Test; - -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.StandardEnvironment; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link EnvironmentTestUtils}. - * - * @author Stephane Nicoll - */ -@Deprecated -public class EnvironmentTestUtilsTests { - - private final ConfigurableEnvironment environment = new StandardEnvironment(); - - @Test - public void addSimplePairEqual() { - testAddSimplePair("my.foo", "bar", "="); - } - - @Test - public void addSimplePairColon() { - testAddSimplePair("my.foo", "bar", ":"); - } - - @Test - public void addSimplePairEqualWithEqualInValue() { - testAddSimplePair("my.foo", "b=ar", "="); - } - - @Test - public void addSimplePairEqualWithColonInValue() { - testAddSimplePair("my.foo", "b:ar", "="); - } - - @Test - public void addSimplePairColonWithColonInValue() { - testAddSimplePair("my.foo", "b:ar", ":"); - } - - @Test - public void addSimplePairColonWithEqualInValue() { - testAddSimplePair("my.foo", "b=ar", ":"); - } - - @Test - public void addPairNoValue() { - String propertyName = "my.foo+bar"; - assertThat(this.environment.containsProperty(propertyName)).isFalse(); - EnvironmentTestUtils.addEnvironment(this.environment, propertyName); - assertThat(this.environment.containsProperty(propertyName)).isTrue(); - assertThat(this.environment.getProperty(propertyName)).isEqualTo(""); - } - - private void testAddSimplePair(String key, String value, String delimiter) { - assertThat(this.environment.containsProperty(key)).isFalse(); - EnvironmentTestUtils.addEnvironment(this.environment, key + delimiter + value); - assertThat(this.environment.getProperty(key)).isEqualTo(value); - } - - @Test - public void testConfigHasHigherPrecedence() { - Map map = new HashMap<>(); - map.put("my.foo", "bar"); - MapPropertySource source = new MapPropertySource("sample", map); - this.environment.getPropertySources().addFirst(source); - assertThat(this.environment.getProperty("my.foo")).isEqualTo("bar"); - EnvironmentTestUtils.addEnvironment(this.environment, "my.foo=bar2"); - assertThat(this.environment.getProperty("my.foo")).isEqualTo("bar2"); - } - -} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index e530d7d87864..07e1fb1eef62 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -932,17 +932,6 @@ public void setMainApplicationClass(Class mainApplicationClass) { this.mainApplicationClass = mainApplicationClass; } - /** - * Returns whether this {@link SpringApplication} is running within a web environment. - * @return {@code true} if running within a web environment, otherwise {@code false}. - * @see #setWebEnvironment(boolean) - * @deprecated since 2.0.0 in favor of {@link #getWebApplicationType()} - */ - @Deprecated - public boolean isWebEnvironment() { - return this.webApplicationType == WebApplicationType.SERVLET; - } - /** * Returns the type of web application that is being run. * @return the type of web application @@ -952,19 +941,6 @@ public WebApplicationType getWebApplicationType() { return this.webApplicationType; } - /** - * Sets if this application is running within a web environment. If not specified will - * attempt to deduce the environment based on the classpath. - * @param webEnvironment if the application is running in a web environment - * @deprecated since 2.0.0 in favor of - * {@link #setWebApplicationType(WebApplicationType)} - */ - @Deprecated - public void setWebEnvironment(boolean webEnvironment) { - this.webApplicationType = (webEnvironment ? WebApplicationType.SERVLET - : WebApplicationType.NONE); - } - /** * Sets the type of web application to be run. If not explicitly set the type of web * application will be deduced based on the classpath. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java index add5881052bd..3d4c07157bb8 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java @@ -288,19 +288,6 @@ public SpringApplicationBuilder sources(Class... sources) { return this; } - /** - * Flag to explicitly request a web or non-web environment (auto detected based on - * classpath if not set). - * @param webEnvironment the flag to set - * @return the current builder - * @deprecated since 2.0.0 in favour of {@link #web(WebApplicationType)} - */ - @Deprecated - public SpringApplicationBuilder web(boolean webEnvironment) { - this.application.setWebEnvironment(webEnvironment); - return this; - } - /** * Flag to explicitly request a specific type of web application. Auto-detected based * on the classpath if not set. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactory.java index c44b8bfe2203..00ce07717d98 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactory.java @@ -17,9 +17,7 @@ package org.springframework.boot.web.servlet.server; import java.io.File; -import java.io.UnsupportedEncodingException; import java.net.URL; -import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; @@ -282,23 +280,6 @@ protected final List getUrlsOfJarsWithMetaInfResources() { return this.staticResourceJars.getUrls(); } - /** - * Converts the given {@code url} into a decoded file path. - * @param url the url to convert - * @return the file path - * @deprecated Since 2.0.2 in favor of {@link File#File(java.net.URI)} - */ - @Deprecated - protected final String getDecodedFile(URL url) { - try { - return URLDecoder.decode(url.getFile(), "UTF-8"); - } - catch (UnsupportedEncodingException ex) { - throw new IllegalStateException( - "Failed to decode '" + url.getFile() + "' using UTF-8"); - } - } - protected final File getValidSessionStoreDir() { return getValidSessionStoreDir(true); } From 3702da4573fde4a06bcc25f731e256a2a2b68940 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 25 May 2018 23:52:38 -0700 Subject: [PATCH 077/701] Formatting --- ...eReactiveHealthIndicatorConfiguration.java | 4 +- .../HealthIndicatorAutoConfiguration.java | 8 +- .../metrics/PropertiesMeterFilter.java | 8 +- ...loudFoundryWebEndpointDiscovererTests.java | 4 +- .../HealthEndpointDocumentationTests.java | 14 +- .../HealthEndpointWebExtensionTests.java | 123 +++++++++--------- ...activeHealthEndpointWebExtensionTests.java | 7 +- ...ricsAutoConfigurationIntegrationTests.java | 5 +- .../boot/actuate/cache/CachesEndpoint.java | 4 +- .../health/CompositeHealthIndicator.java | 18 ++- .../CompositeHealthIndicatorFactory.java | 4 +- .../CompositeReactiveHealthIndicator.java | 4 +- .../DefaultHealthIndicatorRegistry.java | 7 +- ...efaultReactiveHealthIndicatorRegistry.java | 4 +- .../health/HealthEndpointWebExtension.java | 4 +- .../health/HealthIndicatorRegistry.java | 25 ++-- .../HealthIndicatorRegistryFactory.java | 6 +- .../ReactiveHealthIndicatorRegistry.java | 21 ++- ...CompositeReactiveHealthIndicatorTests.java | 22 ++-- ...tReactiveHealthIndicatorRegistryTests.java | 8 +- .../actuate/health/HealthEndpointTests.java | 12 +- .../HealthEndpointWebIntegrationTests.java | 13 +- .../HealthWebEndpointResponseMapperTests.java | 21 +-- ...veHealthIndicatorRegistryFactoryTests.java | 12 +- .../rest/RestClientBuilderCustomizer.java | 1 + .../rest/RestClientProperties.java | 3 +- .../jest/JestAutoConfigurationTests.java | 11 +- .../RestClientAutoConfigurationTests.java | 2 + .../LiquibaseAutoConfigurationTests.java | 4 +- .../WebMvcTestPageableIntegrationTests.java | 3 +- .../boot/maven/AbstractRunMojo.java | 6 +- .../boot/maven/RepackageMojo.java | 6 +- 32 files changed, 195 insertions(+), 199 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java index 5acd02925e9d..748c80bc8397 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/CompositeReactiveHealthIndicatorConfiguration.java @@ -44,8 +44,8 @@ protected ReactiveHealthIndicator createHealthIndicator(Map beans) { return createHealthIndicator(beans.values().iterator().next()); } ReactiveHealthIndicatorRegistry registry = new DefaultReactiveHealthIndicatorRegistry(); - beans.forEach((name, source) -> registry.register(name, - createHealthIndicator(source))); + beans.forEach( + (name, source) -> registry.register(name, createHealthIndicator(source))); return new CompositeReactiveHealthIndicator(this.healthAggregator, registry); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java index 43ac74cbf98e..f9357967d1a5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java @@ -89,9 +89,11 @@ static class ReactiveHealthIndicatorConfiguration { public ReactiveHealthIndicatorRegistry reactiveHealthIndicatorRegistry( ObjectProvider> reactiveHealthIndicators, ObjectProvider> healthIndicators) { - return new ReactiveHealthIndicatorRegistryFactory().createReactiveHealthIndicatorRegistry( - reactiveHealthIndicators.getIfAvailable(Collections::emptyMap), - healthIndicators.getIfAvailable(Collections::emptyMap)); + return new ReactiveHealthIndicatorRegistryFactory() + .createReactiveHealthIndicatorRegistry( + reactiveHealthIndicators + .getIfAvailable(Collections::emptyMap), + healthIndicators.getIfAvailable(Collections::emptyMap)); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java index 85b40cab78b4..01a60810fd1e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/PropertiesMeterFilter.java @@ -57,10 +57,12 @@ public PropertiesMeterFilter(MetricsProperties properties) { private static MeterFilter createMapFilter(Map tags) { if (tags.isEmpty()) { - return new MeterFilter() { }; + return new MeterFilter() { + }; } - Tags commonTags = Tags.of(tags.entrySet().stream().map((entry) -> - Tag.of(entry.getKey(), entry.getValue())).collect(Collectors.toList())); + Tags commonTags = Tags.of(tags.entrySet().stream() + .map((entry) -> Tag.of(entry.getKey(), entry.getValue())) + .collect(Collectors.toList())); return MeterFilter.commonTags(commonTags); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 2d381360f5f0..1e7719770028 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -73,8 +73,8 @@ private WebOperation findMainReadOperation(ExposableWebEndpoint endpoint) { return operation; } } - throw new IllegalStateException("No main read operation found from " - + endpoint.getOperations()); + throw new IllegalStateException( + "No main read operation found from " + endpoint.getOperations()); } private void load(Class configuration, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 2e51aabb7c6e..3b66e3d564cd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -61,8 +61,7 @@ public class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentati fieldWithPath("status") .description("Status of a specific part of the application"), subsectionWithPath("details").description( - "Details of the health of a specific part of the" - + " application.")); + "Details of the health of a specific part of the" + " application.")); @Test public void health() throws Exception { @@ -111,18 +110,17 @@ public DiskSpaceHealthIndicator diskSpaceHealthIndicator() { } @Bean - public DataSourceHealthIndicator dbHealthIndicator( - DataSource dataSource) { + public DataSourceHealthIndicator dbHealthIndicator(DataSource dataSource) { return new DataSourceHealthIndicator(dataSource); } @Bean public CompositeHealthIndicator brokerHealthIndicator() { Map indicators = new LinkedHashMap<>(); - indicators.put("us1", () -> Health.up().withDetail("version", "1.0.2") - .build()); - indicators.put("us2", () -> Health.up().withDetail("version", "1.0.4") - .build()); + indicators.put("us1", + () -> Health.up().withDetail("version", "1.0.2").build()); + indicators.put("us2", + () -> Health.up().withDetail("version", "1.0.4").build()); return new CompositeHealthIndicator(new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry(indicators)); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java index 13f7e612e9de..625c3b7989f7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java @@ -53,8 +53,7 @@ public class HealthEndpointWebExtensionTests { private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withUserConfiguration(HealthIndicatorsConfiguration.class) - .withConfiguration( + .withUserConfiguration(HealthIndicatorsConfiguration.class).withConfiguration( AutoConfigurations.of(HealthIndicatorAutoConfiguration.class, HealthEndpointAutoConfiguration.class)); @@ -96,8 +95,9 @@ public void unauthenticatedUsersAreNotShownDetailsByDefault() { this.contextRunner.run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertThat(extension.health(mock(SecurityContext.class)).getBody() - .getDetails()).isEmpty(); + assertThat( + extension.health(mock(SecurityContext.class)).getBody().getDetails()) + .isEmpty(); }); } @@ -124,9 +124,8 @@ public void authenticatedUsersWhenAuthorizedCanBeShownDetails() { SecurityContext securityContext = mock(SecurityContext.class); given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); - assertThat( - extension.health(securityContext).getBody().getDetails()) - .isNotEmpty(); + assertThat(extension.health(securityContext).getBody().getDetails()) + .isNotEmpty(); }); } @@ -165,9 +164,8 @@ public void detailsCanBeHiddenFromUnauthorizedUsers() { given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); - assertThat( - extension.health(securityContext).getBody().getDetails()) - .isEmpty(); + assertThat(extension.health(securityContext).getBody().getDetails()) + .isEmpty(); }); } @@ -182,9 +180,8 @@ public void detailsCanBeShownToAuthorizedUsers() { given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); - assertThat( - extension.health(securityContext).getBody().getDetails()) - .isNotEmpty(); + assertThat(extension.health(securityContext).getBody().getDetails()) + .isNotEmpty(); }); } @@ -193,8 +190,8 @@ public void unauthenticatedUsersAreNotShownComponentByDefault() { this.contextRunner.run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertDetailsNotFound(extension.healthForComponent( - mock(SecurityContext.class), "simple")); + assertDetailsNotFound( + extension.healthForComponent(mock(SecurityContext.class), "simple")); }); } @@ -205,8 +202,8 @@ public void authenticatedUsersAreNotShownComponentByDefault() { .getBean(HealthEndpointWebExtension.class); SecurityContext securityContext = mock(SecurityContext.class); given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); - assertDetailsNotFound(extension.healthForComponent(securityContext, - "simple")); + assertDetailsNotFound( + extension.healthForComponent(securityContext, "simple")); }); } @@ -221,8 +218,8 @@ public void authenticatedUsersWhenAuthorizedCanBeShownComponent() { SecurityContext securityContext = mock(SecurityContext.class); given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); - assertSimpleComponent(extension.healthForComponent( - securityContext, "simple")); + assertSimpleComponent( + extension.healthForComponent(securityContext, "simple")); }); } @@ -244,8 +241,8 @@ public void componentCanBeHiddenFromAuthenticatedUsers() { .run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertDetailsNotFound(extension.healthForComponent( - mock(SecurityContext.class), "simple")); + assertDetailsNotFound(extension + .healthForComponent(mock(SecurityContext.class), "simple")); }); } @@ -254,15 +251,15 @@ public void componentCanBeHiddenFromUnauthorizedUsers() { this.contextRunner.withPropertyValues( "management.endpoint.health.show-details=when-authorized", "management.endpoint.health.roles=ACTUATOR").run((context) -> { - HealthEndpointWebExtension extension = context - .getBean(HealthEndpointWebExtension.class); - SecurityContext securityContext = mock(SecurityContext.class); - given(securityContext.getPrincipal()) - .willReturn(mock(Principal.class)); - given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); - assertDetailsNotFound(extension.healthForComponent(securityContext, - "simple")); - }); + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); + assertDetailsNotFound( + extension.healthForComponent(securityContext, "simple")); + }); } @Test @@ -270,15 +267,15 @@ public void componentCanBeShownToAuthorizedUsers() { this.contextRunner.withPropertyValues( "management.endpoint.health.show-details=when-authorized", "management.endpoint.health.roles=ACTUATOR").run((context) -> { - HealthEndpointWebExtension extension = context - .getBean(HealthEndpointWebExtension.class); - SecurityContext securityContext = mock(SecurityContext.class); - given(securityContext.getPrincipal()) - .willReturn(mock(Principal.class)); - given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); - assertSimpleComponent(extension.healthForComponent(securityContext, - "simple")); - }); + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); + assertSimpleComponent( + extension.healthForComponent(securityContext, "simple")); + }); } @Test @@ -288,8 +285,8 @@ public void componentThatDoesNotExistMapTo404() { .run((context) -> { HealthEndpointWebExtension extension = context .getBean(HealthEndpointWebExtension.class); - assertDetailsNotFound(extension.healthForComponent(null, - "does-not-exist")); + assertDetailsNotFound( + extension.healthForComponent(null, "does-not-exist")); }); } @@ -360,15 +357,15 @@ public void componentInstanceCanBeHiddenFromUnauthorizedUsers() { this.contextRunner.withPropertyValues( "management.endpoint.health.show-details=when-authorized", "management.endpoint.health.roles=ACTUATOR").run((context) -> { - HealthEndpointWebExtension extension = context - .getBean(HealthEndpointWebExtension.class); - SecurityContext securityContext = mock(SecurityContext.class); - given(securityContext.getPrincipal()) - .willReturn(mock(Principal.class)); - given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); - assertDetailsNotFound(extension.healthForComponentInstance(securityContext, - "composite", "one")); - }); + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(false); + assertDetailsNotFound(extension.healthForComponentInstance( + securityContext, "composite", "one")); + }); } @Test @@ -376,15 +373,15 @@ public void componentInstanceCanBeShownToAuthorizedUsers() { this.contextRunner.withPropertyValues( "management.endpoint.health.show-details=when-authorized", "management.endpoint.health.roles=ACTUATOR").run((context) -> { - HealthEndpointWebExtension extension = context - .getBean(HealthEndpointWebExtension.class); - SecurityContext securityContext = mock(SecurityContext.class); - given(securityContext.getPrincipal()) - .willReturn(mock(Principal.class)); - given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); - assertSimpleComponent(extension.healthForComponentInstance(securityContext, - "composite", "one")); - }); + HealthEndpointWebExtension extension = context + .getBean(HealthEndpointWebExtension.class); + SecurityContext securityContext = mock(SecurityContext.class); + given(securityContext.getPrincipal()) + .willReturn(mock(Principal.class)); + given(securityContext.isUserInRole("ACTUATOR")).willReturn(true); + assertSimpleComponent(extension.healthForComponentInstance( + securityContext, "composite", "one")); + }); } @Test @@ -406,8 +403,7 @@ private void assertDetailsNotFound(WebEndpointResponse response) { private void assertSimpleComponent(WebEndpointResponse response) { assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); - assertThat(response.getBody().getDetails()).containsOnly( - entry("counter", 42)); + assertThat(response.getBody().getDetails()).containsOnly(entry("counter", 42)); } @Test @@ -421,9 +417,8 @@ public void roleCanBeCustomized() { given(securityContext.getPrincipal()) .willReturn(mock(Principal.class)); given(securityContext.isUserInRole("ADMIN")).willReturn(true); - assertThat( - extension.health(securityContext).getBody().getDetails()) - .isNotEmpty(); + assertThat(extension.health(securityContext).getBody().getDetails()) + .isNotEmpty(); }); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java index 873a4a61180e..f2bbde295404 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java @@ -220,12 +220,11 @@ public void roleCanBeCustomized() { @Test public void registryCanBeAltered() { - this.contextRunner - .withUserConfiguration(HealthIndicatorsConfiguration.class) + this.contextRunner.withUserConfiguration(HealthIndicatorsConfiguration.class) .withPropertyValues("management.endpoint.health.show-details=always") .run((context) -> { - ReactiveHealthIndicatorRegistry registry = context.getBean( - ReactiveHealthIndicatorRegistry.class); + ReactiveHealthIndicatorRegistry registry = context + .getBean(ReactiveHealthIndicatorRegistry.class); ReactiveHealthEndpointWebExtension extension = context .getBean(ReactiveHealthEndpointWebExtension.class); assertThat(extension.health(null).block().getBody().getDetails()) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java index 18999833803f..d185e9a0e697 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java @@ -58,13 +58,12 @@ public void propertyBasedMeterFilteringIsAutoConfigured() { @Test public void propertyBasedCommonTagsIsAutoConfigured() { this.contextRunner.withPropertyValues("management.metrics.tags.region=test", - "management.metrics.tags.origin=local") - .run((context) -> { + "management.metrics.tags.origin=local").run((context) -> { MeterRegistry registry = context.getBean(MeterRegistry.class); registry.counter("my.counter", "env", "qa"); assertThat(registry.find("my.counter").tags("env", "qa") .tags("region", "test").tags("origin", "local").counter()) - .isNotNull(); + .isNotNull(); }); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index afcdc0c8b427..62b5c43635b5 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -68,8 +68,8 @@ public CachesReport caches() { new CacheDescriptor(entry.getTarget())); }); Map cacheManagerDescriptors = new LinkedHashMap<>(); - descriptors.forEach((name, entries) -> - cacheManagerDescriptors.put(name, new CacheManagerDescriptor(entries))); + descriptors.forEach((name, entries) -> cacheManagerDescriptors.put(name, + new CacheManagerDescriptor(entries))); return new CachesReport(cacheManagerDescriptors); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java index 04cb30f35d05..804eb2be0250 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java @@ -45,11 +45,10 @@ public CompositeHealthIndicator(HealthAggregator healthAggregator) { } /** - * Create a new {@link CompositeHealthIndicator} from the specified - * indicators. + * Create a new {@link CompositeHealthIndicator} from the specified indicators. * @param healthAggregator the health aggregator - * @param indicators a map of {@link HealthIndicator HealthIndicators} with - * the key being used as an indicator name. + * @param indicators a map of {@link HealthIndicator HealthIndicators} with the key + * being used as an indicator name. * @deprecated since 2.1.0 in favour of * {@link #CompositeHealthIndicator(HealthAggregator, HealthIndicatorRegistry)} */ @@ -60,8 +59,8 @@ public CompositeHealthIndicator(HealthAggregator healthAggregator, } /** - * Create a new {@link CompositeHealthIndicator} from the indicators in the - * given {@code registry}. + * Create a new {@link CompositeHealthIndicator} from the indicators in the given + * {@code registry}. * @param healthAggregator the health aggregator * @param registry the registry of {@link HealthIndicator HealthIndicators}. */ @@ -72,12 +71,11 @@ public CompositeHealthIndicator(HealthAggregator healthAggregator, } /** - * Adds the given {@code healthIndicator}, associating it with the given - * {@code name}. + * Adds the given {@code healthIndicator}, associating it with the given {@code name}. * @param name the name of the indicator * @param indicator the indicator - * @throws IllegalStateException if an indicator with the given {@code name} - * is already registered. + * @throws IllegalStateException if an indicator with the given {@code name} is + * already registered. * @deprecated since 2.1.0 in favour of * {@link HealthIndicatorRegistry#register(String, HealthIndicator)} */ diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java index 8d0c44dac984..f6bcc96bcec0 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorFactory.java @@ -57,8 +57,8 @@ public CompositeHealthIndicator createHealthIndicator( Assert.notNull(healthIndicators, "HealthIndicators must not be null"); HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory( this.healthIndicatorNameFactory); - return new CompositeHealthIndicator( - healthAggregator, factory.createHealthIndicatorRegistry(healthIndicators)); + return new CompositeHealthIndicator(healthAggregator, + factory.createHealthIndicatorRegistry(healthIndicators)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java index a6d291fa6d98..e1c4858bb410 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicator.java @@ -91,8 +91,8 @@ public CompositeReactiveHealthIndicator(HealthAggregator healthAggregator, * @param name the name of the health indicator * @param indicator the health indicator to add * @return this instance - * @throws IllegalStateException if an indicator with the given {@code name} - * is already registered. + * @throws IllegalStateException if an indicator with the given {@code name} is + * already registered. * @deprecated since 2.1.0 in favour of * {@link ReactiveHealthIndicatorRegistry#register(String, ReactiveHealthIndicator)} */ diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java index a1296460479c..38b9cb7c7e01 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java @@ -43,10 +43,9 @@ public DefaultHealthIndicatorRegistry() { } /** - * Create a new {@link DefaultHealthIndicatorRegistry} from the specified - * indicators. - * @param healthIndicators a map of {@link HealthIndicator}s with the key - * being used as an indicator name. + * Create a new {@link DefaultHealthIndicatorRegistry} from the specified indicators. + * @param healthIndicators a map of {@link HealthIndicator}s with the key being used + * as an indicator name. */ public DefaultHealthIndicatorRegistry(Map healthIndicators) { Assert.notNull(healthIndicators, "HealthIndicators must not be null"); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java index 1b9d9145ebcc..4bc2aca31988 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java @@ -46,8 +46,8 @@ public DefaultReactiveHealthIndicatorRegistry() { /** * Create a new {@link DefaultReactiveHealthIndicatorRegistry} from the specified * indicators. - * @param healthIndicators a map of {@link HealthIndicator}s with the key - * being used as an indicator name. + * @param healthIndicators a map of {@link HealthIndicator}s with the key being used + * as an indicator name. */ public DefaultReactiveHealthIndicatorRegistry( Map healthIndicators) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java index ae3ac45c0958..82c4cf7ced57 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java @@ -65,8 +65,8 @@ public WebEndpointResponse healthForComponent(SecurityContext securityCo public WebEndpointResponse healthForComponentInstance( SecurityContext securityContext, @Selector String component, @Selector String instance) { - Supplier health = () -> this.delegate.healthForComponentInstance( - component, instance); + Supplier health = () -> this.delegate + .healthForComponentInstance(component, instance); return this.responseMapper.mapDetails(health, securityContext); } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java index b466b9479e56..9b4df6af9b68 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java @@ -31,36 +31,35 @@ public interface HealthIndicatorRegistry { /** - * Registers the given {@link HealthIndicator}, associating it with the - * given {@code name}. + * Registers the given {@link HealthIndicator}, associating it with the given + * {@code name}. * @param name the name of the indicator * @param healthIndicator the indicator - * @throws IllegalStateException if an indicator with the given {@code name} - * is already registered. + * @throws IllegalStateException if an indicator with the given {@code name} is + * already registered. */ void register(String name, HealthIndicator healthIndicator); /** - * Unregisters the {@link HealthIndicator} previously registered with the - * given {@code name}. + * Unregisters the {@link HealthIndicator} previously registered with the given + * {@code name}. * @param name the name of the indicator - * @return the unregistered indicator, or {@code null} if no indicator was - * found in the registry for the given {@code name}. + * @return the unregistered indicator, or {@code null} if no indicator was found in + * the registry for the given {@code name}. */ HealthIndicator unregister(String name); /** * Returns the {@link HealthIndicator} registered with the given {@code name}. * @param name the name of the indicator - * @return the health indicator, or {@code null} if no indicator was - * registered with the given {@code name}. + * @return the health indicator, or {@code null} if no indicator was registered with + * the given {@code name}. */ HealthIndicator get(String name); /** - * Returns a snapshot of the registered health indicators and their names. - * The contents of the map do not reflect subsequent changes to the - * registry. + * Returns a snapshot of the registered health indicators and their names. The + * contents of the map do not reflect subsequent changes to the registry. * @return the snapshot of registered health indicators */ Map getAll(); diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java index 6fff7a1ed2f3..4c2f2edc4a52 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistryFactory.java @@ -41,10 +41,8 @@ public HealthIndicatorRegistryFactory() { } /** - * Create a {@link HealthIndicatorRegistry} based on the specified health - * indicators. - * @param healthIndicators the {@link HealthIndicator} instances mapped by - * name + * Create a {@link HealthIndicatorRegistry} based on the specified health indicators. + * @param healthIndicators the {@link HealthIndicator} instances mapped by name * @return a {@link HealthIndicator} that delegates to the specified * {@code healthIndicators}. */ diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java index 1121cd332c21..41e905586138 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistry.java @@ -31,12 +31,12 @@ public interface ReactiveHealthIndicatorRegistry { /** - * Registers the given {@link ReactiveHealthIndicator}, associating it with the - * given {@code name}. + * Registers the given {@link ReactiveHealthIndicator}, associating it with the given + * {@code name}. * @param name the name of the indicator * @param healthIndicator the indicator - * @throws IllegalStateException if an indicator with the given {@code name} - * is already registered. + * @throws IllegalStateException if an indicator with the given {@code name} is + * already registered. */ void register(String name, ReactiveHealthIndicator healthIndicator); @@ -44,23 +44,22 @@ public interface ReactiveHealthIndicatorRegistry { * Unregisters the {@link ReactiveHealthIndicator} previously registered with the * given {@code name}. * @param name the name of the indicator - * @return the unregistered indicator, or {@code null} if no indicator was - * found in the registry for the given {@code name}. + * @return the unregistered indicator, or {@code null} if no indicator was found in + * the registry for the given {@code name}. */ ReactiveHealthIndicator unregister(String name); /** * Returns the {@link ReactiveHealthIndicator} registered with the given {@code name}. * @param name the name of the indicator - * @return the health indicator, or {@code null} if no indicator was - * registered with the given {@code name}. + * @return the health indicator, or {@code null} if no indicator was registered with + * the given {@code name}. */ ReactiveHealthIndicator get(String name); /** - * Returns a snapshot of the registered health indicators and their names. - * The contents of the map do not reflect subsequent changes to the - * registry. + * Returns a snapshot of the registered health indicators and their names. The + * contents of the map do not reflect subsequent changes to the registry. * @return the snapshot of registered health indicators */ Map getAll(); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java index 7e63f176d03e..95aa93eb25f2 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeReactiveHealthIndicatorTests.java @@ -45,7 +45,7 @@ public class CompositeReactiveHealthIndicatorTests { public void singleIndicator() { CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( this.healthAggregator, new DefaultReactiveHealthIndicatorRegistry( - Collections.singletonMap("test", () -> Mono.just(HEALTHY)))); + Collections.singletonMap("test", () -> Mono.just(HEALTHY)))); StepVerifier.create(indicator.health()).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.UP); assertThat(h.getDetails()).containsOnlyKeys("test"); @@ -64,9 +64,9 @@ public void longHealth() { new DefaultReactiveHealthIndicatorRegistry(indicators)); StepVerifier.withVirtualTime(indicator::health).expectSubscription() .thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> { - assertThat(h.getStatus()).isEqualTo(Status.UP); - assertThat(h.getDetails()).hasSize(50); - }).verifyComplete(); + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).hasSize(50); + }).verifyComplete(); } @@ -78,7 +78,7 @@ public void timeoutReachedUsesFallback() { CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( this.healthAggregator, new DefaultReactiveHealthIndicatorRegistry(indicators)) - .timeoutStrategy(100, UNKNOWN_HEALTH); + .timeoutStrategy(100, UNKNOWN_HEALTH); StepVerifier.create(indicator.health()).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.UP); assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); @@ -95,14 +95,14 @@ public void timeoutNotReached() { CompositeReactiveHealthIndicator indicator = new CompositeReactiveHealthIndicator( this.healthAggregator, new DefaultReactiveHealthIndicatorRegistry(indicators)) - .timeoutStrategy(20000, null); + .timeoutStrategy(20000, null); StepVerifier.withVirtualTime(indicator::health).expectSubscription() .thenAwait(Duration.ofMillis(10000)).consumeNextWith((h) -> { - assertThat(h.getStatus()).isEqualTo(Status.UP); - assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); - assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY); - assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY); - }).verifyComplete(); + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("slow", "fast"); + assertThat(h.getDetails().get("slow")).isEqualTo(HEALTHY); + assertThat(h.getDetails().get("fast")).isEqualTo(HEALTHY); + }).verifyComplete(); } static class TimeoutHealth implements ReactiveHealthIndicator { diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java index e8b4adc66c67..63aa766a5871 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistryTests.java @@ -47,10 +47,10 @@ public class DefaultReactiveHealthIndicatorRegistryTests { @Before public void setUp() { - given(this.one.health()).willReturn(Mono.just( - new Health.Builder().unknown().withDetail("1", "1").build())); - given(this.two.health()).willReturn(Mono.just( - new Health.Builder().unknown().withDetail("2", "2").build())); + given(this.one.health()).willReturn( + Mono.just(new Health.Builder().unknown().withDetail("1", "1").build())); + given(this.two.health()).willReturn( + Mono.just(new Health.Builder().unknown().withDetail("2", "2").build())); this.registry = new DefaultReactiveHealthIndicatorRegistry(); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index ca387000caee..2b5a56510bc3 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -59,8 +59,8 @@ public void statusAndFullDetailsAreExposed() { @Test public void statusForComponentIsExposed() { - HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( - Collections.singletonMap("test", one))); + HealthEndpoint endpoint = new HealthEndpoint( + createHealthIndicator(Collections.singletonMap("test", one))); Health health = endpoint.healthForComponent("test"); assertThat(health).isNotNull(); assertThat(health.getStatus()).isEqualTo(Status.UP); @@ -69,8 +69,8 @@ public void statusForComponentIsExposed() { @Test public void statusForUnknownComponentReturnNull() { - HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( - Collections.emptyMap())); + HealthEndpoint endpoint = new HealthEndpoint( + createHealthIndicator(Collections.emptyMap())); Health health = endpoint.healthForComponent("does-not-exist"); assertThat(health).isNull(); } @@ -79,7 +79,7 @@ public void statusForUnknownComponentReturnNull() { public void statusForComponentInstanceIsExposed() { CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( - Collections.singletonMap("sub", () -> Health.down().build()))); + Collections.singletonMap("sub", () -> Health.down().build()))); HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( Collections.singletonMap("test", compositeIndicator))); Health health = endpoint.healthForComponentInstance("test", "sub"); @@ -92,7 +92,7 @@ public void statusForComponentInstanceIsExposed() { public void statusForUnknownComponentInstanceReturnNull() { CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( - Collections.singletonMap("sub", () -> Health.down().build()))); + Collections.singletonMap("sub", () -> Health.down().build()))); HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( Collections.singletonMap("test", compositeIndicator))); Health health = endpoint.healthForComponentInstance("test", "does-not-exist"); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java index d8e90c59fb96..186c3af3b4ae 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java @@ -56,9 +56,9 @@ public void whenHealthIsDown503ResponseIsReturned() { registry.register("charlie", () -> Health.down().build()); try { client.get().uri("/actuator/health").exchange().expectStatus() - .isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody().jsonPath("status") - .isEqualTo("DOWN").jsonPath("details.alpha.status").isEqualTo("UP") - .jsonPath("details.bravo.status").isEqualTo("UP") + .isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody() + .jsonPath("status").isEqualTo("DOWN").jsonPath("details.alpha.status") + .isEqualTo("UP").jsonPath("details.bravo.status").isEqualTo("UP") .jsonPath("details.charlie.status").isEqualTo("DOWN"); } finally { @@ -71,9 +71,10 @@ public void whenHealthIndicatorIsRemovedResponseIsAltered() { HealthIndicatorRegistry registry = context.getBean(HealthIndicatorRegistry.class); HealthIndicator bravo = registry.unregister("bravo"); try { - client.get().uri("/actuator/health").exchange().expectStatus().isOk().expectBody() - .jsonPath("status").isEqualTo("UP").jsonPath("details.alpha.status") - .isEqualTo("UP").jsonPath("details.bravo.status").doesNotExist(); + client.get().uri("/actuator/health").exchange().expectStatus().isOk() + .expectBody().jsonPath("status").isEqualTo("UP") + .jsonPath("details.alpha.status").isEqualTo("UP") + .jsonPath("details.bravo.status").doesNotExist(); } finally { registry.register("bravo", bravo); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java index ef6de57a6114..3740db55c9f7 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java @@ -62,7 +62,8 @@ public void mapDetailsWithDisableDetailsDoesNotInvokeSupplier() { @Test public void mapDetailsWithUnauthorizedUserDoesNotInvokeSupplier() { - HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED); + HealthWebEndpointResponseMapper mapper = createMapper( + ShowDetails.WHEN_AUTHORIZED); Supplier supplier = mockSupplier(); SecurityContext securityContext = mockSecurityContext("USER"); WebEndpointResponse response = mapper.mapDetails(supplier, @@ -75,13 +76,15 @@ public void mapDetailsWithUnauthorizedUserDoesNotInvokeSupplier() { @Test public void mapDetailsWithAuthorizedUserInvokeSupplier() { - HealthWebEndpointResponseMapper mapper = createMapper(ShowDetails.WHEN_AUTHORIZED); + HealthWebEndpointResponseMapper mapper = createMapper( + ShowDetails.WHEN_AUTHORIZED); Supplier supplier = mockSupplier(); given(supplier.get()).willReturn(Health.down().build()); SecurityContext securityContext = mockSecurityContext("ACTUATOR"); WebEndpointResponse response = mapper.mapDetails(supplier, securityContext); - assertThat(response.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); + assertThat(response.getStatus()) + .isEqualTo(HttpStatus.SERVICE_UNAVAILABLE.value()); assertThat(response.getBody().getStatus()).isEqualTo(Status.DOWN); verify(supplier).get(); verify(securityContext).isUserInRole("ACTUATOR"); @@ -108,12 +111,12 @@ private Supplier mockSupplier() { private SecurityContext mockSecurityContext(String... roles) { List associatedRoles = Arrays.asList(roles); SecurityContext securityContext = mock(SecurityContext.class); - given(securityContext.getPrincipal()) - .willReturn(mock(Principal.class)); - given(securityContext.isUserInRole(anyString())).will((Answer) invocation -> { - String expectedRole = invocation.getArgument(0); - return associatedRoles.contains(expectedRole); - }); + given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); + given(securityContext.isUserInRole(anyString())) + .will((Answer) invocation -> { + String expectedRole = invocation.getArgument(0); + return associatedRoles.contains(expectedRole); + }); return securityContext; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java index 824d0d6180f5..dcb7b3a5bc91 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthIndicatorRegistryFactoryTests.java @@ -39,16 +39,18 @@ public class ReactiveHealthIndicatorRegistryFactoryTests { @Test public void defaultHealthIndicatorNameFactory() { - ReactiveHealthIndicatorRegistry registry = this.factory.createReactiveHealthIndicatorRegistry( - Collections.singletonMap("myHealthIndicator", () -> Mono.just(UP)), null); + ReactiveHealthIndicatorRegistry registry = this.factory + .createReactiveHealthIndicatorRegistry(Collections + .singletonMap("myHealthIndicator", () -> Mono.just(UP)), null); assertThat(registry.getAll()).containsOnlyKeys("my"); } @Test public void healthIndicatorIsAdapted() { - ReactiveHealthIndicatorRegistry registry = this.factory.createReactiveHealthIndicatorRegistry( - Collections.singletonMap("test", () -> Mono.just(UP)), - Collections.singletonMap("regular", () -> DOWN)); + ReactiveHealthIndicatorRegistry registry = this.factory + .createReactiveHealthIndicatorRegistry( + Collections.singletonMap("test", () -> Mono.just(UP)), + Collections.singletonMap("regular", () -> DOWN)); assertThat(registry.getAll()).containsOnlyKeys("test", "regular"); StepVerifier.create(registry.get("regular").health()).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.DOWN); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java index 8ed0f1f77719..69a5baa0296c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientBuilderCustomizer.java @@ -34,4 +34,5 @@ public interface RestClientBuilderCustomizer { * @param builder the builder to customize */ void customize(RestClientBuilder builder); + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java index 33d876b38484..7990bd829c88 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientProperties.java @@ -47,8 +47,6 @@ public class RestClientProperties { */ private String password; - - public List getUris() { return this.uris; } @@ -72,4 +70,5 @@ public String getPassword() { public void setPassword(String password) { this.password = password; } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java index 58aff9a82277..395b24e83a64 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfigurationTests.java @@ -72,8 +72,8 @@ public void close() { @Test public void jestClientOnLocalhostByDefault() { - this.contextRunner.run((context) -> - assertThat(context).hasSingleBean(JestClient.class)); + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(JestClient.class)); } @Test @@ -130,11 +130,12 @@ public void jestCanCommunicateWithElasticsearchInstance() { Map source = new HashMap<>(); source.put("a", "alpha"); source.put("b", "bravo"); - Index index = new Index.Builder(source).index("foo") - .type("bar").id("1").build(); + Index index = new Index.Builder(source).index("foo").type("bar") + .id("1").build(); execute(client, index); Get getRequest = new Get.Builder("foo", "1").build(); - assertThat(execute(client, getRequest).getResponseCode()).isEqualTo(200); + assertThat(execute(client, getRequest).getResponseCode()) + .isEqualTo(200); })); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java index e2bd0fed32d0..1fe8e2f7229f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -100,6 +100,7 @@ static class CustomRestClientConfiguration { public RestClient customRestClient() { return mock(RestClient.class); } + } @Configuration @@ -109,6 +110,7 @@ static class BuilderCustomizerConfiguration { public RestClientBuilderCustomizer myCustomizer() { return (builder) -> builder.setMaxRetryTimeoutMillis(42); } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index 3e9b2490ea0f..137ea6da095f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -181,15 +181,13 @@ public void overrideUser() { @Test public void overrideTestRollbackOnUpdate() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) - .withPropertyValues( - "spring.liquibase.test-rollback-on-update:true") + .withPropertyValues("spring.liquibase.test-rollback-on-update:true") .run((context) -> { SpringLiquibase liquibase = context.getBean(SpringLiquibase.class); assertThat(liquibase.isTestRollbackOnUpdate()).isTrue(); }); } - @Test public void changeLogDoesNotExist() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java index e1950a0ff6cc..cdb2651e35ac 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java @@ -43,8 +43,7 @@ public class WebMvcTestPageableIntegrationTests { @Test public void shouldSupportPageable() throws Exception { this.mvc.perform(get("/paged").param("page", "2").param("size", "42")) - .andExpect(status().isOk()) - .andExpect(content().string("2:42")); + .andExpect(status().isOk()).andExpect(content().string("2:42")); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 0c4d1f9d1cac..da9161a4f9f9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -267,7 +267,8 @@ protected void logDisabledFork() { + "]"); } if (hasWorkingDirectorySet()) { - getLog().warn("Fork mode disabled, ignoring working directory configuration"); + getLog().warn( + "Fork mode disabled, ignoring working directory configuration"); } } } @@ -475,7 +476,8 @@ private void addDependencies(List urls) private void logArguments(String message, String[] args) { if (getLog().isDebugEnabled()) { - getLog().debug(Arrays.stream(args).collect(Collectors.joining(" ", message, ""))); + getLog().debug( + Arrays.stream(args).collect(Collectors.joining(" ", message, ""))); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index f43fe800addb..031888f93b19 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -229,9 +229,9 @@ private void repackage() throws MojoExecutionException { } /** - * Return the source {@link Artifact} to repackage. If a classifier is specified - * and an artifact with that classifier exists, it is used. Otherwise, the main - * artifact is used. + * Return the source {@link Artifact} to repackage. If a classifier is specified and + * an artifact with that classifier exists, it is used. Otherwise, the main artifact + * is used. * @return the source artifact to repackage */ private Artifact getSourceArtifact() { From 68ffbafbae8f5902e64c8bf1d01eca34018db8c2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 26 May 2018 00:01:45 -0700 Subject: [PATCH 078/701] Fix checkstyle violations --- .../metrics/web/reactive/client/WebClientExchangeTags.java | 4 ++-- .../actuate/health/HealthWebEndpointResponseMapperTests.java | 2 +- .../boot/autoconfigure/ldap/LdapAutoConfigurationTests.java | 2 +- .../java/org/springframework/boot/maven/RepackageMojo.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index ca852e3d6bf4..22394d4e9675 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -67,7 +67,7 @@ public static Tag uri(ClientRequest request) { private static String extractPath(String url) { String path = url.replaceFirst("^https?://[^/]+/", ""); - return path.startsWith("/") ? path : "/" + path; + return (path.startsWith("/") ? path : "/" + path); } /** @@ -87,7 +87,7 @@ public static Tag status(ClientResponse response) { * @return the status tag */ public static Tag status(Throwable throwable) { - return throwable instanceof IOException ? IO_ERROR : CLIENT_ERROR; + return (throwable instanceof IOException ? IO_ERROR : CLIENT_ERROR); } /** diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java index 3740db55c9f7..97884a9d2c21 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java @@ -113,7 +113,7 @@ private SecurityContext mockSecurityContext(String... roles) { SecurityContext securityContext = mock(SecurityContext.class); given(securityContext.getPrincipal()).willReturn(mock(Principal.class)); given(securityContext.isUserInRole(anyString())) - .will((Answer) invocation -> { + .will((Answer) (invocation) -> { String expectedRole = invocation.getArgument(0); return associatedRoles.contains(expectedRole); }); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java index 9e54fd144a0f..160d43b06da5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ldap/LdapAutoConfigurationTests.java @@ -108,7 +108,7 @@ public void contextSourceWithExtraCustomization() { @Test public void templateExists() { this.contextRunner.withPropertyValues("spring.ldap.urls:ldap://localhost:389") - .run(context -> assertThat(context).hasSingleBean(LdapTemplate.class)); + .run((context) -> assertThat(context).hasSingleBean(LdapTemplate.class)); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 031888f93b19..3d0a699e75d9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -345,8 +345,8 @@ private void attachArtifact(Artifact source, File target) { this.classifier, target); } else { - String artifactId = this.classifier != null - ? "artifact with classifier " + this.classifier : "main artifact"; + String artifactId = (this.classifier != null + ? "artifact with classifier " + this.classifier : "main artifact"); getLog().info(String.format("Replacing %s %s", artifactId, source.getFile())); source.setFile(target); } From de01e7aad4f5f88c670df299d4d898a9d7f6f4df Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 24 May 2018 00:01:19 +0900 Subject: [PATCH 079/701] Polish See gh-13243 --- .../metrics/orm/jpa/HibernateMetricsAutoConfiguration.java | 2 +- .../autoconfigure/metrics/orm/jpa/package-info.java | 2 +- .../orm/jpa/HibernateMetricsAutoConfigurationTests.java | 7 +++---- .../health/HealthWebEndpointResponseMapperTests.java | 4 ++-- .../src/main/asciidoc/production-ready-features.adoc | 2 +- .../org/springframework/boot/maven/AbstractRunMojo.java | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java index 024e8278a063..4a7b1585b72e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -71,7 +71,7 @@ private void bindEntityManagerFactoryToRegistry(String beanName, } /** - * Get the name of a {@link EntityManagerFactory} based on its {@code beanName}. + * Get the name of an {@link EntityManagerFactory} based on its {@code beanName}. * @param beanName the name of the {@link EntityManagerFactory} bean * @return a name for the given entity manager factory */ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java index ecb620329144..42960c2cf8cb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for JDBC metrics. + * Auto-configuration for JPA metrics. */ package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java index fe123f35aae7..cc207e72a1c2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -128,7 +128,7 @@ public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFa .withUserConfiguration( NonHibernateEntityManagerFactoryConfiguration.class) .run((context) -> { - // ensure EntityManagerFactory is not an Hibernate SessionFactory + // ensure EntityManagerFactory is not a Hibernate SessionFactory assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class)) .isInstanceOf(PersistenceException.class); @@ -178,9 +178,8 @@ private LocalContainerEntityManagerFactoryBean createSessionFactory( DataSource ds) { Map jpaProperties = new HashMap<>(); jpaProperties.put("hibernate.generate_statistics", "true"); - EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder( - new HibernateJpaVendorAdapter(), jpaProperties, null); - return builder.dataSource(ds).packages(PACKAGE_CLASSES).build(); + return new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), + jpaProperties, null).dataSource(ds).packages(PACKAGE_CLASSES).build(); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java index 97884a9d2c21..7001ce84228a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthWebEndpointResponseMapperTests.java @@ -46,7 +46,7 @@ public class HealthWebEndpointResponseMapperTests { private final HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper(); - private Set autorizedRoles = Collections.singleton("ACTUATOR"); + private Set authorizedRoles = Collections.singleton("ACTUATOR"); @Test public void mapDetailsWithDisableDetailsDoesNotInvokeSupplier() { @@ -122,7 +122,7 @@ private SecurityContext mockSecurityContext(String... roles) { private HealthWebEndpointResponseMapper createMapper(ShowDetails showDetails) { return new HealthWebEndpointResponseMapper(this.statusHttpMapper, showDetails, - this.autorizedRoles); + this.authorizedRoles); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 045c2604a0f0..b002403a7770 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1809,7 +1809,7 @@ Auto-configuration enables the instrumentation of all available Hibernate Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from the bean name. -To enable statistics, the standardJPA property `hibernate.generate_statistics` must be +To enable statistics, the standard JPA property `hibernate.generate_statistics` must be set to `true`. You can enable that on the auto-configured `EntityManagerFactory` as shown in the following example: diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index da9161a4f9f9..14f1c6ef37e4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -318,7 +318,7 @@ protected RunArguments resolveApplicationArguments() { /** * Resolve the environment variables to use. - * @return a {@link EnvVariables} defining the environment variables + * @return an {@link EnvVariables} defining the environment variables */ protected EnvVariables resolveEnvVariables() { return new EnvVariables(this.environmentVariables); From 3f001899b4f1f71ea94fcba0c2a3f7310c30f6da Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 29 May 2018 17:51:01 +0200 Subject: [PATCH 080/701] Harmonize ssl properties for Kafka Closes gh-13239 --- .../autoconfigure/kafka/KafkaProperties.java | 48 +++++++++---------- .../kafka/KafkaAutoConfigurationTests.java | 36 +++++++------- .../appendix-application-properties.adoc | 48 +++++++++---------- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index 1788a8c7fdc0..5716bcffe8a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -823,12 +823,12 @@ public static class Ssl { /** * Location of the key store file. */ - private Resource keystoreLocation; + private Resource keyStoreLocation; /** * Store password for the key store file. */ - private String keystorePassword; + private String keyStorePassword; /** * Type of the key store. @@ -838,12 +838,12 @@ public static class Ssl { /** * Location of the trust store file. */ - private Resource truststoreLocation; + private Resource trustStoreLocation; /** * Store password for the trust store file. */ - private String truststorePassword; + private String trustStorePassword; /** * Type of the trust store. @@ -863,20 +863,20 @@ public void setKeyPassword(String keyPassword) { this.keyPassword = keyPassword; } - public Resource getKeystoreLocation() { - return this.keystoreLocation; + public Resource getKeyStoreLocation() { + return this.keyStoreLocation; } - public void setKeystoreLocation(Resource keystoreLocation) { - this.keystoreLocation = keystoreLocation; + public void setKeyStoreLocation(Resource keyStoreLocation) { + this.keyStoreLocation = keyStoreLocation; } - public String getKeystorePassword() { - return this.keystorePassword; + public String getKeyStorePassword() { + return this.keyStorePassword; } - public void setKeystorePassword(String keystorePassword) { - this.keystorePassword = keystorePassword; + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; } public String getKeyStoreType() { @@ -887,20 +887,20 @@ public void setKeyStoreType(String keyStoreType) { this.keyStoreType = keyStoreType; } - public Resource getTruststoreLocation() { - return this.truststoreLocation; + public Resource getTrustStoreLocation() { + return this.trustStoreLocation; } - public void setTruststoreLocation(Resource truststoreLocation) { - this.truststoreLocation = truststoreLocation; + public void setTrustStoreLocation(Resource trustStoreLocation) { + this.trustStoreLocation = trustStoreLocation; } - public String getTruststorePassword() { - return this.truststorePassword; + public String getTrustStorePassword() { + return this.trustStorePassword; } - public void setTruststorePassword(String truststorePassword) { - this.truststorePassword = truststorePassword; + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; } public String getTrustStoreType() { @@ -924,15 +924,15 @@ public Map buildProperties() { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this::getKeyPassword) .to(properties.in(SslConfigs.SSL_KEY_PASSWORD_CONFIG)); - map.from(this::getKeystoreLocation).as(this::resourceToPath) + map.from(this::getKeyStoreLocation).as(this::resourceToPath) .to(properties.in(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)); - map.from(this::getKeystorePassword) + map.from(this::getKeyStorePassword) .to(properties.in(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)); map.from(this::getKeyStoreType) .to(properties.in(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG)); - map.from(this::getTruststoreLocation).as(this::resourceToPath) + map.from(this::getTrustStoreLocation).as(this::resourceToPath) .to(properties.in(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)); - map.from(this::getTruststorePassword) + map.from(this::getTrustStorePassword) .to(properties.in(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)); map.from(this::getTrustStoreType) .to(properties.in(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 732fa3fd3e5a..3e91f1d12c67 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -75,12 +75,12 @@ public void consumerProperties() { "spring.kafka.properties.baz=qux", "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", "spring.kafka.ssl.key-password=p1", - "spring.kafka.ssl.keystore-location=classpath:ksLoc", - "spring.kafka.ssl.keystore-password=p2", - "spring.kafka.ssl.keystore-type=PKCS12", - "spring.kafka.ssl.truststore-location=classpath:tsLoc", - "spring.kafka.ssl.truststore-password=p3", - "spring.kafka.ssl.truststore-type=PKCS12", + "spring.kafka.ssl.key-store-location=classpath:ksLoc", + "spring.kafka.ssl.key-store-password=p2", + "spring.kafka.ssl.key-store-type=PKCS12", + "spring.kafka.ssl.trust-store-location=classpath:tsLoc", + "spring.kafka.ssl.trust-store-password=p3", + "spring.kafka.ssl.trust-store-type=PKCS12", "spring.kafka.ssl.protocol=TLSv1.2", "spring.kafka.consumer.auto-commit-interval=123", "spring.kafka.consumer.max-poll-records=42", @@ -166,12 +166,12 @@ public void producerProperties() { "spring.kafka.producer.retries=2", "spring.kafka.producer.properties.fiz.buz=fix.fox", "spring.kafka.producer.ssl.key-password=p4", - "spring.kafka.producer.ssl.keystore-location=classpath:ksLocP", - "spring.kafka.producer.ssl.keystore-password=p5", - "spring.kafka.producer.ssl.keystore-type=PKCS12", - "spring.kafka.producer.ssl.truststore-location=classpath:tsLocP", - "spring.kafka.producer.ssl.truststore-password=p6", - "spring.kafka.producer.ssl.truststore-type=PKCS12", + "spring.kafka.producer.ssl.key-store-location=classpath:ksLocP", + "spring.kafka.producer.ssl.key-store-password=p5", + "spring.kafka.producer.ssl.key-store-type=PKCS12", + "spring.kafka.producer.ssl.trust-store-location=classpath:tsLocP", + "spring.kafka.producer.ssl.trust-store-password=p6", + "spring.kafka.producer.ssl.trust-store-type=PKCS12", "spring.kafka.producer.ssl.protocol=TLSv1.2", "spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.IntegerSerializer") .run((context) -> { @@ -232,12 +232,12 @@ public void adminProperties() { "spring.kafka.admin.fail-fast=true", "spring.kafka.admin.properties.fiz.buz=fix.fox", "spring.kafka.admin.ssl.key-password=p4", - "spring.kafka.admin.ssl.keystore-location=classpath:ksLocP", - "spring.kafka.admin.ssl.keystore-password=p5", - "spring.kafka.admin.ssl.keystore-type=PKCS12", - "spring.kafka.admin.ssl.truststore-location=classpath:tsLocP", - "spring.kafka.admin.ssl.truststore-password=p6", - "spring.kafka.admin.ssl.truststore-type=PKCS12", + "spring.kafka.admin.ssl.key-store-location=classpath:ksLocP", + "spring.kafka.admin.ssl.key-store-password=p5", + "spring.kafka.admin.ssl.key-store-type=PKCS12", + "spring.kafka.admin.ssl.trust-store-location=classpath:tsLocP", + "spring.kafka.admin.ssl.trust-store-password=p6", + "spring.kafka.admin.ssl.trust-store-type=PKCS12", "spring.kafka.admin.ssl.protocol=TLSv1.2").run((context) -> { KafkaAdmin admin = context.getBean(KafkaAdmin.class); Map configs = admin.getConfig(); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 10d8267eafbd..76dc71da7593 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1002,13 +1002,13 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.admin.fail-fast=false # Whether to fail fast if the broker is not available on startup. spring.kafka.admin.properties.*= # Additional admin-specific properties used to configure the client. spring.kafka.admin.ssl.key-password= # Password of the private key in the key store file. - spring.kafka.admin.ssl.keystore-location= # Location of the key store file. - spring.kafka.admin.ssl.keystore-password= # Store password for the key store file. - spring.kafka.admin.ssl.keystore-type= # Type of the key store. + spring.kafka.admin.ssl.key-store-location= # Location of the key store file. + spring.kafka.admin.ssl.key-store-password= # Store password for the key store file. + spring.kafka.admin.ssl.key-store-type= # Type of the key store. spring.kafka.admin.ssl.protocol= # SSL protocol to use. - spring.kafka.admin.ssl.truststore-location= # Location of the trust store file. - spring.kafka.admin.ssl.truststore-password= # Store password for the trust store file. - spring.kafka.admin.ssl.truststore-type= # Type of the trust store. + spring.kafka.admin.ssl.trust-store-location= # Location of the trust store file. + spring.kafka.admin.ssl.trust-store-password= # Store password for the trust store file. + spring.kafka.admin.ssl.trust-store-type= # Type of the trust store. spring.kafka.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. spring.kafka.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.consumer.auto-commit-interval= # Frequency with which the consumer offsets are auto-committed to Kafka if 'enable.auto.commit' is set to true. @@ -1024,13 +1024,13 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.consumer.max-poll-records= # Maximum number of records returned in a single call to poll(). spring.kafka.consumer.properties.*= # Additional consumer-specific properties used to configure the client. spring.kafka.consumer.ssl.key-password= # Password of the private key in the key store file. - spring.kafka.consumer.ssl.keystore-location= # Location of the key store file. - spring.kafka.consumer.ssl.keystore-password= # Store password for the key store file. - spring.kafka.consumer.ssl.keystore-type= # Type of the key store. + spring.kafka.consumer.ssl.key-store-location= # Location of the key store file. + spring.kafka.consumer.ssl.key-store-password= # Store password for the key store file. + spring.kafka.consumer.ssl.key-store-type= # Type of the key store. spring.kafka.consumer.ssl.protocol= # SSL protocol to use. - spring.kafka.consumer.ssl.truststore-location= # Location of the trust store file. - spring.kafka.consumer.ssl.truststore-password= # Store password for the trust store file. - spring.kafka.consumer.ssl.truststore-type= # Type of the trust store. + spring.kafka.consumer.ssl.trust-store-location= # Location of the trust store file. + spring.kafka.consumer.ssl.trust-store-password= # Store password for the trust store file. + spring.kafka.consumer.ssl.trust-store-type= # Type of the trust store. spring.kafka.consumer.value-deserializer= # Deserializer class for values. spring.kafka.jaas.control-flag=required # Control flag for login configuration. spring.kafka.jaas.enabled=false # Whether to enable JAAS configuration. @@ -1057,24 +1057,24 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.producer.properties.*= # Additional producer-specific properties used to configure the client. spring.kafka.producer.retries= # When greater than zero, enables retrying of failed sends. spring.kafka.producer.ssl.key-password= # Password of the private key in the key store file. - spring.kafka.producer.ssl.keystore-location= # Location of the key store file. - spring.kafka.producer.ssl.keystore-password= # Store password for the key store file. - spring.kafka.producer.ssl.keystore-type= # Type of the key store. + spring.kafka.producer.ssl.key-store-location= # Location of the key store file. + spring.kafka.producer.ssl.key-store-password= # Store password for the key store file. + spring.kafka.producer.ssl.key-store-type= # Type of the key store. spring.kafka.producer.ssl.protocol= # SSL protocol to use. - spring.kafka.producer.ssl.truststore-location= # Location of the trust store file. - spring.kafka.producer.ssl.truststore-password= # Store password for the trust store file. - spring.kafka.producer.ssl.truststore-type= # Type of the trust store. + spring.kafka.producer.ssl.trust-store-location= # Location of the trust store file. + spring.kafka.producer.ssl.trust-store-password= # Store password for the trust store file. + spring.kafka.producer.ssl.trust-store-type= # Type of the trust store. spring.kafka.producer.transaction-id-prefix= # When non empty, enables transaction support for producer. spring.kafka.producer.value-serializer= # Serializer class for values. spring.kafka.properties.*= # Additional properties, common to producers and consumers, used to configure the client. spring.kafka.ssl.key-password= # Password of the private key in the key store file. - spring.kafka.ssl.keystore-location= # Location of the key store file. - spring.kafka.ssl.keystore-password= # Store password for the key store file. - spring.kafka.ssl.keystore-type= # Type of the key store. + spring.kafka.ssl.key-store-location= # Location of the key store file. + spring.kafka.ssl.key-store-password= # Store password for the key store file. + spring.kafka.ssl.key-store-type= # Type of the key store. spring.kafka.ssl.protocol= # SSL protocol to use. - spring.kafka.ssl.truststore-location= # Location of the trust store file. - spring.kafka.ssl.truststore-password= # Store password for the trust store file. - spring.kafka.ssl.truststore-type= # Type of the trust store. + spring.kafka.ssl.trust-store-location= # Location of the trust store file. + spring.kafka.ssl.trust-store-password= # Store password for the trust store file. + spring.kafka.ssl.trust-store-type= # Type of the trust store. spring.kafka.template.default-topic= # Default topic to which messages are sent. # RABBIT ({sc-spring-boot-autoconfigure}/amqp/RabbitProperties.{sc-ext}[RabbitProperties]) From 48a6abe2178c1959c2c2ab7051e3d5600f0efe91 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 30 May 2018 10:19:06 +0100 Subject: [PATCH 081/701] Polish --- .../spring-boot-dependencies}/.eclipse/eclipse.properties | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {spring-boot-dependencies => spring-boot-project/spring-boot-dependencies}/.eclipse/eclipse.properties (100%) diff --git a/spring-boot-dependencies/.eclipse/eclipse.properties b/spring-boot-project/spring-boot-dependencies/.eclipse/eclipse.properties similarity index 100% rename from spring-boot-dependencies/.eclipse/eclipse.properties rename to spring-boot-project/spring-boot-dependencies/.eclipse/eclipse.properties From bd9299dbf9a24427308ed3cb53f2b001bb053e35 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 30 May 2018 14:24:07 +0200 Subject: [PATCH 082/701] Add missing metadata for renamed SSL properties Closes gh-13239 --- ...itional-spring-configuration-metadata.json | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f385ef55b267..930e3988ca42 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1316,6 +1316,150 @@ "level": "error" } }, + { + "name": "spring.kafka.admin.ssl.keystore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the key store file.", + "deprecation": { + "replacement": "spring.kafka.admin.ssl.key-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.admin.ssl.keystore-password", + "type": "java.lang.String", + "description": "Store password for the key store file.", + "deprecation": { + "replacement": "spring.kafka.admin.ssl.key-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.admin.ssl.truststore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the trust store file.", + "deprecation": { + "replacement": "spring.kafka.admin.ssl.trust-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.admin.ssl.truststore-password", + "type": "java.lang.String", + "description": "Store password for the trust store file.", + "deprecation": { + "replacement": "spring.kafka.admin.ssl.trust-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.consumer.ssl.keystore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the key store file.", + "deprecation": { + "replacement": "spring.kafka.consumer.ssl.key-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.consumer.ssl.keystore-password", + "type": "java.lang.String", + "description": "Store password for the key store file.", + "deprecation": { + "replacement": "spring.kafka.consumer.ssl.key-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.consumer.ssl.truststore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the trust store file.", + "deprecation": { + "replacement": "spring.kafka.consumer.ssl.trust-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.consumer.ssl.truststore-password", + "type": "java.lang.String", + "description": "Store password for the trust store file.", + "deprecation": { + "replacement": "spring.kafka.consumer.ssl.trust-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.producer.ssl.keystore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the key store file.", + "deprecation": { + "replacement": "spring.kafka.producer.ssl.key-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.producer.ssl.keystore-password", + "type": "java.lang.String", + "description": "Store password for the key store file.", + "deprecation": { + "replacement": "spring.kafka.producer.ssl.key-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.producer.ssl.truststore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the trust store file.", + "deprecation": { + "replacement": "spring.kafka.producer.ssl.trust-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.producer.ssl.truststore-password", + "type": "java.lang.String", + "description": "Store password for the trust store file.", + "deprecation": { + "replacement": "spring.kafka.producer.ssl.trust-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.ssl.keystore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the key store file.", + "deprecation": { + "replacement": "spring.kafka.ssl.key-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.ssl.keystore-password", + "type": "java.lang.String", + "description": "Store password for the key store file.", + "deprecation": { + "replacement": "spring.kafka.ssl.key-store-password", + "level": "error" + } + }, + { + "name": "spring.kafka.ssl.truststore-location", + "type": "org.springframework.core.io.Resource", + "description": "Location of the trust store file.", + "deprecation": { + "replacement": "spring.kafka.ssl.trust-store-location", + "level": "error" + } + }, + { + "name": "spring.kafka.ssl.truststore-password", + "type": "java.lang.String", + "description": "Store password for the trust store file.", + "deprecation": { + "replacement": "spring.kafka.ssl.trust-store-password", + "level": "error" + } + }, { "name": "spring.messages.cache-seconds", "type": "java.lang.Integer", From f06627c40856f5b7778a872fd5c3bc6e2c9d1716 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 30 May 2018 16:09:07 +0200 Subject: [PATCH 083/701] Allow CompositeHealthIndicator to be created with a Map as before See gh-4965 --- .../HealthEndpointDocumentationTests.java | 3 +-- .../health/HealthEndpointWebExtensionTests.java | 3 +-- .../boot/actuate/health/CompositeHealthIndicator.java | 3 --- .../actuate/health/CompositeHealthIndicatorTests.java | 7 +++---- .../boot/actuate/health/HealthEndpointTests.java | 10 +++++----- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 3b66e3d564cd..2e9b8655e876 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -27,7 +27,6 @@ import org.junit.Test; import org.springframework.boot.actuate.health.CompositeHealthIndicator; -import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; @@ -122,7 +121,7 @@ public CompositeHealthIndicator brokerHealthIndicator() { indicators.put("us2", () -> Health.up().withDetail("version", "1.0.4").build()); return new CompositeHealthIndicator(new OrderedHealthAggregator(), - new DefaultHealthIndicatorRegistry(indicators)); + indicators); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java index 625c3b7989f7..9c7454502774 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java @@ -25,7 +25,6 @@ import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.health.CompositeHealthIndicator; -import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthEndpointWebExtension; import org.springframework.boot.actuate.health.HealthIndicator; @@ -436,7 +435,7 @@ public HealthIndicator compositeHealthIndicator() { nestedIndicators.put("one", simpleHealthIndicator()); nestedIndicators.put("two", () -> Health.up().build()); return new CompositeHealthIndicator(new OrderedHealthAggregator(), - new DefaultHealthIndicatorRegistry(nestedIndicators)); + nestedIndicators); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java index 804eb2be0250..999b57128a6b 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CompositeHealthIndicator.java @@ -49,10 +49,7 @@ public CompositeHealthIndicator(HealthAggregator healthAggregator) { * @param healthAggregator the health aggregator * @param indicators a map of {@link HealthIndicator HealthIndicators} with the key * being used as an indicator name. - * @deprecated since 2.1.0 in favour of - * {@link #CompositeHealthIndicator(HealthAggregator, HealthIndicatorRegistry)} */ - @Deprecated public CompositeHealthIndicator(HealthAggregator healthAggregator, Map indicators) { this(healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java index 69778a0c5439..4b24481ddc8a 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/CompositeHealthIndicatorTests.java @@ -63,7 +63,7 @@ public void createWithIndicators() { indicators.put("one", this.one); indicators.put("two", this.two); CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); + this.healthAggregator, indicators); Health result = composite.health(); assertThat(result.getDetails()).hasSize(2); assertThat(result.getDetails()).containsEntry("one", @@ -78,10 +78,9 @@ public void testSerialization() throws Exception { indicators.put("db1", this.one); indicators.put("db2", this.two); CompositeHealthIndicator innerComposite = new CompositeHealthIndicator( - this.healthAggregator, new DefaultHealthIndicatorRegistry(indicators)); + this.healthAggregator, indicators); CompositeHealthIndicator composite = new CompositeHealthIndicator( - this.healthAggregator, new DefaultHealthIndicatorRegistry( - Collections.singletonMap("db", innerComposite))); + this.healthAggregator, Collections.singletonMap("db", innerComposite)); Health result = composite.health(); ObjectMapper mapper = new ObjectMapper(); assertThat(mapper.writeValueAsString(result)).isEqualTo( diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index 2b5a56510bc3..788ce2b21fd4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -78,8 +78,8 @@ public void statusForUnknownComponentReturnNull() { @Test public void statusForComponentInstanceIsExposed() { CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( - new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( - Collections.singletonMap("sub", () -> Health.down().build()))); + new OrderedHealthAggregator(), + Collections.singletonMap("sub", () -> Health.down().build())); HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( Collections.singletonMap("test", compositeIndicator))); Health health = endpoint.healthForComponentInstance("test", "sub"); @@ -91,8 +91,8 @@ public void statusForComponentInstanceIsExposed() { @Test public void statusForUnknownComponentInstanceReturnNull() { CompositeHealthIndicator compositeIndicator = new CompositeHealthIndicator( - new OrderedHealthAggregator(), new DefaultHealthIndicatorRegistry( - Collections.singletonMap("sub", () -> Health.down().build()))); + new OrderedHealthAggregator(), + Collections.singletonMap("sub", () -> Health.down().build())); HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator( Collections.singletonMap("test", compositeIndicator))); Health health = endpoint.healthForComponentInstance("test", "does-not-exist"); @@ -110,7 +110,7 @@ public void statusForComponentInstanceThatIsNotACompositeReturnNull() { private HealthIndicator createHealthIndicator( Map healthIndicators) { return new CompositeHealthIndicator(new OrderedHealthAggregator(), - new DefaultHealthIndicatorRegistry(healthIndicators)); + healthIndicators); } } From 9f4a5c13a574f24c44288c3e378345f4ae1c42d5 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 30 May 2018 17:58:55 -0700 Subject: [PATCH 084/701] Add auto-config for WebFlux OAuth2 Login Closes gh-13142 --- .../client/ClientsConfiguredCondition.java | 63 ++++++++++ ...h2ClientPropertiesRegistrationAdapter.java | 2 +- .../security/oauth2/client/package-info.java | 2 +- ...ReactiveOAuth2ClientAutoConfiguration.java | 43 +++++++ ...ntRegistrationRepositoryConfiguration.java | 60 +++++++++ ...eactiveOAuth2WebSecurityConfiguration.java | 44 +++++++ .../oauth2/client/reactive/package-info.java | 20 +++ .../OAuth2ClientAutoConfiguration.java | 2 +- ...ntRegistrationRepositoryConfiguration.java | 54 +-------- .../OAuth2WebSecurityConfiguration.java | 2 +- .../oauth2/client/servlet/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 3 +- ...iveOAuth2ClientAutoConfigurationTests.java | 101 ++++++++++++++++ ...istrationRepositoryConfigurationTests.java | 65 ++++++++++ ...veOAuth2WebSecurityConfigurationTests.java | 114 ++++++++++++++++++ ...istrationRepositoryConfigurationTests.java | 2 +- .../OAuth2WebSecurityConfigurationTests.java | 2 +- .../main/asciidoc/spring-boot-features.adoc | 5 +- .../README.adoc | 12 ++ .../pom.xml | 59 +++++++++ .../oauth2/client/ExampleController.java | 32 +++++ ...SampleReactiveOAuth2ClientApplication.java | 29 +++++ .../src/main/resources/application.yml | 19 +++ ...eReactiveOAuth2ClientApplicationTests.java | 54 +++++++++ 24 files changed, 751 insertions(+), 58 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientAutoConfiguration.java (99%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientRegistrationRepositoryConfiguration.java (51%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2WebSecurityConfiguration.java (99%) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientRegistrationRepositoryConfigurationTests.java (99%) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2WebSecurityConfigurationTests.java (99%) create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java new file mode 100644 index 000000000000..fcdbd72e4f7b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client; + +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Condition that matches if any {@code spring.security.oauth2.client.registration} + * properties are defined. + */ +public class ClientsConfiguredCondition extends SpringBootCondition { + + private static final Bindable> BINDABLE_REGISTRATION = Bindable + .mapOf(String.class, OAuth2ClientProperties.Registration.class); + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ConditionMessage.Builder message = ConditionMessage + .forCondition("OAuth2 Clients Configured Condition"); + Map registrations = this + .getRegistrations(context.getEnvironment()); + if (!registrations.isEmpty()) { + return ConditionOutcome.match(message + .foundExactly("registered clients " + registrations.values().stream() + .map(OAuth2ClientProperties.Registration::getClientId) + .collect(Collectors.joining(", ")))); + } + return ConditionOutcome.noMatch(message.notAvailable("registered clients")); + } + + private Map getRegistrations( + Environment environment) { + return Binder.get(environment) + .bind("spring.security.oauth2.client.registration", BINDABLE_REGISTRATION) + .orElse(Collections.emptyMap()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index b0a76ddb2bbc..ec4518d9e9f7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -39,7 +39,7 @@ * @author Thiago Hirata * @since 2.0.0 */ -final class OAuth2ClientPropertiesRegistrationAdapter { +public final class OAuth2ClientPropertiesRegistrationAdapter { private OAuth2ClientPropertiesRegistrationAdapter() { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java index 6437a3e8304f..0cd3a5d08e41 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for Spring Security's OAuth 2 client. + * Support for Spring Security's OAuth 2 client. */ package org.springframework.boot.autoconfigure.security.oauth2.client; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java new file mode 100644 index 000000000000..dcaecfba661a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's Reactive + * OAuth2 client. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) +@ConditionalOnClass({ EnableWebFluxSecurity.class, ClientRegistration.class }) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@Import({ ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class }) +public class ReactiveOAuth2ClientAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java new file mode 100644 index 000000000000..325ae96191a3 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +/** + * {@link Configuration} used to map {@link OAuth2ClientProperties} to client + * registrations. + * + * @author Madhura Bhave + */ +@Configuration +@EnableConfigurationProperties(OAuth2ClientProperties.class) +@Conditional(ClientsConfiguredCondition.class) +class ReactiveOAuth2ClientRegistrationRepositoryConfiguration { + + private final OAuth2ClientProperties properties; + + ReactiveOAuth2ClientRegistrationRepositoryConfiguration( + OAuth2ClientProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class) + public InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>( + OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(this.properties).values()); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java new file mode 100644 index 000000000000..a1376e93fcb5 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +/** + * {@link Configuration} used to create an in-memory + * {@link ReactiveOAuth2AuthorizedClientService}. + * + * @author Madhura Bhave + */ +@Configuration +public class ReactiveOAuth2WebSecurityConfiguration { + + @Bean + @ConditionalOnBean(ReactiveClientRegistrationRepository.class) + @ConditionalOnMissingBean + public ReactiveOAuth2AuthorizedClientService authorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java new file mode 100644 index 000000000000..4f9e03c3e82a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Security's Reactive OAuth 2 client. + */ +package org.springframework.boot.autoconfigure.security.oauth2.client.reactive; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java index 5f2c1d513a31..3cd23fdbe269 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java similarity index 51% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java index 966924cffa2f..8be5b23eb6ca 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java @@ -14,28 +14,19 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration; +import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; 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.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; @@ -45,11 +36,10 @@ * registrations. * * @author Madhura Bhave - * @author Phillip Webb */ @Configuration @EnableConfigurationProperties(OAuth2ClientProperties.class) -@Conditional(OAuth2ClientRegistrationRepositoryConfiguration.ClientsConfiguredCondition.class) +@Conditional(ClientsConfiguredCondition.class) class OAuth2ClientRegistrationRepositoryConfiguration { private final OAuth2ClientProperties properties; @@ -67,38 +57,4 @@ public InMemoryClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(registrations); } - /** - * Condition that matches if any {@code spring.security.oauth2.client.registration} - * properties are defined. - */ - static class ClientsConfiguredCondition extends SpringBootCondition { - - private static final Bindable> BINDABLE_REGISTRATION = Bindable - .mapOf(String.class, OAuth2ClientProperties.Registration.class); - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - ConditionMessage.Builder message = ConditionMessage - .forCondition("OAuth2 Clients Configured Condition"); - Map registrations = this - .getRegistrations(context.getEnvironment()); - if (!registrations.isEmpty()) { - return ConditionOutcome.match(message.foundExactly( - "registered clients " + registrations.values().stream() - .map(OAuth2ClientProperties.Registration::getClientId) - .collect(Collectors.joining(", ")))); - } - return ConditionOutcome.noMatch(message.notAvailable("registered clients")); - } - - private Map getRegistrations(Environment environment) { - return Binder.get(environment) - .bind("spring.security.oauth2.client.registration", - BINDABLE_REGISTRATION) - .orElse(Collections.emptyMap()); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index 60e9494b7bd9..953c41262cdb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java new file mode 100644 index 000000000000..573079129a70 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Security's OAuth 2 client. + */ +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 424c6edb5a51..8abd511201ed 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -103,7 +103,8 @@ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoCon org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ -org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java new file mode 100644 index 000000000000..99c69ba4c9ed --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2ClientAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2ClientAutoConfigurationTests { + + private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class)); + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + + @Test + public void autoConfigurationShouldImportConfigurations() { + this.contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { + assertThat(context).hasSingleBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context) + .hasSingleBean(ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnClassEnableWebFluxSecurity() { + FilteredClassLoader classLoader = new FilteredClassLoader( + EnableWebFluxSecurity.class); + this.contextRunner.withClassLoader(classLoader) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnClassClientRegistration() { + FilteredClassLoader classLoader = new FilteredClassLoader( + ClientRegistration.class); + this.contextRunner.withClassLoader(classLoader) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnReactiveWebApplication() { + WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(ReactiveOAuth2ClientAutoConfiguration.class)); + contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java new file mode 100644 index 000000000000..4ca71fc738f2 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import org.junit.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2ClientRegistrationRepositoryConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + + @Test + public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ClientRegistrationRepository.class)); + } + + @Test + public void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + ReactiveClientRegistrationRepository repository = context + .getBean(ReactiveClientRegistrationRepository.class); + ClientRegistration registration = repository + .findByRegistrationId("foo").block(); + assertThat(registration).isNotNull(); + assertThat(registration.getClientSecret()).isEqualTo("secret"); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java new file mode 100644 index 000000000000..4d1b9016324b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.core.AuthorizationGrantType; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2WebSecurityConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2WebSecurityConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + public void authorizedClientServiceBeanIsConditionalOnClientRegistrationRepository() { + this.contextRunner + .withUserConfiguration(ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class)); + } + + @Test + public void configurationRegistersAuthorizedClientServiceBean() { + this.contextRunner + .withUserConfiguration(ReactiveClientRepositoryConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class)); + } + + @Test + public void authorizedClientServiceBeanIsConditionalOnMissingBean() { + this.contextRunner + .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> { + assertThat(context) + .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class); + assertThat(context).hasBean("testAuthorizedClientService"); + }); + } + + @Configuration + static class ReactiveClientRepositoryConfiguration { + + @Bean + public ReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>(); + registrations.add(getClientRegistration("first", "http://user-info-uri.com")); + registrations.add(getClientRegistration("second", "http://other-user-info")); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + + private ClientRegistration getClientRegistration(String id, String userInfoUri) { + ClientRegistration.Builder builder = ClientRegistration + .withRegistrationId(id); + builder.clientName("foo").clientId("foo").clientAuthenticationMethod( + org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .scope("read").clientSecret("secret") + .redirectUriTemplate("http://redirect-uri.com") + .authorizationUri("http://authorization-uri.com") + .tokenUri("http://token-uri.com").userInfoUri(userInfoUri) + .userNameAttributeName("login"); + return builder.build(); + } + + } + + @Configuration + @Import(ReactiveClientRepositoryConfiguration.class) + static class OAuth2AuthorizedClientServiceConfiguration { + + @Bean + public ReactiveOAuth2AuthorizedClientService testAuthorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java index a7a6639be6fb..039f4c476b55 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.junit.Test; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index efba0c68e0ad..d6803ce5d018 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import java.util.ArrayList; import java.util.List; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 6e362044b18a..e1fea87b01cb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3151,7 +3151,8 @@ Spring. ==== Client If you have `spring-security-oauth2-client` on your classpath, you can take advantage of some auto-configuration to make it easy to set up an OAuth2 Client. This configuration -makes use of the properties under `OAuth2ClientProperties`. +makes use of the properties under `OAuth2ClientProperties`. The same properties are applicable +for both servlet and reactive applications. You can register multiple OAuth2 clients and providers under the `spring.security.oauth2.client` prefix, as shown in the following example: @@ -3186,7 +3187,7 @@ You can register multiple OAuth2 clients and providers under the By default, Spring Security's `OAuth2LoginAuthenticationFilter` only processes URLs matching `/login/oauth2/code/*`. If you want to customize the `redirect-uri-template` to use a different pattern, you need to provide configuration to process that custom pattern. -For example, you can add your own `WebSecurityConfigurerAdapter` that resembles the +For example, for servlet applications, you can add your own `WebSecurityConfigurerAdapter` that resembles the following: [source,java,indent=0] diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc new file mode 100644 index 000000000000..ba8ce9869f27 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc @@ -0,0 +1,12 @@ += Spring Boot Sample Reactive OAuth2 Client + +== Register Github OAuth2 application +To run the sample, you need to link:https://github.com/settings/applications/new[register an OAuth application on Github]. +While registering your application, ensure the Authorization callback URL is set to http://localhost:8080/login/oauth2/code/github. +After completing the registration, you will have a new OAuth Application with a Client ID and Client Secret. + +== Configuring application.yml +Once the OAuth application is registered with GitHub, you need to configure the sample application to use this OAuth application (client). +Edit the link:src/main/resources/application.yml[application.yml] and replace ${APP-CLIENT-ID} and ${APP-CLIENT-SECRET} with the OAuth client credentials created in the previous section. + +The sample can now be run and you can login with your Github user credentials. diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml new file mode 100644 index 000000000000..69c4759b16fa --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + ${revision} + + spring-boot-sample-reactive-oauth2-client + Spring Boot Sample Reactive OAuth2 Client + Spring Boot Sample Reactive OAuth2 Client + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-client + + + org.springframework.security + spring-security-oauth2-jose + + + + org.apache.httpcomponents + httpclient + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java new file mode 100644 index 000000000000..90cc03ac1825 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.client; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ExampleController { + + @RequestMapping("/") + public String email(Principal principal) { + return "Hello " + principal.getName(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java new file mode 100644 index 000000000000..0b4b49e8d599 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleReactiveOAuth2ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleReactiveOAuth2ClientApplication.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml new file mode 100644 index 000000000000..220007d7e4b3 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + security: + oauth2: + client: + registration: + github-client-1: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github user + provider: github + scope: user + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + github-client-2: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github email + provider: github + scope: user:email + redirect-uri-template: http://localhost:8080/login/oauth2/code/github \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java new file mode 100644 index 000000000000..74fd195dac60 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.client; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { + "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret" }) +public class SampleReactiveOAuth2ClientApplicationTests { + + @Autowired + private WebTestClient webTestClient; + + @Test + public void everythingShouldRedirectToLogin() { + this.webTestClient.get().uri("/").exchange() + .expectStatus().isFound() + .expectHeader().valueEquals("Location", "/login"); + } + + @Test + public void loginShouldHaveBothOAuthClientsToChooseFrom() { + byte[] body = this.webTestClient.get().uri("/login").exchange() + .expectStatus().isOk() + .returnResult(String.class).getResponseBodyContent(); + String bodyString = new String(body); + assertThat(bodyString).contains("/oauth2/authorization/github-client-1"); + assertThat(bodyString).contains("/oauth2/authorization/github-client-2"); + } + +} From 840948c6c904c9648870a308a549c10d5c927c7e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 30 May 2018 21:02:57 -0700 Subject: [PATCH 085/701] Polish --- .../oauth2/client/ClientsConfiguredCondition.java | 14 ++++++++------ .../OAuth2ClientPropertiesRegistrationAdapter.java | 1 + .../ReactiveOAuth2WebSecurityConfiguration.java | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java index fcdbd72e4f7b..295abeda5f63 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -31,10 +31,13 @@ /** * Condition that matches if any {@code spring.security.oauth2.client.registration} * properties are defined. + * + * @author Madhura Bhave + * @since 2.1.0 */ public class ClientsConfiguredCondition extends SpringBootCondition { - private static final Bindable> BINDABLE_REGISTRATION = Bindable + private static final Bindable> STRING_REGISTRATION_MAP = Bindable .mapOf(String.class, OAuth2ClientProperties.Registration.class); @Override @@ -42,8 +45,8 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("OAuth2 Clients Configured Condition"); - Map registrations = this - .getRegistrations(context.getEnvironment()); + Map registrations = getRegistrations( + context.getEnvironment()); if (!registrations.isEmpty()) { return ConditionOutcome.match(message .foundExactly("registered clients " + registrations.values().stream() @@ -55,9 +58,8 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, private Map getRegistrations( Environment environment) { - return Binder.get(environment) - .bind("spring.security.oauth2.client.registration", BINDABLE_REGISTRATION) - .orElse(Collections.emptyMap()); + return Binder.get(environment).bind("spring.security.oauth2.client.registration", + STRING_REGISTRATION_MAP).orElse(Collections.emptyMap()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index c9c61d0fef93..4927c2605972 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -37,6 +37,7 @@ * * @author Phillip Webb * @author Thiago Hirata + * @since 2.1.0 */ public final class OAuth2ClientPropertiesRegistrationAdapter { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java index a1376e93fcb5..31cf4b25c063 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java @@ -28,6 +28,7 @@ * {@link ReactiveOAuth2AuthorizedClientService}. * * @author Madhura Bhave + * @since 2.1.0 */ @Configuration public class ReactiveOAuth2WebSecurityConfiguration { From fec75c42fafbd4f33838a8aa01b175f17a521a5c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 31 May 2018 17:07:42 +0200 Subject: [PATCH 086/701] Move unused property in code to metadata --- .../boot/autoconfigure/mail/MailProperties.java | 13 ------------- .../additional-spring-configuration-metadata.json | 7 +++++++ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java index 47d8305791f6..01099ae3f722 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java @@ -76,11 +76,6 @@ public class MailProperties { */ private String jndiName; - /** - * Whether to test that the mail server is available on startup. - */ - private boolean testConnection; - public String getHost() { return this.host; } @@ -141,12 +136,4 @@ public String getJndiName() { return this.jndiName; } - public boolean isTestConnection() { - return this.testConnection; - } - - public void setTestConnection(boolean testConnection) { - this.testConnection = testConnection; - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 930e3988ca42..dafabc25def5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -409,6 +409,13 @@ "name": "spring.kafka.listener.type", "defaultValue": "single" }, + { + "name": "spring.mail.test-connection", + "description": "Whether to test that the mail server is available on startup.", + "sourceType": "org.springframework.boot.autoconfigure.mail.MailProperties", + "type": "java.lang.Boolean", + "defaultValue": false + }, { "name": "spring.mongodb.embedded.features", "defaultValue": [ From 81ef6fec7b6950047c3bc022d3d4391964d29680 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 1 Jun 2018 07:59:18 +0200 Subject: [PATCH 087/701] Add reference to Gitter --- README.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 5c824aad0a4f..de39eb2556b3 100755 --- a/README.adoc +++ b/README.adoc @@ -67,7 +67,8 @@ Having trouble with Spring Boot? We'd like to help! * If you are upgrading, read the https://github.com/spring-projects/spring-boot/wiki[release notes] for upgrade instructions and "new and noteworthy" features. * Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions - tagged with https://stackoverflow.com/tags/spring-boot[`spring-boot`]. + tagged with https://stackoverflow.com/tags/spring-boot[`spring-boot`]. You can also chat + with the community on https://gitter.im/spring-projects/spring-boot[Gitter]. * Report bugs with Spring Boot at https://github.com/spring-projects/spring-boot/issues[github.com/spring-projects/spring-boot/issues]. From 77dcbdb1e547518874944b0d92a33302f246a90c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 1 Jun 2018 09:28:55 +0200 Subject: [PATCH 088/701] Polish See gh-13320 --- .../elasticsearch/rest/RestClientAutoConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index 1f99a2b859e4..9598af3432dd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-Configuration} for Elasticsearch REST clients. + * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch REST clients. * * @author Brian Clozel * @since 2.1.0 @@ -60,7 +60,7 @@ public RestClientAutoConfiguration(RestClientProperties properties, .getIfAvailable(Collections::emptyList); } - @Bean(destroyMethod = "close") + @Bean @ConditionalOnMissingBean public RestClient restClient(RestClientBuilder builder) { return builder.build(); From 5d5a14e4f7c69dda4dc043615cb3d8504ff1e091 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 1 Jun 2018 16:12:49 +0900 Subject: [PATCH 089/701] Make MetricsProperties fields final if possible Closes gh-13324 --- .../metrics/MetricsProperties.java | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java index 2a9efba264f9..860a94d948f7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsProperties.java @@ -20,7 +20,6 @@ import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.util.Assert; /** * {@link ConfigurationProperties} for configuring Micrometer-based metrics. @@ -42,7 +41,7 @@ public class MetricsProperties { * Whether meter IDs starting-with the specified name should be enabled. The longest * match wins, the key `all` can also be used to configure all meters. */ - private Map enable = new LinkedHashMap<>(); + private final Map enable = new LinkedHashMap<>(); /** * Common tags that are applied to every meter. @@ -65,11 +64,6 @@ public Map getEnable() { return this.enable; } - public void setEnable(Map enable) { - Assert.notNull(enable, "enable must not be null"); - this.enable = enable; - } - public Map getTags() { return this.tags; } @@ -172,14 +166,14 @@ public static class Distribution { * this has no effect. The longest match wins, the key `all` can also be used to * configure all meters. */ - private Map percentilesHistogram = new LinkedHashMap<>(); + private final Map percentilesHistogram = new LinkedHashMap<>(); /** * Specific computed non-aggregable percentiles to ship to the backend for meter * IDs starting-with the specified name. The longest match wins, the key `all` can * also be used to configure all meters. */ - private Map percentiles = new LinkedHashMap<>(); + private final Map percentiles = new LinkedHashMap<>(); /** * Specific SLA boundaries for meter IDs starting-with the specified name. The @@ -188,35 +182,20 @@ public static class Distribution { * as a long or as a Duration value (for timer meters, defaulting to ms if no unit * specified). */ - private Map sla = new LinkedHashMap<>(); + private final Map sla = new LinkedHashMap<>(); public Map getPercentilesHistogram() { return this.percentilesHistogram; } - public void setPercentilesHistogram(Map percentilesHistogram) { - Assert.notNull(percentilesHistogram, "PercentilesHistogram must not be null"); - this.percentilesHistogram = percentilesHistogram; - } - public Map getPercentiles() { return this.percentiles; } - public void setPercentiles(Map percentiles) { - Assert.notNull(percentiles, "Percentiles must not be null"); - this.percentiles = percentiles; - } - public Map getSla() { return this.sla; } - public void setSla(Map sla) { - Assert.notNull(sla, "SLA must not be null"); - this.sla = sla; - } - } } From 205b1c1327aef9adf6cc68a7dd572bc8b4889bbc Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Thu, 31 May 2018 23:30:36 +0200 Subject: [PATCH 090/701] Upgrade to Hazelcast 3.10.1 Closes gh-13322 --- .../src/test/resources/cache/test-hazelcast.xml | 2 +- .../src/test/resources/hazelcast.xml | 2 +- .../src/test/resources/cache/test-hazelcast.xml | 2 +- .../spring-boot-actuator/src/test/resources/hazelcast.xml | 2 +- .../src/test/resources/hazelcast.xml | 2 +- .../autoconfigure/hazelcast/hazelcast-client-specific.xml | 2 +- .../boot/autoconfigure/hazelcast/hazelcast-specific.xml | 4 ++-- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../spring-boot-sample-cache/src/main/resources/hazelcast.xml | 2 +- .../src/main/resources/hazelcast.xml | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/cache/test-hazelcast.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/cache/test-hazelcast.xml index 1684f41d0851..94a0d679d8e4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/cache/test-hazelcast.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/cache/test-hazelcast.xml @@ -1,4 +1,4 @@ - diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/hazelcast.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/hazelcast.xml index c60e05846e44..9aa7a45632aa 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/hazelcast.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/hazelcast.xml @@ -1,5 +1,5 @@ diff --git a/spring-boot-project/spring-boot-actuator/src/test/resources/cache/test-hazelcast.xml b/spring-boot-project/spring-boot-actuator/src/test/resources/cache/test-hazelcast.xml index 1684f41d0851..94a0d679d8e4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/resources/cache/test-hazelcast.xml +++ b/spring-boot-project/spring-boot-actuator/src/test/resources/cache/test-hazelcast.xml @@ -1,4 +1,4 @@ - diff --git a/spring-boot-project/spring-boot-actuator/src/test/resources/hazelcast.xml b/spring-boot-project/spring-boot-actuator/src/test/resources/hazelcast.xml index c60e05846e44..9aa7a45632aa 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/resources/hazelcast.xml +++ b/spring-boot-project/spring-boot-actuator/src/test/resources/hazelcast.xml @@ -1,5 +1,5 @@ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/hazelcast.xml b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/hazelcast.xml index 7a060b660337..92aa5e76c63f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/hazelcast.xml +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/hazelcast.xml @@ -1,5 +1,5 @@ default-instance diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml index e5596bf2206c..53281f3ed336 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://www.hazelcast.com/schema/client-config hazelcast-client-config-3.10.xsd"> diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml index 42f6f16e7395..308a412d0f58 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml @@ -1,4 +1,4 @@ - @@ -16,4 +16,4 @@ - \ No newline at end of file + diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d167f2b88dc6..016683de091a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -65,7 +65,7 @@ 2.8.5 1.4.197 1.3 - 3.9.4 + 3.10.1 1.2.3 5.2.17.Final 1.0.2.Final diff --git a/spring-boot-samples/spring-boot-sample-cache/src/main/resources/hazelcast.xml b/spring-boot-samples/spring-boot-sample-cache/src/main/resources/hazelcast.xml index 2711cdbd8c16..1cbc30ee961c 100644 --- a/spring-boot-samples/spring-boot-sample-cache/src/main/resources/hazelcast.xml +++ b/spring-boot-samples/spring-boot-sample-cache/src/main/resources/hazelcast.xml @@ -1,4 +1,4 @@ - diff --git a/spring-boot-samples/spring-boot-sample-session/src/main/resources/hazelcast.xml b/spring-boot-samples/spring-boot-sample-session/src/main/resources/hazelcast.xml index f2f41b3061ee..8159481745aa 100644 --- a/spring-boot-samples/spring-boot-sample-session/src/main/resources/hazelcast.xml +++ b/spring-boot-samples/spring-boot-sample-session/src/main/resources/hazelcast.xml @@ -1,4 +1,4 @@ - From 37a7457f36e3b2a7413e8edb8f70a436f7c7f2f7 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 1 Jun 2018 15:02:46 -0700 Subject: [PATCH 091/701] Polish --- .../boot/context/properties/bind/CollectionBinder.java | 3 ++- .../boot/context/properties/bind/MapBinder.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java index 618c80d034b8..81f76c2b77c9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java @@ -71,7 +71,8 @@ protected Collection merge(Supplier> existing, } } - private Collection getExistingIfPossible(Supplier> existing) { + private Collection getExistingIfPossible( + Supplier> existing) { try { return existing.get(); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java index 29ceb2f253b1..8aaa5c0c7920 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java @@ -100,7 +100,8 @@ protected Map merge(Supplier> existing, } } - private Map getExistingIfPossible(Supplier> existing) { + private Map getExistingIfPossible( + Supplier> existing) { try { return existing.get(); } From c9df1c551a56ac4344974d63f67c60f7608f6afc Mon Sep 17 00:00:00 2001 From: dnosan Date: Sat, 31 Mar 2018 15:07:42 +0300 Subject: [PATCH 092/701] Add auto-configuration for WebServiceTemplate See gh-12707 --- .../WebServiceTemplateAutoConfiguration.java | 67 + .../webservices/client/package-info.java | 20 + .../main/resources/META-INF/spring.factories | 3 +- ...ServiceTemplateAutoConfigurationTests.java | 150 +++ .../main/asciidoc/spring-boot-features.adoc | 30 +- spring-boot-project/spring-boot/pom.xml | 10 + .../client/WebServiceTemplateBuilder.java | 1106 +++++++++++++++++ .../client/WebServiceTemplateCustomizer.java | 34 + .../boot/webservices/client/package-info.java | 21 + ...plateBuilderCustomsMessageSenderTests.java | 93 ++ ...mponentsClientHttpRequestFactoryTests.java | 55 + ...ilderHttpComponentsMessageSenderTests.java | 67 + ...erHttpUrlConnectionMessageSenderTests.java | 70 ++ ...rOkHttp3ClientHttpRequestFactoryTests.java | 82 ++ ...erSimpleClientHttpRequestFactoryTests.java | 52 + .../WebServiceTemplateBuilderTests.java | 520 ++++++++ 16 files changed, 2378 insertions(+), 2 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java new file mode 100644 index 000000000000..e12ee5b8bcd5 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2018 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.autoconfigure.webservices.client; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; +import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.util.CollectionUtils; +import org.springframework.ws.client.core.WebServiceTemplate; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link WebServiceTemplate}. + * + * @author Dmytro Nosan + */ +@Configuration +@ConditionalOnClass({ WebServiceTemplateBuilder.class, WebServiceTemplate.class, + Unmarshaller.class, Marshaller.class }) +public class WebServiceTemplateAutoConfiguration { + + private final ObjectProvider> webServiceTemplateCustomizers; + + public WebServiceTemplateAutoConfiguration( + ObjectProvider> webServiceTemplateCustomizers) { + this.webServiceTemplateCustomizers = webServiceTemplateCustomizers; + } + + @Bean + @ConditionalOnMissingBean + public WebServiceTemplateBuilder webServiceTemplateBuilder() { + WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + List customizers = this.webServiceTemplateCustomizers + .getIfAvailable(); + if (!CollectionUtils.isEmpty(customizers)) { + customizers = new ArrayList<>(customizers); + AnnotationAwareOrderComparator.sort(customizers); + builder = builder.setCustomizers(customizers); + } + return builder; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java new file mode 100644 index 000000000000..5677addf4504 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Web Services Clients. + */ +package org.springframework.boot.autoconfigure.webservices.client; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 8abd511201ed..69b1f0e79041 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -126,7 +126,8 @@ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ -org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration +org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\ +org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java new file mode 100644 index 000000000000..d60b88ca6555 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java @@ -0,0 +1,150 @@ +/* + * Copyright 2012-2018 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.autoconfigure.webservices.client; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; +import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.client.core.WebServiceTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateAutoConfiguration + * WebServiceTemplateAutoConfiguration}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void webServiceTemplateShouldNotHaveMarshallerAndUnmarshaller() { + load(WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getUnmarshaller()).isNull(); + assertThat(webServiceTemplate.getMarshaller()).isNull(); + } + + @Test + public void webServiceTemplateShouldUserCustomBuilder() { + load(CustomWebServiceTemplateBuilderConfig.class, WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getMarshaller()).isNotNull(); + } + + @Test + public void webServiceTemplateShouldApplyCustomizer() { + load(WebServiceTemplateCustomizerConfig.class, WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getUnmarshaller()).isNotNull(); + } + + @Test + public void builderShouldBeFreshForEachUse() { + load(DirtyWebServiceTemplateConfig.class); + } + + private void load(Class... config) { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(config); + ctx.register(WebServiceTemplateAutoConfiguration.class); + ctx.refresh(); + this.context = ctx; + } + + @Configuration + static class WebServiceTemplateConfig { + + @Bean + public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { + return builder.build(); + } + + } + + @Configuration + static class DirtyWebServiceTemplateConfig { + + @Bean + public WebServiceTemplate webServiceTemplateOne( + WebServiceTemplateBuilder builder) { + try { + return builder.build(); + } + finally { + breakBuilderOnNextCall(builder); + } + } + + @Bean + public WebServiceTemplate webServiceTemplateTwo( + WebServiceTemplateBuilder builder) { + try { + return builder.build(); + } + finally { + breakBuilderOnNextCall(builder); + } + } + + private void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) { + builder.addCustomizers((webServiceTemplate) -> { + throw new IllegalStateException(); + }); + } + + } + + @Configuration + static class CustomWebServiceTemplateBuilderConfig { + + @Bean + public WebServiceTemplateBuilder webServiceTemplateBuilder() { + return new WebServiceTemplateBuilder().setMarshaller(new Jaxb2Marshaller()); + } + + } + + @Configuration + static class WebServiceTemplateCustomizerConfig { + + @Bean + public WebServiceTemplateCustomizer webServiceTemplateCustomizer() { + return (ws) -> ws.setUnmarshaller(new Jaxb2Marshaller()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index d0677cafd94c..beb46654bf8a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,7 +5634,6 @@ The following code shows a typical example: ---- - [[boot-features-webclient-customization]] === WebClient Customization There are three main approaches to `WebClient` customization, depending on how broadly you @@ -5653,6 +5652,35 @@ the point of injection. Finally, you can fall back to the original API and use `WebClient.create()`. In that case, no auto-configuration or `WebClientCustomizer` is applied. +[[boot-features-webservicetemplate]] +== Calling Web Services with `WebServiceTemplate` +If you need to call remote WEB services from your application, you can use the Spring +Framework's {spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. Since +`WebServiceTemplate` instances often need to be customized before being used, Spring Boot does +not provide any single auto-configured `WebServiceTemplate` bean. It does, however, +auto-configure a `WebServiceTemplateBuilder`, which can be used to create `WebServiceTemplate` +instances when needed. + +The following code shows a typical example: + +[source,java,indent=0] +---- + @Service + public class MyService { + + private final WebServiceTemplate webServiceTemplate; + + public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { + this.webServiceTemplate = webServiceTemplateBuilder.build(); + } + + public DetailsResp someCall(DetailsReq detailsReq) { + return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); + + } + + } +---- [[boot-features-validation]] diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index aff395bf3f28..dcbecba69141 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -245,6 +245,16 @@ spring-orm true + + org.springframework.ws + spring-ws-core + true + + + org.springframework + spring-oxm + true + org.springframework spring-test diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java new file mode 100644 index 000000000000..4a185900d58b --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -0,0 +1,1106 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import java.lang.reflect.Field; +import java.net.URI; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.xml.transform.TransformerFactory; + +import org.springframework.beans.BeanUtils; +import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.client.core.FaultMessageResolver; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.destination.DestinationProvider; +import org.springframework.ws.client.support.interceptor.ClientInterceptor; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; +import org.springframework.ws.transport.http.HttpComponentsMessageSender; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +/** + * Builder that can be used to configure and create a + * {@link org.springframework.ws.client.core.WebServiceTemplate}. By default the built + * {@link org.springframework.ws.client.core.WebServiceTemplate} will attempt to use the + * most suitable {@link org.springframework.ws.transport.WebServiceMessageSender}, call + * {@link #detectWebServiceMessageSender(boolean) detectWebServiceMessageSender(false)} if + * you prefer to keep the default. In a typical auto-configured Spring Boot application + * this builder is available as a bean and can be injected whenever a + * {@link WebServiceTemplate} is needed. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilder { + + private static final Map> MESSAGE_SENDER_FACTORY_CLASSES; + + static { + Map> candidates = new LinkedHashMap<>(); + candidates.put("org.apache.http.client.HttpClient", + HttpComponentsMessageSenderFactory.class); + candidates.put("org.springframework.http.client.ClientHttpRequestFactory", + ClientHttpRequestMessageSenderFactory.class); + MESSAGE_SENDER_FACTORY_CLASSES = Collections.unmodifiableMap(candidates); + } + + private final Set interceptors; + + private final Set internalCustomizers; + + private final Set customizers; + + private final Set> webServiceMessageSenderSuppliers; + + private final Set webServiceMessageSenderCustomizers; + + private final Marshaller marshaller; + + private final Unmarshaller unmarshaller; + + private final DestinationProvider destinationProvider; + + private final Class transformerFactoryClass; + + private final WebServiceMessageFactory messageFactory; + + private final boolean detectWebServiceMessageSender; + + public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) { + this(Collections.emptySet(), Collections.emptySet(), + append(Collections.emptySet(), customizers), + Collections.emptySet(), Collections.emptySet(), null, null, null, null, + null, true); + } + + private WebServiceTemplateBuilder(Set interceptors, + Set internalCustomizers, + Set customizers, + Set> webServiceMessageSenderSuppliers, + Set webServiceMessageSenderCustomizers, + Marshaller marshaller, Unmarshaller unmarshaller, + DestinationProvider destinationProvider, + Class transformerFactoryClass, + WebServiceMessageFactory messageFactory, + boolean detectWebServiceMessageSender) { + this.interceptors = interceptors; + this.internalCustomizers = internalCustomizers; + this.customizers = customizers; + this.webServiceMessageSenderSuppliers = webServiceMessageSenderSuppliers; + this.webServiceMessageSenderCustomizers = webServiceMessageSenderCustomizers; + this.marshaller = marshaller; + this.unmarshaller = unmarshaller; + this.destinationProvider = destinationProvider; + this.transformerFactoryClass = transformerFactoryClass; + this.messageFactory = messageFactory; + this.detectWebServiceMessageSender = detectWebServiceMessageSender; + } + + /** + * Set {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Interceptors are applied in the order that they were + * added after builder configuration has been applied. + * + * Note! Override existing interceptors + * @param interceptors the interceptors to set + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder setInterceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return setInterceptors(Arrays.asList(interceptors)); + } + + /** + * Set {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Interceptors are applied in the order that they were + * added after builder configuration has been applied. + * + * Note! Override existing interceptors + * @param interceptors the interceptors to set + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder setInterceptors( + Collection interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return new WebServiceTemplateBuilder( + append(Collections.emptySet(), interceptors), + this.internalCustomizers, this.customizers, + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Add additional {@link ClientInterceptor ClientInterceptors} that should be used + * with the {@link WebServiceTemplate}. Interceptors are applied in the order that + * they were added after builder configuration has been applied. + * @param interceptors the interceptors to add + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder addInterceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return addInterceptors(Arrays.asList(interceptors)); + } + + /** + * Add additional {@link ClientInterceptor ClientInterceptors} that should be used + * with the {@link WebServiceTemplate}. Interceptors are applied in the order that + * they were added after builder configuration has been applied. + * @param interceptors the interceptors to add + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder addInterceptors( + Collection interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return new WebServiceTemplateBuilder(append(this.interceptors, interceptors), + this.internalCustomizers, this.customizers, + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should + * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order + * that they were added after builder configuration has been applied. + * + * Note! Override existing customizers + * @param customizers the customizers to set + * @return a new builder instance + */ + + public WebServiceTemplateBuilder setCustomizers( + Collection customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + append(Collections.emptySet(), customizers), + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should + * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order + * that they were added after builder configuration has been applied. + * + * Note! Override existing customizers + * @param customizers the customizers to set + * @return a new builder instance + */ + public WebServiceTemplateBuilder setCustomizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return setCustomizers(Arrays.asList(customizers)); + } + + /** + * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} + * that should be applied to the {@link WebServiceTemplate}. Customizers are applied + * in the order that they were added after builder configuration has been applied. + * @param customizers the customizers to add + * @return a new builder instance + */ + public WebServiceTemplateBuilder addCustomizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return addCustomizers(Arrays.asList(customizers)); + } + + /** + * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} + * that should be applied to the {@link WebServiceTemplate}. Customizers are applied + * in the order that they were added after builder configuration has been applied. + * @param customizers the customizers to add + * @return a new builder instance + */ + + public WebServiceTemplateBuilder addCustomizers( + Collection customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + append(this.customizers, customizers), + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the {@code Suppliers} of {@link WebServiceMessageSender} that should be called + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSenders( + Collection> webServiceMessageSenderSuppliers) { + Assert.notNull(webServiceMessageSenderSuppliers, + "webServiceMessageSenderSuppliers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, + append(Collections + .>emptySet(), + webServiceMessageSenderSuppliers), + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Add additional {@code Suppliers} of {@link WebServiceMessageSender} that should be + * called each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + */ + public WebServiceTemplateBuilder addWebServiceMessageSenders( + Collection> webServiceMessageSenderSuppliers) { + Assert.notNull(webServiceMessageSenderSuppliers, + "webServiceMessageSenderSuppliers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, + append(this.webServiceMessageSenderSuppliers, + webServiceMessageSenderSuppliers), + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setCheckConnectionForFault(boolean) + * setCheckConnectionForFault} on the underlying. + * @param checkConnectionForFault Specify whether checkConnectionForFault should be + * enabled or not. + * @return a new builder instance. + **/ + public WebServiceTemplateBuilder setCheckConnectionForFault( + boolean checkConnectionForFault) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new CheckConnectionFaultCustomizer(checkConnectionForFault)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setCheckConnectionForError(boolean) + * setCheckConnectionForError} on the underlying. + * @param checkConnectionForError Specify whether checkConnectionForError should be + * enabled or not. + * @return a new builder instance. + **/ + + public WebServiceTemplateBuilder setCheckConnectionForError( + boolean checkConnectionForError) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new CheckConnectionForErrorCustomizer(checkConnectionForError)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the {@code Supplier} of {@link WebServiceMessageSender} that should be called + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderSupplier Supplier for the messageSender + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #setWebServiceMessageSenders(Collection) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSender( + Supplier webServiceMessageSenderSupplier) { + Assert.notNull(webServiceMessageSenderSupplier, + "webServiceMessageSenderSupplier must not be null"); + return setWebServiceMessageSenders( + Collections.singleton(webServiceMessageSenderSupplier)); + } + + /** + * Add additional {@code Supplier} of {@link WebServiceMessageSender} that should be + * called each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderSupplier Supplier for the messageSender + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #addWebServiceMessageSenders(Collection) + */ + public WebServiceTemplateBuilder addWebServiceMessageSender( + Supplier webServiceMessageSenderSupplier) { + Assert.notNull(webServiceMessageSenderSupplier, + "webServiceMessageSenderSupplier must not be null"); + return addWebServiceMessageSenders( + Collections.singleton(webServiceMessageSenderSupplier)); + } + + /** + * Sets the {@code Class} of {@link WebServiceMessageSender} that should be created + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderClass {@code Class} of + * {@link WebServiceMessageSender} + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #setWebServiceMessageSender(Supplier) + * @see BeanUtils#instantiateClass(Class) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSender( + Class webServiceMessageSenderClass) { + Assert.notNull(webServiceMessageSenderClass, + "webServiceMessageSenderClass must not be null"); + return setWebServiceMessageSender( + supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); + } + + /** + * Add additional {@code Class} of {@link WebServiceMessageSender} that should be + * created each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderClass {@code Class} of + * {@link WebServiceMessageSender} + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #addWebServiceMessageSender(Supplier) + * @see BeanUtils#instantiateClass(Class) + */ + public WebServiceTemplateBuilder addWebServiceMessageSender( + Class webServiceMessageSenderClass) { + Assert.notNull(webServiceMessageSenderClass, + "webServiceMessageSenderClass must not be null"); + return addWebServiceMessageSender( + supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); + } + + /** + * Sets the message factory used for creating messages. + * @param messageFactory instance of WebServiceMessageFactory + * @return a new builder instance. + * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory) + **/ + + public WebServiceTemplateBuilder setWebServiceMessageFactory( + WebServiceMessageFactory messageFactory) { + Assert.notNull(messageFactory, "messageFactory must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setUnmarshaller(Unmarshaller) unmarshaller} on the + * underlying. + * @param unmarshaller message unmarshaller + * @return a new builder instance. + * @see WebServiceTemplate#setUnmarshaller(Unmarshaller) + **/ + public WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) { + Assert.notNull(unmarshaller, "unmarshaller must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setMarshaller(Marshaller) marshaller} on the + * underlying. + * @param marshaller message marshaller + * @return a new builder instance. + * @see WebServiceTemplate#setMarshaller(Marshaller) + **/ + public WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) { + Assert.notNull(marshaller, "marshaller must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the connection timeout in milliseconds on the underlying. + * @param connectionTimeout the connection timeout in milliseconds + * @return a new builder instance. + * @throws java.lang.IllegalStateException if the underlying source doesn't support a + * connection timeout. + */ + public WebServiceTemplateBuilder setConnectionTimeout(int connectionTimeout) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + append(this.webServiceMessageSenderCustomizers, + new ConnectionTimeoutWebServiceMessageSenderCustomizer( + connectionTimeout)), + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory, + this.detectWebServiceMessageSender); + } + + /** + * Sets the read timeout in milliseconds on the underlying. + * @param readTimeout the read timeout in milliseconds + * @return a new builder instance. + * @throws java.lang.IllegalStateException if the underlying source doesn't support a + * read timeout. + */ + public WebServiceTemplateBuilder setReadTimeout(int readTimeout) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + append(this.webServiceMessageSenderCustomizers, + new ReadTimeoutWebServiceMessageSenderCustomizer(readTimeout)), + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory, + this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) + * faultMessageResolver} on the underlying. + * @param faultMessageResolver faultMessageResolver may be set to null to disable + * fault handling. + * @return a new builder instance. + **/ + public WebServiceTemplateBuilder setFaultMessageResolver( + FaultMessageResolver faultMessageResolver) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new FaultMessageResolverCustomizer(faultMessageResolver)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setTransformerFactoryClass(Class) + * setTransformerFactoryClass} on the underlying. + * @param transformerFactoryClass boolean value + * @return a new builder instance. + **/ + + public WebServiceTemplateBuilder setTransformerFactoryClass( + Class transformerFactoryClass) { + Assert.notNull(transformerFactoryClass, + "transformerFactoryClass must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set the default URI to be used on operations that do not have a URI parameter. + * + * Note!Typically, either this property is set, or + * {@link #setDestinationProvider(DestinationProvider)}, but not both. + * @param defaultUri the destination provider URI to be used on operations that do not + * have a URI parameter. + * @return a new builder instance. + */ + public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { + Assert.hasText(defaultUri, "defaultUri must not be empty"); + return setDestinationProvider(() -> URI.create(defaultUri)); + } + + /** + * Set {@link WebServiceTemplate#setDestinationProvider(DestinationProvider) + * destinationProvider} on the underlying. + * + * Note!Typically, either this property is set, or + * {@link #setDefaultUri(String)}, but not both. + * @param destinationProvider the destination provider URI to be used on operations + * that do not have a URI parameter. + * @return a new builder instance. + */ + public WebServiceTemplateBuilder setDestinationProvider( + DestinationProvider destinationProvider) { + Assert.notNull(destinationProvider, "destinationProvider must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set if the {@link WebServiceMessageSender} should be detected based on the + * classpath. Default is {@code true}. + * @param detectWebServiceMessageSender if the {@link WebServiceMessageSender} should + * be detected + * @return a new builder instance + */ + public WebServiceTemplateBuilder detectWebServiceMessageSender( + boolean detectWebServiceMessageSender) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, detectWebServiceMessageSender); + } + + /** + * Build a new {@link WebServiceTemplate} instance and configure it using this + * builder. + * @return a configured {@link WebServiceTemplate} instance. + * @see #build(Class) + * @see #configure(WebServiceTemplate) + */ + public WebServiceTemplate build() { + return build(WebServiceTemplate.class); + } + + /** + * Build a new {@link WebServiceTemplate} instance of the specified type and configure + * it using this builder. + * @param the type of web service template + * @param webServiceTemplateClass the template type to create + * @return a configured {@link WebServiceTemplate} instance. + * @see WebServiceTemplateBuilder#build() + * @see #configure(WebServiceTemplate) + */ + + public T build(Class webServiceTemplateClass) { + Assert.notNull(webServiceTemplateClass, + "webServiceTemplateClass must not be null"); + return configure(BeanUtils.instantiateClass(webServiceTemplateClass)); + } + + /** + * Configure the provided {@link WebServiceTemplate} instance using this builder. + * @param the type of web service template + * @param webServiceTemplate the {@link WebServiceTemplate} to configure + * @return the web service template instance + * @see #build() + * @see #build(Class) + */ + public T configure(T webServiceTemplate) { + Assert.notNull(webServiceTemplate, "webServiceTemplate must not be null"); + + configureSenders(webServiceTemplate); + + if (!CollectionUtils.isEmpty(this.internalCustomizers)) { + for (WebServiceTemplateCustomizer internalCustomizer : this.internalCustomizers) { + internalCustomizer.customize(webServiceTemplate); + } + } + + if (this.marshaller != null) { + webServiceTemplate.setMarshaller(this.marshaller); + } + + if (this.unmarshaller != null) { + webServiceTemplate.setUnmarshaller(this.unmarshaller); + } + + if (this.destinationProvider != null) { + webServiceTemplate.setDestinationProvider(this.destinationProvider); + } + + if (this.transformerFactoryClass != null) { + webServiceTemplate.setTransformerFactoryClass(this.transformerFactoryClass); + } + + if (this.messageFactory != null) { + webServiceTemplate.setMessageFactory(this.messageFactory); + } + + if (!CollectionUtils.isEmpty(this.customizers)) { + for (WebServiceTemplateCustomizer customizer : this.customizers) { + customizer.customize(webServiceTemplate); + } + } + + if (!CollectionUtils.isEmpty(this.interceptors)) { + webServiceTemplate.setInterceptors( + append(this.interceptors, webServiceTemplate.getInterceptors()) + .toArray(new ClientInterceptor[0])); + } + + return webServiceTemplate; + } + + private void configureSenders(T webServiceTemplate) { + + if (!CollectionUtils.isEmpty(this.webServiceMessageSenderSuppliers)) { + Set webServiceMessageSenders = new LinkedHashSet<>(); + for (Supplier webServiceMessageSenderSupplier : this.webServiceMessageSenderSuppliers) { + webServiceMessageSenders.add(webServiceMessageSenderSupplier.get()); + } + webServiceTemplate.setMessageSenders( + webServiceMessageSenders.toArray(new WebServiceMessageSender[0])); + } + else if (this.detectWebServiceMessageSender) { + webServiceTemplate.setMessageSenders( + new WebServiceMessageSender[] { detectMessageSender() }); + } + + if (!CollectionUtils.isEmpty(this.webServiceMessageSenderCustomizers)) { + if (!ObjectUtils.isEmpty(webServiceTemplate.getMessageSenders())) { + for (WebServiceMessageSender webServiceMessageSender : webServiceTemplate + .getMessageSenders()) { + for (WebServiceMessageSenderCustomizer webServiceMessageSenderCustomizer : this.webServiceMessageSenderCustomizers) { + webServiceMessageSenderCustomizer + .customize(webServiceMessageSender); + } + } + } + } + } + + private WebServiceMessageSender detectMessageSender() { + ClassLoader classLoader = getClass().getClassLoader(); + for (Map.Entry> candidate : MESSAGE_SENDER_FACTORY_CLASSES + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + WebServiceMessageSenderFactory webServiceMessageSenderFactory = BeanUtils + .instantiateClass(candidate.getValue()); + Optional webServiceMessageSender = webServiceMessageSenderFactory + .create(); + if (webServiceMessageSender.isPresent()) { + return webServiceMessageSender.get(); + } + } + } + return new HttpUrlConnectionMessageSender(); + } + + private static Supplier supplier(T value, Function mapper) { + return () -> mapper.apply(value); + } + + private static Set append(Set set, T[] additions) { + return append(set, additions != null + ? new LinkedHashSet<>(Arrays.asList(additions)) : Collections.emptySet()); + } + + private static Set append(Set set, T addition) { + Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); + result.add(addition); + return Collections.unmodifiableSet(result); + } + + private static Set append(Set set, Collection additions) { + Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); + result.addAll(additions != null ? additions : Collections.emptyList()); + return Collections.unmodifiableSet(result); + } + + private interface WebServiceMessageSenderFactory { + + Optional create(); + + } + + private interface WebServiceMessageSenderCustomizer { + + void customize(WebServiceMessageSender webServiceMessageSender); + + } + + private static final class ClientHttpRequestMessageSenderFactory + implements WebServiceMessageSenderFactory { + + private static final Map REQUEST_FACTORY_CANDIDATES; + + static { + Map candidates = new LinkedHashMap<>(); + candidates.put("okhttp3.OkHttpClient", + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); + REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + } + + @Override + public Optional create() { + ClassLoader classLoader = getClass().getClassLoader(); + for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class factoryClass = ClassUtils + .resolveClassName(candidate.getValue(), classLoader); + ClientHttpRequestFactory clientHttpRequestFactory = (ClientHttpRequestFactory) BeanUtils + .instantiateClass(factoryClass); + return Optional.of( + new ClientHttpRequestMessageSender(clientHttpRequestFactory)); + } + } + return Optional.empty(); + } + + } + + private static final class HttpComponentsMessageSenderFactory + implements WebServiceMessageSenderFactory { + + @Override + public Optional create() { + return Optional.of(new HttpComponentsMessageSender()); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#checkConnectionForFault checkConnectionForFault }. + */ + private static final class CheckConnectionFaultCustomizer + implements WebServiceTemplateCustomizer { + + private final boolean checkConnectionFault; + + private CheckConnectionFaultCustomizer(boolean checkConnectionFault) { + this.checkConnectionFault = checkConnectionFault; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setCheckConnectionForFault(this.checkConnectionFault); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#checkConnectionForError checkConnectionForError }. + */ + private static final class CheckConnectionForErrorCustomizer + implements WebServiceTemplateCustomizer { + + private final boolean checkConnectionForError; + + private CheckConnectionForErrorCustomizer(boolean checkConnectionForError) { + this.checkConnectionForError = checkConnectionForError; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setCheckConnectionForError(this.checkConnectionForError); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#faultMessageResolver faultMessageResolver }. + */ + private static final class FaultMessageResolverCustomizer + implements WebServiceTemplateCustomizer { + + private final FaultMessageResolver faultMessageResolver; + + private FaultMessageResolverCustomizer( + FaultMessageResolver faultMessageResolver) { + this.faultMessageResolver = faultMessageResolver; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setFaultMessageResolver(this.faultMessageResolver); + } + + } + + /** + * {@link WebServiceMessageSenderCustomizer} to set connection timeout. + */ + private static final class ConnectionTimeoutWebServiceMessageSenderCustomizer + extends TimeoutWebServiceMessageSenderCustomizer { + + private ConnectionTimeoutWebServiceMessageSenderCustomizer(int connectTimeout) { + super(connectTimeout, Timeout.CONNECTION); + } + + } + + /** + * {@link WebServiceMessageSenderCustomizer} to set read timeout. + */ + private static final class ReadTimeoutWebServiceMessageSenderCustomizer + extends TimeoutWebServiceMessageSenderCustomizer { + + private ReadTimeoutWebServiceMessageSenderCustomizer(int readTimeout) { + super(readTimeout, Timeout.READ); + } + + } + + private abstract static class TimeoutWebServiceMessageSenderCustomizer + implements WebServiceMessageSenderCustomizer { + + private static final Map>> CUSTOMIZERS; + + static { + Map>> candidates = new LinkedHashMap<>(); + candidates.put( + "org.springframework.ws.transport.http.HttpComponentsMessageSender", + HttpComponentsTimeoutCustomizer.class); + candidates.put( + "org.springframework.ws.transport.http.ClientHttpRequestMessageSender", + ClientHttpRequestTimeoutCustomizer.class); + candidates.put( + "org.springframework.ws.transport.http.HttpUrlConnectionMessageSender", + HttpUrlConnectionTimeoutCustomizer.class); + CUSTOMIZERS = Collections.unmodifiableMap(candidates); + } + + private final Timeout type; + + private final int timeout; + + TimeoutWebServiceMessageSenderCustomizer(int timeout, Timeout type) { + this.timeout = timeout; + this.type = type; + } + + @Override + public final void customize(WebServiceMessageSender webServiceMessageSender) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, webServiceMessageSender, this.type, this.timeout, + classLoader); + + } + + @SuppressWarnings("unchecked") + private static void customize( + Map>> customizers, + T target, Timeout type, int timeout, ClassLoader classLoader) { + for (Map.Entry>> candidate : customizers + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class candidateClass = ClassUtils + .resolveClassName(candidate.getKey(), classLoader); + if (ClassUtils.isAssignable(candidateClass, target.getClass())) { + TimeoutCustomizer timeoutCustomizer = BeanUtils + .instantiateClass(candidate.getValue()); + customize(timeoutCustomizer, target, type, timeout); + return; + } + } + } + throw new IllegalStateException("There is no way to customize '" + + target.getClass() + "' " + "with '" + type.name().toLowerCase() + + "Timeout'. Please use a custom " + "customizer."); + + } + + private static void customize(TimeoutCustomizer customizer, T target, + Timeout type, int timeout) { + if (type == Timeout.CONNECTION) { + customizer.setConnectionTimeout(target, timeout); + } + else if (type == Timeout.READ) { + customizer.setReadTimeout(target, timeout); + } + } + + interface TimeoutCustomizer { + + void setReadTimeout(T source, int timeout); + + void setConnectionTimeout(T source, int timeout); + + } + + enum Timeout { + + READ, CONNECTION + + } + + private static final class HttpComponentsTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpComponentsMessageSender source, int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(HttpComponentsMessageSender source, + int timeout) { + source.setConnectionTimeout(timeout); + } + + } + + private static final class HttpUrlConnectionTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpUrlConnectionMessageSender source, + int timeout) { + source.setReadTimeout(Duration.ofMillis(timeout)); + } + + @Override + public void setConnectionTimeout(HttpUrlConnectionMessageSender source, + int timeout) { + source.setConnectionTimeout(Duration.ofMillis(timeout)); + } + + } + + private static final class ClientHttpRequestTimeoutCustomizer + implements TimeoutCustomizer { + + private static final Map>> CUSTOMIZERS; + + static { + Map>> candidates = new LinkedHashMap<>(); + candidates.put( + "org.springframework.http.client.HttpComponentsClientHttpRequestFactory", + HttpComponentsClientHttpRequestFactoryTimeoutCustomizer.class); + candidates.put( + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory", + OkHttp3ClientHttpRequestFactoryTimeoutCustomizer.class); + candidates.put( + "org.springframework.http.client.SimpleClientHttpRequestFactory", + SimpleClientHttpRequestFactoryTimeoutCustomizer.class); + CUSTOMIZERS = Collections.unmodifiableMap(candidates); + } + + @Override + public void setReadTimeout(ClientHttpRequestMessageSender source, + int timeout) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, getRequestFactory(source), Timeout.READ, timeout, + classLoader); + } + + @Override + public void setConnectionTimeout(ClientHttpRequestMessageSender source, + int timeout) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, getRequestFactory(source), Timeout.CONNECTION, + timeout, classLoader); + } + + private ClientHttpRequestFactory getRequestFactory( + ClientHttpRequestMessageSender source) { + ClientHttpRequestFactory requestFactory = source.getRequestFactory(); + if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { + return requestFactory; + } + Field field = ReflectionUtils.findField( + AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); + Assert.notNull(field, "Field must not be null"); + ReflectionUtils.makeAccessible(field); + do { + requestFactory = (ClientHttpRequestFactory) ReflectionUtils + .getField(field, requestFactory); + } + while (requestFactory instanceof AbstractClientHttpRequestFactoryWrapper); + return requestFactory; + } + + private static final class SimpleClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(SimpleClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(SimpleClientHttpRequestFactory source, + int timeout) { + source.setConnectTimeout(timeout); + } + + } + + private static final class HttpComponentsClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpComponentsClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout( + HttpComponentsClientHttpRequestFactory source, int timeout) { + source.setConnectTimeout(timeout); + } + + } + + private static final class OkHttp3ClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(OkHttp3ClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(OkHttp3ClientHttpRequestFactory source, + int timeout) { + source.setConnectTimeout(timeout); + } + + } + + } + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java new file mode 100644 index 000000000000..f619e6f9996b --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.springframework.ws.client.core.WebServiceTemplate; + +/** + * Callback interface that can be used to customize a {@link WebServiceTemplate}. + * + * @author Dmytro Nosan + */ +public interface WebServiceTemplateCustomizer { + + /** + * Callback to customize a {@link WebServiceTemplate} instance. + * @param webServiceTemplate the template to customize + */ + void customize(WebServiceTemplate webServiceTemplate); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java new file mode 100644 index 000000000000..5e0d4ce13fe2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Web Services client utilities. + */ + +package org.springframework.boot.webservices.client; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java new file mode 100644 index 000000000000..8ae3040b9513 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +/** + * Tests for + * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderCustomsMessageSenderTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void unknownSenderReadTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setReadTimeout(3000).setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + + @Test + public void unknownSenderConnectionTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage( + "with 'connectionTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setConnectionTimeout(3000).setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + + @Test + public void unknownRequestFactoryReadTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setReadTimeout(3000) + .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( + Mockito.mock(ClientHttpRequestFactory.class))) + .build(); + } + + @Test + public void unknownRequestFactoryConnectionTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage( + "with 'connectionTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setConnectionTimeout(3000) + .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( + Mockito.mock(ClientHttpRequestFactory.class))) + .build(); + } + + @Test + public void shouldBuildWithoutTimeouts() { + this.builder.setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java new file mode 100644 index 000000000000..f2cafa15c7c7 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.apache.http.client.config.RequestConfig; +import org.junit.Test; + +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void setTimeout() { + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils + .getField(factory, "requestConfig"); + assertThat(requestConfig).isNotNull(); + assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); + assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java new file mode 100644 index 000000000000..82f08a27de33 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.apache.http.client.HttpClient; +import org.apache.http.params.HttpConnectionParams; +import org.junit.Test; + +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.HttpComponentsMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for + * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. This + * test class check that builder will create HttpComponents by default if apache client is + * present in the classpath. + * + * @author Dmytro Nosan + */ +@SuppressWarnings("deprecation") +public class WebServiceTemplateBuilderHttpComponentsMessageSenderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + WebServiceTemplate webServiceTemplate = new WebServiceTemplateBuilder().build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpComponentsMessageSender.class); + + } + + @Test + public void setTimeout() { + HttpComponentsMessageSender sender = new HttpComponentsMessageSender(); + HttpClient httpClient = sender.getHttpClient(); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(HttpConnectionParams.getConnectionTimeout(httpClient.getParams())) + .isEqualTo(5000); + assertThat(HttpConnectionParams.getSoTimeout(httpClient.getParams())) + .isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java new file mode 100644 index 000000000000..3468091f6ee5 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import java.time.Duration; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will + * create HttpUrlConnectionMessageSender If Ok-http and Apache client are not present in + * the classpath. + * + * @author Dmytro Nosan + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions({ "httpclient-*.jar", "okhttp-*.jar" }) +public class WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + WebServiceTemplate webServiceTemplate = this.builder.build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + + } + + @Test + public void setTimeout() { + HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender(); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(ReflectionTestUtils.getField(sender, "connectionTimeout")) + .isEqualTo(Duration.ofMillis(5000)); + assertThat(ReflectionTestUtils.getField(sender, "readTimeout")) + .isEqualTo(Duration.ofMillis(2000)); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java new file mode 100644 index 000000000000..3d37a488f116 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import okhttp3.OkHttpClient; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will + * create ClientHttpRequestMessageSender (OkHttp3ClientHttpRequestFactory) if apache + * client is not present in the classpath + * + * @author Dmytro Nosan + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions("httpclient-*.jar") +public class WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + + WebServiceTemplate webServiceTemplate = this.builder.build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(ClientHttpRequestMessageSender.class); + + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) webServiceTemplate + .getMessageSenders()[0]; + + assertThat(sender.getRequestFactory()) + .isInstanceOf(OkHttp3ClientHttpRequestFactory.class); + + } + + @Test + public void setTimeout() { + OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + OkHttpClient client = (OkHttpClient) ReflectionTestUtils.getField(factory, + "client"); + + assertThat(client).isNotNull(); + + assertThat(client.connectTimeoutMillis()).isEqualTo(5000); + assertThat(client.readTimeoutMillis()).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java new file mode 100644 index 000000000000..e2f3c0a5c369 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.junit.Test; + +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void setTimeout() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(ReflectionTestUtils.getField(factory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(factory, "readTimeout")).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java new file mode 100644 index 000000000000..ffdffd404016 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java @@ -0,0 +1,520 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; + +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; + +import org.junit.Test; +import org.mockito.Mockito; + +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.client.core.FaultMessageResolver; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.interceptor.ClientInterceptor; +import org.springframework.ws.soap.client.core.SoapFaultMessageResolver; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void addInterceptors() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder.addInterceptors(f1) + .addInterceptors(f2).build(); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, + f2); + } + + @Test + public void addInterceptorsCollection() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addInterceptors(Collections.singletonList(f1)) + .addInterceptors(Collections.singleton(f2)).build(); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, + f2); + + } + + @Test + public void setInterceptors() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder.setInterceptors(f1) + .setInterceptors(f2).build(); + + assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); + } + + @Test + public void setInterceptorsCollection() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setInterceptors(Collections.singletonList(f1)) + .setInterceptors(Collections.singleton(f2)).build(); + + assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); + + } + + @Test + public void addCustomizers() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder.addCustomizers(customizer) + .addCustomizers(customizer1).build(); + + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + + } + + @Test + public void addCustomizersCollection() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder + .addCustomizers(Collections.singleton(customizer)) + .addCustomizers(Collections.singletonList(customizer1)).build(); + + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void setCustomizers() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder.setCustomizers(customizer) + .setCustomizers(customizer1).build(); + + assertThat(webServiceTemplate.getMarshaller()).isNull(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + + } + + @Test + public void setCustomizersCollection() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder + .setCustomizers(Collections.singleton(customizer)) + .setCustomizers(Collections.singletonList(customizer1)).build(); + + assertThat(webServiceTemplate.getMarshaller()).isNull(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void addWebServiceMessageSenders() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSenders(Collections.singleton(() -> sender)) + .addWebServiceMessageSenders(Collections.singletonList(() -> sender1)) + .build(); + + assertThat(webServiceTemplate.getMessageSenders()) + .containsExactlyInAnyOrder(sender, sender1); + } + + @Test + public void setWebServiceMessageSenders() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSenders(Collections.singleton(() -> sender)) + .setWebServiceMessageSenders(Collections.singletonList(() -> sender1)) + .build(); + + assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) + .contains(sender1); + + } + + @Test + public void addWebServiceMessageSenderClass() { + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSender(ClientHttpRequestMessageSender.class) + .addWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(2); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(ClientHttpRequestMessageSender.class); + assertThat(webServiceTemplate.getMessageSenders()[1]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + } + + @Test + public void setWebServiceMessageSenderClass() { + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSender(ClientHttpRequestMessageSender.class) + .setWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + + } + + @Test + public void addWebServiceMessageSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSender(() -> sender) + .addWebServiceMessageSender(() -> sender1).build(); + + assertThat(webServiceTemplate.getMessageSenders()) + .containsExactlyInAnyOrder(sender, sender1); + } + + @Test + public void setWebServiceMessageSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSender(() -> sender) + .setWebServiceMessageSender(() -> sender1).build(); + + assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) + .contains(sender1); + + } + + @Test + public void setCheckConnectionForFault() { + MockWebServiceTemplate webServiceTemplate = this.builder + .setCheckConnectionForFault(false).build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.isCheckConnectionForFault()).isFalse(); + } + + @Test + public void setCheckConnectionForError() { + + MockWebServiceTemplate webServiceTemplate = this.builder + .setCheckConnectionForError(false).build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.isCheckConnectionForError()).isFalse(); + + } + + @Test + public void setTransformerFactoryClass() { + MockWebServiceTemplate webServiceTemplate = this.builder + .setTransformerFactoryClass(SAXTransformerFactory.class) + .build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.getTransformerFactoryClass()) + .isEqualTo(SAXTransformerFactory.class); + + } + + @Test + public void setWebServiceMessageFactory() { + + SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageFactory(messageFactory).build(); + + assertThat(webServiceTemplate.getMessageFactory()).isEqualTo(messageFactory); + + } + + @Test + public void setMarshaller() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + + WebServiceTemplate webServiceTemplate = this.builder + .setMarshaller(jaxb2Marshaller).build(); + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void setUnmarshaller() { + Jaxb2Marshaller jaxb2Unmarshaller = new Jaxb2Marshaller(); + + WebServiceTemplate webServiceTemplate = this.builder + .setUnmarshaller(jaxb2Unmarshaller).build(); + + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Unmarshaller); + } + + @Test + public void setFaultMessageResolver() { + + FaultMessageResolver faultMessageResolver = new SoapFaultMessageResolver(); + WebServiceTemplate webServiceTemplate = this.builder + .setFaultMessageResolver(faultMessageResolver).build(); + + assertThat(webServiceTemplate.getFaultMessageResolver()) + .isEqualTo(faultMessageResolver); + } + + @Test + public void setDefaultUri() { + URI uri = URI.create("http://localhost:8080"); + + WebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()) + .build(); + + assertThat(webServiceTemplate.getDestinationProvider().getDestination()) + .isEqualTo(uri); + + } + + @Test + public void setDestinationProvider() { + URI uri = URI.create("http://localhost:8080"); + + WebServiceTemplate webServiceTemplate = this.builder + .setDestinationProvider(() -> uri).build(); + + assertThat(webServiceTemplate.getDestinationProvider().getDestination()) + .isEqualTo(uri); + + } + + @Test + public void shouldNotOverrideDefaultSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + webServiceTemplate.setMessageSender(sender); + + this.builder.detectWebServiceMessageSender(false).configure(webServiceTemplate); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1).contains(sender); + + } + + @Test + public void addInterceptorsToExistingWebServiceTemplate() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + webServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 }); + + this.builder.addInterceptors(f2).configure(webServiceTemplate); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, + f1); + } + + @Test(expected = IllegalArgumentException.class) + public void setInterceptorsArrayNull() { + this.builder.setInterceptors((ClientInterceptor[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setInterceptorsCollectionNull() { + this.builder.setInterceptors((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addInterceptorsArrayNull() { + this.builder.addInterceptors((ClientInterceptor[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addInterceptorsCollectionNull() { + this.builder.addInterceptors((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setCustomizersArrayNull() { + this.builder.setCustomizers((WebServiceTemplateCustomizer[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setCustomizersCollectionNull() { + this.builder + .setCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addCustomizersArrayNull() { + this.builder + .addCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addCustomizersCollectionNull() { + this.builder + .addCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSendersNull() { + this.builder.setWebServiceMessageSenders(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSendersNull() { + this.builder.addWebServiceMessageSenders(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSenderClassNull() { + this.builder.setWebServiceMessageSender( + (Class) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSenderClassNull() { + this.builder.addWebServiceMessageSender( + (Class) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSenderSupplierNull() { + this.builder.setWebServiceMessageSender( + (Supplier) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSenderSupplierNull() { + this.builder.addWebServiceMessageSender( + (Supplier) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageFactoryNull() { + this.builder.setWebServiceMessageFactory(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setUnmarshallerNull() { + this.builder.setUnmarshaller(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setMarshallerNull() { + this.builder.setMarshaller(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setTransformerFactoryClassNull() { + this.builder.setTransformerFactoryClass(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setDefaultUriNull() { + this.builder.setDefaultUri(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setDestinationProviderNull() { + this.builder.setDestinationProvider(null).build(); + } + + private static class MockWebServiceTemplate extends WebServiceTemplate { + + private boolean checkConnectionForError; + + private boolean checkConnectionForFault; + + private Class transformerFactoryClass; + + boolean isCheckConnectionForError() { + return this.checkConnectionForError; + } + + @Override + public void setCheckConnectionForError(boolean checkConnectionForError) { + this.checkConnectionForError = checkConnectionForError; + } + + boolean isCheckConnectionForFault() { + return this.checkConnectionForFault; + } + + @Override + public void setCheckConnectionForFault(boolean checkConnectionForFault) { + this.checkConnectionForFault = checkConnectionForFault; + } + + Class getTransformerFactoryClass() { + return this.transformerFactoryClass; + } + + @Override + public void setTransformerFactoryClass( + Class transformerFactoryClass) { + this.transformerFactoryClass = transformerFactoryClass; + } + + } + +} From ef9c1a8e35d82ac8465d1e37ca32938086a8d8fc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 1 Jun 2018 11:48:43 +0200 Subject: [PATCH 093/701] Extract ClientHttpRequestFactory detection to its own class See gh-12707 --- .../ClientHttpRequestFactorySupplier.java | 65 +++++++++++++++++++ .../boot/web/client/RestTemplateBuilder.java | 31 +-------- 2 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java new file mode 100644 index 000000000000..f55039f23394 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2018 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.web.client; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.springframework.beans.BeanUtils; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.util.ClassUtils; + +/** + * A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate + * based on the available implementations on the classpath. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class ClientHttpRequestFactorySupplier + implements Supplier { + + private static final Map REQUEST_FACTORY_CANDIDATES; + + static { + Map candidates = new LinkedHashMap<>(); + candidates.put("org.apache.http.client.HttpClient", + "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"); + candidates.put("okhttp3.OkHttpClient", + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); + REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + } + + @Override + public ClientHttpRequestFactory get() { + for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES + .entrySet()) { + ClassLoader classLoader = getClass().getClassLoader(); + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class factoryClass = ClassUtils.resolveClassName(candidate.getValue(), + classLoader); + return (ClientHttpRequestFactory) BeanUtils + .instantiateClass(factoryClass); + } + } + return new SimpleClientHttpRequestFactory(); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 58d464deb419..5038a5ecd0e1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -23,9 +23,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -33,11 +31,9 @@ import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthorizationInterceptor; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import org.springframework.web.client.ResponseErrorHandler; @@ -64,17 +60,6 @@ */ public class RestTemplateBuilder { - private static final Map REQUEST_FACTORY_CANDIDATES; - - static { - Map candidates = new LinkedHashMap<>(); - candidates.put("org.apache.http.client.HttpClient", - "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"); - candidates.put("okhttp3.OkHttpClient", - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); - REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); - } - private final boolean detectRequestFactory; private final String rootUri; @@ -561,7 +546,7 @@ private void configureRequestFactory(RestTemplate restTemplate) { requestFactory = this.requestFactorySupplier.get(); } else if (this.detectRequestFactory) { - requestFactory = detectRequestFactory(); + requestFactory = new ClientHttpRequestFactorySupplier().get(); } if (requestFactory != null) { ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary( @@ -590,20 +575,6 @@ private ClientHttpRequestFactory unwrapRequestFactoryIfNecessary( return unwrappedRequestFactory; } - private ClientHttpRequestFactory detectRequestFactory() { - for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES - .entrySet()) { - ClassLoader classLoader = getClass().getClassLoader(); - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class factoryClass = ClassUtils.resolveClassName(candidate.getValue(), - classLoader); - return (ClientHttpRequestFactory) BeanUtils - .instantiateClass(factoryClass); - } - } - return new SimpleClientHttpRequestFactory(); - } - private Set append(Set set, T addition) { Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); result.add(addition); From 8bcea0d8cccc30f202a49c02ad4638244748eb97 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 31 May 2018 12:28:45 +0200 Subject: [PATCH 094/701] Polish "Add auto-configuration for WebServiceTemplate" Closes gh-1270 --- .../WebServiceTemplateAutoConfiguration.java | 6 +- ...ServiceTemplateAutoConfigurationTests.java | 106 +- .../main/asciidoc/spring-boot-features.adoc | 75 +- spring-boot-project/spring-boot/pom.xml | 10 +- .../HttpWebServiceMessageSenderBuilder.java | 124 ++ .../client/WebServiceTemplateBuilder.java | 1007 +++++------------ .../client/WebServiceTemplateCustomizer.java | 1 + .../boot/webservices/client/package-info.java | 1 - ...SenderBuilderOkHttp3IntegrationTests.java} | 55 +- ...geSenderBuilderSimpleIntegrationTests.java | 71 ++ ...tpWebServiceMessageSenderBuilderTests.java | 84 ++ ...plateBuilderCustomsMessageSenderTests.java | 93 -- ...mponentsClientHttpRequestFactoryTests.java | 55 - ...ilderHttpComponentsMessageSenderTests.java | 67 -- ...erHttpUrlConnectionMessageSenderTests.java | 70 -- ...erSimpleClientHttpRequestFactoryTests.java | 52 - .../WebServiceTemplateBuilderTests.java | 598 ++++------ 17 files changed, 930 insertions(+), 1545 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java rename spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/{WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java => HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java} (55%) create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java index e12ee5b8bcd5..d7a2edfeb244 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java @@ -37,10 +37,10 @@ * {@link EnableAutoConfiguration Auto-configuration} for {@link WebServiceTemplate}. * * @author Dmytro Nosan + * @since 2.1.0 */ @Configuration -@ConditionalOnClass({ WebServiceTemplateBuilder.class, WebServiceTemplate.class, - Unmarshaller.class, Marshaller.class }) +@ConditionalOnClass({ WebServiceTemplate.class, Unmarshaller.class, Marshaller.class }) public class WebServiceTemplateAutoConfiguration { private final ObjectProvider> webServiceTemplateCustomizers; @@ -59,7 +59,7 @@ public WebServiceTemplateBuilder webServiceTemplateBuilder() { if (!CollectionUtils.isEmpty(customizers)) { customizers = new ArrayList<>(customizers); AnnotationAwareOrderComparator.sort(customizers); - builder = builder.setCustomizers(customizers); + builder = builder.customizers(customizers); } return builder; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java index d60b88ca6555..6d647e104e08 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java @@ -16,82 +16,94 @@ package org.springframework.boot.autoconfigure.webservices.client; -import org.junit.After; +import java.util.function.Consumer; + import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link WebServiceTemplateAutoConfiguration - * WebServiceTemplateAutoConfiguration}. + * Tests for {@link WebServiceTemplateAutoConfiguration}. * + * @author Stephane Nicoll * @author Dmytro Nosan */ public class WebServiceTemplateAutoConfigurationTests { - private AnnotationConfigApplicationContext context; + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(WebServiceTemplateAutoConfiguration.class)); - @After - public void close() { - if (this.context != null) { - this.context.close(); - } + @Test + public void autoConfiguredBuilderShouldNotHaveMarshallerAndUnmarshaller() { + this.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getUnmarshaller()).isNull(); + assertThat(webServiceTemplate.getMarshaller()).isNull(); + })); } @Test - public void webServiceTemplateShouldNotHaveMarshallerAndUnmarshaller() { - load(WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getUnmarshaller()).isNull(); - assertThat(webServiceTemplate.getMarshaller()).isNull(); + public void autoConfiguredBuilderShouldHaveHttpMessageSenderByDefault() { + this.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + WebServiceMessageSender messageSender = webServiceTemplate + .getMessageSenders()[0]; + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + })); } @Test - public void webServiceTemplateShouldUserCustomBuilder() { - load(CustomWebServiceTemplateBuilderConfig.class, WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getMarshaller()).isNotNull(); + public void webServiceTemplateWhenHasCustomBuilderShouldUseCustomBuilder() { + this.contextRunner + .withUserConfiguration(CustomWebServiceTemplateBuilderConfig.class) + .run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getMarshaller()) + .isSameAs(CustomWebServiceTemplateBuilderConfig.marshaller); + })); } @Test public void webServiceTemplateShouldApplyCustomizer() { - load(WebServiceTemplateCustomizerConfig.class, WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getUnmarshaller()).isNotNull(); + this.contextRunner.withUserConfiguration(WebServiceTemplateCustomizerConfig.class) + .run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getUnmarshaller()) + .isSameAs(WebServiceTemplateCustomizerConfig.unmarshaller); + })); } @Test public void builderShouldBeFreshForEachUse() { - load(DirtyWebServiceTemplateConfig.class); + this.contextRunner.withUserConfiguration(DirtyWebServiceTemplateConfig.class) + .run((context) -> { + assertThat(context).hasNotFailed(); + }); } - private void load(Class... config) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(config); - ctx.register(WebServiceTemplateAutoConfiguration.class); - ctx.refresh(); - this.context = ctx; - } - - @Configuration - static class WebServiceTemplateConfig { - - @Bean - public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { - return builder.build(); - } - + private ContextConsumer assertWebServiceTemplateBuilder( + Consumer builder) { + return (context) -> { + assertThat(context).hasSingleBean(WebServiceTemplateBuilder.class); + builder.accept(context.getBean(WebServiceTemplateBuilder.class)); + }; } @Configuration @@ -120,7 +132,7 @@ public WebServiceTemplate webServiceTemplateTwo( } private void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) { - builder.addCustomizers((webServiceTemplate) -> { + builder.additionalCustomizers((webServiceTemplate) -> { throw new IllegalStateException(); }); } @@ -130,9 +142,11 @@ private void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) { @Configuration static class CustomWebServiceTemplateBuilderConfig { + private static final Marshaller marshaller = new Jaxb2Marshaller(); + @Bean public WebServiceTemplateBuilder webServiceTemplateBuilder() { - return new WebServiceTemplateBuilder().setMarshaller(new Jaxb2Marshaller()); + return new WebServiceTemplateBuilder().setMarshaller(marshaller); } } @@ -140,9 +154,11 @@ public WebServiceTemplateBuilder webServiceTemplateBuilder() { @Configuration static class WebServiceTemplateCustomizerConfig { + private static final Unmarshaller unmarshaller = new Jaxb2Marshaller(); + @Bean public WebServiceTemplateCustomizer webServiceTemplateCustomizer() { - return (ws) -> ws.setUnmarshaller(new Jaxb2Marshaller()); + return (ws) -> ws.setUnmarshaller(unmarshaller); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index beb46654bf8a..ed40a6892ea1 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,6 +5634,7 @@ The following code shows a typical example: ---- + [[boot-features-webclient-customization]] === WebClient Customization There are three main approaches to `WebClient` customization, depending on how broadly you @@ -5652,35 +5653,6 @@ the point of injection. Finally, you can fall back to the original API and use `WebClient.create()`. In that case, no auto-configuration or `WebClientCustomizer` is applied. -[[boot-features-webservicetemplate]] -== Calling Web Services with `WebServiceTemplate` -If you need to call remote WEB services from your application, you can use the Spring -Framework's {spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. Since -`WebServiceTemplate` instances often need to be customized before being used, Spring Boot does -not provide any single auto-configured `WebServiceTemplate` bean. It does, however, -auto-configure a `WebServiceTemplateBuilder`, which can be used to create `WebServiceTemplate` -instances when needed. - -The following code shows a typical example: - -[source,java,indent=0] ----- - @Service - public class MyService { - - private final WebServiceTemplate webServiceTemplate; - - public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { - this.webServiceTemplate = webServiceTemplateBuilder.build(); - } - - public DetailsResp someCall(DetailsReq detailsReq) { - return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); - - } - - } ----- [[boot-features-validation]] @@ -7416,6 +7388,51 @@ following example: +[[boot-features-webservices-template]] +== Calling Web Services with `WebServiceTemplate` +If you need to call remote Web services from your application, you can use the +{spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. +Since `WebServiceTemplate` instances often need to be customized before being used, Spring +Boot does not provide any single auto-configured `WebServiceTemplate` bean. It does, +however, auto-configure a `WebServiceTemplateBuilder`, which can be used to create +`WebServiceTemplate` instances when needed. + +The following code shows a typical example: + +[source,java,indent=0] +---- + @Service + public class MyService { + + private final WebServiceTemplate webServiceTemplate; + + public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { + this.webServiceTemplate = webServiceTemplateBuilder.build(); + } + + public DetailsResp someWsCall(DetailsReq detailsReq) { + return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); + + } + + } +---- + +By default, `WebServiceTemplateBuilder` detects a suitable HTTP-based +`WebServiceMessageSender` using the available HTTP client libraries on the classpath. You +can also customize read and connection timeouts as follows: + +[source,java,indent=0] +---- + @Bean + public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { + return builder.messageSenders(new HttpWebServiceMessageSenderBuilder() + .setReadTimeout(5000).setConnectionTimeout(2000).build()).build(); + } +---- + + + [[boot-features-developing-auto-configuration]] == Creating Your Own Auto-configuration If you work in a company that develops shared libraries, or if you work on an open-source diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index dcbecba69141..b268584e087b 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -245,11 +245,6 @@ spring-orm true - - org.springframework.ws - spring-ws-core - true - org.springframework spring-oxm @@ -280,6 +275,11 @@ spring-security-web true + + org.springframework.ws + spring-ws-core + true + org.yaml snakeyaml diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java new file mode 100644 index 000000000000..e5c998b24680 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import java.lang.reflect.Method; +import java.util.function.Supplier; + +import org.springframework.boot.web.client.ClientHttpRequestFactorySupplier; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +/** + * {@link WebServiceMessageSender} builder that can detect a suitable HTTP library based + * on the classpath. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class HttpWebServiceMessageSenderBuilder { + + private Integer connectionTimeout; + + private Integer readTimeout; + + private Supplier requestFactorySupplier; + + /** + * Set the connection timeout in milliseconds. + * @param connectionTimeout the connection timeout in milliseconds + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder setConnectionTimeout( + int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return this; + } + + /** + * Set the read timeout in milliseconds. + * @param readTimeout the read timeout in milliseconds + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + /** + * Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called + * to create the HTTP-based {@link WebServiceMessageSender}. + * @param requestFactorySupplier the supplier for the request factory + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder requestFactory( + Supplier requestFactorySupplier) { + Assert.notNull(requestFactorySupplier, + "RequestFactory Supplier must not be null"); + this.requestFactorySupplier = requestFactorySupplier; + return this; + } + + public WebServiceMessageSender build() { + ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null + ? this.requestFactorySupplier.get() + : new ClientHttpRequestFactorySupplier().get()); + if (this.connectionTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.connectionTimeout, + "setConnectTimeout").customize(requestFactory); + } + if (this.readTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") + .customize(requestFactory); + } + return new ClientHttpRequestMessageSender(requestFactory); + } + + /** + * {@link ClientHttpRequestFactory} customizer to call a "set timeout" method. + */ + private static class TimeoutRequestFactoryCustomizer { + + private final int timeout; + + private final String methodName; + + TimeoutRequestFactoryCustomizer(int timeout, String methodName) { + this.timeout = timeout; + this.methodName = methodName; + } + + public void customize(ClientHttpRequestFactory factory) { + ReflectionUtils.invokeMethod(findMethod(factory), factory, this.timeout); + } + + private Method findMethod(ClientHttpRequestFactory factory) { + Method method = ReflectionUtils.findMethod(factory.getClass(), + this.methodName, int.class); + if (method != null) { + return method; + } + throw new IllegalStateException("Request factory " + factory.getClass() + + " does not have a " + this.methodName + "(int) method"); + } + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java index 4a185900d58b..c8d831c3fbbe 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -16,69 +16,46 @@ package org.springframework.boot.webservices.client; -import java.lang.reflect.Field; import java.net.URI; -import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Optional; import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; import javax.xml.transform.TransformerFactory; import org.springframework.beans.BeanUtils; -import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; -import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.client.support.destination.DestinationProvider; import org.springframework.ws.client.support.interceptor.ClientInterceptor; import org.springframework.ws.transport.WebServiceMessageSender; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; -import org.springframework.ws.transport.http.HttpComponentsMessageSender; -import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; /** - * Builder that can be used to configure and create a - * {@link org.springframework.ws.client.core.WebServiceTemplate}. By default the built - * {@link org.springframework.ws.client.core.WebServiceTemplate} will attempt to use the - * most suitable {@link org.springframework.ws.transport.WebServiceMessageSender}, call - * {@link #detectWebServiceMessageSender(boolean) detectWebServiceMessageSender(false)} if - * you prefer to keep the default. In a typical auto-configured Spring Boot application - * this builder is available as a bean and can be injected whenever a - * {@link WebServiceTemplate} is needed. + * Builder that can be used to configure and create a {@link WebServiceTemplate}. Provides + * convenience methods to register {@link #messageSenders(WebServiceMessageSender...) + * message senders}, {@link #interceptors(ClientInterceptor...) client interceptors} and + * {@link #customizers(WebServiceTemplateCustomizer...) customizers}. + *

+ * By default the built {@link WebServiceTemplate} uses the most suitable HTTP-based + * {@link WebServiceMessageSender}, call {@link #detectHttpMessageSender(boolean) + * detectHttpMessageSender(false)} if you prefer to keep the default. In a typical + * auto-configured Spring Boot application this builder is available as a bean and can be + * injected whenever a {@link WebServiceTemplate} is needed. * * @author Dmytro Nosan + * @author Stephane Nicoll + * @since 2.1.0 */ public class WebServiceTemplateBuilder { - private static final Map> MESSAGE_SENDER_FACTORY_CLASSES; - - static { - Map> candidates = new LinkedHashMap<>(); - candidates.put("org.apache.http.client.HttpClient", - HttpComponentsMessageSenderFactory.class); - candidates.put("org.springframework.http.client.ClientHttpRequestFactory", - ClientHttpRequestMessageSenderFactory.class); - MESSAGE_SENDER_FACTORY_CLASSES = Collections.unmodifiableMap(candidates); - } + private final boolean detectHttpMessageSender; private final Set interceptors; @@ -86,9 +63,7 @@ public class WebServiceTemplateBuilder { private final Set customizers; - private final Set> webServiceMessageSenderSuppliers; - - private final Set webServiceMessageSenderCustomizers; + private final WebServiceMessageSenders messageSenders; private final Marshaller marshaller; @@ -100,141 +75,210 @@ public class WebServiceTemplateBuilder { private final WebServiceMessageFactory messageFactory; - private final boolean detectWebServiceMessageSender; - public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) { - this(Collections.emptySet(), Collections.emptySet(), + this(true, Collections.emptySet(), Collections.emptySet(), append(Collections.emptySet(), customizers), - Collections.emptySet(), Collections.emptySet(), null, null, null, null, - null, true); + new WebServiceMessageSenders(), null, null, null, null, null); } - private WebServiceTemplateBuilder(Set interceptors, + private WebServiceTemplateBuilder(boolean detectHttpMessageSender, + Set interceptors, Set internalCustomizers, Set customizers, - Set> webServiceMessageSenderSuppliers, - Set webServiceMessageSenderCustomizers, - Marshaller marshaller, Unmarshaller unmarshaller, - DestinationProvider destinationProvider, + WebServiceMessageSenders messageSenders, Marshaller marshaller, + Unmarshaller unmarshaller, DestinationProvider destinationProvider, Class transformerFactoryClass, - WebServiceMessageFactory messageFactory, - boolean detectWebServiceMessageSender) { + WebServiceMessageFactory messageFactory) { this.interceptors = interceptors; this.internalCustomizers = internalCustomizers; this.customizers = customizers; - this.webServiceMessageSenderSuppliers = webServiceMessageSenderSuppliers; - this.webServiceMessageSenderCustomizers = webServiceMessageSenderCustomizers; + this.messageSenders = messageSenders; + this.detectHttpMessageSender = detectHttpMessageSender; this.marshaller = marshaller; this.unmarshaller = unmarshaller; this.destinationProvider = destinationProvider; this.transformerFactoryClass = transformerFactoryClass; this.messageFactory = messageFactory; - this.detectWebServiceMessageSender = detectWebServiceMessageSender; } /** - * Set {@link ClientInterceptor ClientInterceptors} that should be used with the - * {@link WebServiceTemplate}. Interceptors are applied in the order that they were - * added after builder configuration has been applied. - * - * Note! Override existing interceptors + * Set if a suitable HTTP-based {@link WebServiceMessageSender} should be detected + * based on the classpath. Default is {@code true}. + * @param detectHttpMessageSender if a HTTP-based {@link WebServiceMessageSender} + * should be detected + * @return a new builder instance + * @see HttpWebServiceMessageSenderBuilder + */ + public WebServiceTemplateBuilder detectHttpMessageSender( + boolean detectHttpMessageSender) { + return new WebServiceTemplateBuilder(detectHttpMessageSender, this.interceptors, + this.internalCustomizers, this.customizers, this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); + } + + /** + * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be + * used with the {@link WebServiceTemplate}. Setting this value will replace any + * previously defined message senders, including the HTTP-based message sender, if + * any. Consider using {@link #additionalMessageSenders(WebServiceMessageSender...)} + * to keep it with user-defined message senders. + * @param messageSenders the message senders to set + * @return a new builder instance. + * @see #additionalMessageSenders(WebServiceMessageSender...) + * @see #detectHttpMessageSender(boolean) + */ + public WebServiceTemplateBuilder messageSenders( + WebServiceMessageSender... messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return messageSenders(Arrays.asList(messageSenders)); + } + + /** + * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be + * used with the {@link WebServiceTemplate}. Setting this value will replace any + * previously defined message senders, including the HTTP-based message sender, if + * any. Consider using {@link #additionalMessageSenders(Collection)} to keep it with + * user-defined message senders. + * @param messageSenders the message senders to set + * @return a new builder instance. + * @see #additionalMessageSenders(Collection) + * @see #detectHttpMessageSender(boolean) + */ + public WebServiceTemplateBuilder messageSenders( + Collection messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders.set(messageSenders), this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); + } + + /** + * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should + * be used with the {@link WebServiceTemplate}. + * @param messageSenders the message senders to add + * @return a new builder instance. + * @see #messageSenders(WebServiceMessageSender...) + */ + public WebServiceTemplateBuilder additionalMessageSenders( + WebServiceMessageSender... messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return additionalMessageSenders(Arrays.asList(messageSenders)); + } + + /** + * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should + * be used with the {@link WebServiceTemplate}. + * @param messageSenders the message senders to add + * @return a new builder instance. + * @see #messageSenders(Collection) + */ + public WebServiceTemplateBuilder additionalMessageSenders( + Collection messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders.add(messageSenders), this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); + } + + /** + * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Setting this value will replace any previously defined + * interceptors. * @param interceptors the interceptors to set * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #additionalInterceptors(ClientInterceptor...) */ - public WebServiceTemplateBuilder setInterceptors(ClientInterceptor... interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return setInterceptors(Arrays.asList(interceptors)); + public WebServiceTemplateBuilder interceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "Interceptors must not be null"); + return interceptors(Arrays.asList(interceptors)); } /** - * Set {@link ClientInterceptor ClientInterceptors} that should be used with the - * {@link WebServiceTemplate}. Interceptors are applied in the order that they were - * added after builder configuration has been applied. - * - * Note! Override existing interceptors + * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Setting this value will replace any previously defined + * interceptors. * @param interceptors the interceptors to set * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #additionalInterceptors(Collection) */ - public WebServiceTemplateBuilder setInterceptors( + public WebServiceTemplateBuilder interceptors( Collection interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return new WebServiceTemplateBuilder( + Assert.notNull(interceptors, "Interceptors must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, append(Collections.emptySet(), interceptors), - this.internalCustomizers, this.customizers, - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.internalCustomizers, this.customizers, this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); } /** * Add additional {@link ClientInterceptor ClientInterceptors} that should be used - * with the {@link WebServiceTemplate}. Interceptors are applied in the order that - * they were added after builder configuration has been applied. + * with the {@link WebServiceTemplate}. * @param interceptors the interceptors to add * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #interceptors(ClientInterceptor...) */ - public WebServiceTemplateBuilder addInterceptors(ClientInterceptor... interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return addInterceptors(Arrays.asList(interceptors)); + public WebServiceTemplateBuilder additionalInterceptors( + ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "Interceptors must not be null"); + return additionalInterceptors(Arrays.asList(interceptors)); } /** * Add additional {@link ClientInterceptor ClientInterceptors} that should be used - * with the {@link WebServiceTemplate}. Interceptors are applied in the order that - * they were added after builder configuration has been applied. + * with the {@link WebServiceTemplate}. * @param interceptors the interceptors to add * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #interceptors(Collection) */ - public WebServiceTemplateBuilder addInterceptors( + public WebServiceTemplateBuilder additionalInterceptors( Collection interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return new WebServiceTemplateBuilder(append(this.interceptors, interceptors), - this.internalCustomizers, this.customizers, - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + Assert.notNull(interceptors, "Interceptors must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + append(this.interceptors, interceptors), this.internalCustomizers, + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order - * that they were added after builder configuration has been applied. - * - * Note! Override existing customizers + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance + * @see #additionalCustomizers(WebServiceTemplateCustomizer...) */ - - public WebServiceTemplateBuilder setCustomizers( - Collection customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - append(Collections.emptySet(), customizers), - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + public WebServiceTemplateBuilder customizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return customizers(Arrays.asList(customizers)); } /** * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order - * that they were added after builder configuration has been applied. - * - * Note! Override existing customizers + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance + * @see #additionalCustomizers(Collection) */ - public WebServiceTemplateBuilder setCustomizers( - WebServiceTemplateCustomizer... customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return setCustomizers(Arrays.asList(customizers)); + public WebServiceTemplateBuilder customizers( + Collection customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, + append(Collections.emptySet(), customizers), + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** @@ -243,11 +287,12 @@ public WebServiceTemplateBuilder setCustomizers( * in the order that they were added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance + * @see #customizers(WebServiceTemplateCustomizer...) */ - public WebServiceTemplateBuilder addCustomizers( + public WebServiceTemplateBuilder additionalCustomizers( WebServiceTemplateCustomizer... customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return addCustomizers(Arrays.asList(customizers)); + Assert.notNull(customizers, "Customizers must not be null"); + return additionalCustomizers(Arrays.asList(customizers)); } /** @@ -256,342 +301,160 @@ public WebServiceTemplateBuilder addCustomizers( * in the order that they were added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance + * @see #customizers(Collection) */ - - public WebServiceTemplateBuilder addCustomizers( + public WebServiceTemplateBuilder additionalCustomizers( Collection customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - append(this.customizers, customizers), - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Sets the {@code Suppliers} of {@link WebServiceMessageSender} that should be called - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - */ - - public WebServiceTemplateBuilder setWebServiceMessageSenders( - Collection> webServiceMessageSenderSuppliers) { - Assert.notNull(webServiceMessageSenderSuppliers, - "webServiceMessageSenderSuppliers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, - append(Collections - .>emptySet(), - webServiceMessageSenderSuppliers), - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + Assert.notNull(customizers, "Customizers must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, + append(this.customizers, customizers), this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); } /** - * Add additional {@code Suppliers} of {@link WebServiceMessageSender} that should be - * called each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * Indicates whether the connection should be checked for fault indicators + * ({@code true}), or whether we should rely on the message only ({@code false}). + * @param checkConnectionForFault whether to check for fault indicators * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see WebServiceTemplate#setCheckConnectionForFault(boolean) */ - public WebServiceTemplateBuilder addWebServiceMessageSenders( - Collection> webServiceMessageSenderSuppliers) { - Assert.notNull(webServiceMessageSenderSuppliers, - "webServiceMessageSenderSuppliers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, - append(this.webServiceMessageSenderSuppliers, - webServiceMessageSenderSuppliers), - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Set {@link WebServiceTemplate#setCheckConnectionForFault(boolean) - * setCheckConnectionForFault} on the underlying. - * @param checkConnectionForFault Specify whether checkConnectionForFault should be - * enabled or not. - * @return a new builder instance. - **/ public WebServiceTemplateBuilder setCheckConnectionForFault( boolean checkConnectionForFault) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new CheckConnectionFaultCustomizer(checkConnectionForFault)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setCheckConnectionForError(boolean) - * setCheckConnectionForError} on the underlying. - * @param checkConnectionForError Specify whether checkConnectionForError should be - * enabled or not. + * Indicates whether the connection should be checked for error indicators + * ({@code true}), or whether these should be ignored ({@code false}). + * @param checkConnectionForError whether to check for error indicators * @return a new builder instance. - **/ - + * @see WebServiceTemplate#setCheckConnectionForError(boolean) + */ public WebServiceTemplateBuilder setCheckConnectionForError( boolean checkConnectionForError) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new CheckConnectionForErrorCustomizer(checkConnectionForError)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Sets the {@code Supplier} of {@link WebServiceMessageSender} that should be called - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderSupplier Supplier for the messageSender - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #setWebServiceMessageSenders(Collection) - */ - - public WebServiceTemplateBuilder setWebServiceMessageSender( - Supplier webServiceMessageSenderSupplier) { - Assert.notNull(webServiceMessageSenderSupplier, - "webServiceMessageSenderSupplier must not be null"); - return setWebServiceMessageSenders( - Collections.singleton(webServiceMessageSenderSupplier)); - } - - /** - * Add additional {@code Supplier} of {@link WebServiceMessageSender} that should be - * called each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderSupplier Supplier for the messageSender - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #addWebServiceMessageSenders(Collection) - */ - public WebServiceTemplateBuilder addWebServiceMessageSender( - Supplier webServiceMessageSenderSupplier) { - Assert.notNull(webServiceMessageSenderSupplier, - "webServiceMessageSenderSupplier must not be null"); - return addWebServiceMessageSenders( - Collections.singleton(webServiceMessageSenderSupplier)); - } - - /** - * Sets the {@code Class} of {@link WebServiceMessageSender} that should be created - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderClass {@code Class} of - * {@link WebServiceMessageSender} - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #setWebServiceMessageSender(Supplier) - * @see BeanUtils#instantiateClass(Class) - */ - - public WebServiceTemplateBuilder setWebServiceMessageSender( - Class webServiceMessageSenderClass) { - Assert.notNull(webServiceMessageSenderClass, - "webServiceMessageSenderClass must not be null"); - return setWebServiceMessageSender( - supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); - } - - /** - * Add additional {@code Class} of {@link WebServiceMessageSender} that should be - * created each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderClass {@code Class} of - * {@link WebServiceMessageSender} - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #addWebServiceMessageSender(Supplier) - * @see BeanUtils#instantiateClass(Class) - */ - public WebServiceTemplateBuilder addWebServiceMessageSender( - Class webServiceMessageSenderClass) { - Assert.notNull(webServiceMessageSenderClass, - "webServiceMessageSenderClass must not be null"); - return addWebServiceMessageSender( - supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Sets the message factory used for creating messages. - * @param messageFactory instance of WebServiceMessageFactory + * Sets the {@link WebServiceMessageFactory} to use for creating messages. + * @param messageFactory the message factory to use for creating messages * @return a new builder instance. * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory) **/ - public WebServiceTemplateBuilder setWebServiceMessageFactory( WebServiceMessageFactory messageFactory) { Assert.notNull(messageFactory, "messageFactory must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - messageFactory, this.detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, messageFactory); } /** - * Set {@link WebServiceTemplate#setUnmarshaller(Unmarshaller) unmarshaller} on the - * underlying. - * @param unmarshaller message unmarshaller + * Set the {@link Unmarshaller} to use to deserialize messages. + * @param unmarshaller the message unmarshaller * @return a new builder instance. * @see WebServiceTemplate#setUnmarshaller(Unmarshaller) **/ public WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) { - Assert.notNull(unmarshaller, "unmarshaller must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, unmarshaller, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setMarshaller(Marshaller) marshaller} on the - * underlying. - * @param marshaller message marshaller + * Set the {@link Marshaller} to use to serialize messages. + * @param marshaller the message marshaller * @return a new builder instance. * @see WebServiceTemplate#setMarshaller(Marshaller) **/ public WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) { - Assert.notNull(marshaller, "marshaller must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, marshaller, this.unmarshaller, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.messageFactory); } /** - * Sets the connection timeout in milliseconds on the underlying. - * @param connectionTimeout the connection timeout in milliseconds + * Set the {@link FaultMessageResolver} to use. + * @param faultMessageResolver the fault message resolver to use * @return a new builder instance. - * @throws java.lang.IllegalStateException if the underlying source doesn't support a - * connection timeout. + * @see WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) */ - public WebServiceTemplateBuilder setConnectionTimeout(int connectionTimeout) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - append(this.webServiceMessageSenderCustomizers, - new ConnectionTimeoutWebServiceMessageSenderCustomizer( - connectionTimeout)), - this.marshaller, this.unmarshaller, this.destinationProvider, - this.transformerFactoryClass, this.messageFactory, - this.detectWebServiceMessageSender); - } - - /** - * Sets the read timeout in milliseconds on the underlying. - * @param readTimeout the read timeout in milliseconds - * @return a new builder instance. - * @throws java.lang.IllegalStateException if the underlying source doesn't support a - * read timeout. - */ - public WebServiceTemplateBuilder setReadTimeout(int readTimeout) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - append(this.webServiceMessageSenderCustomizers, - new ReadTimeoutWebServiceMessageSenderCustomizer(readTimeout)), - this.marshaller, this.unmarshaller, this.destinationProvider, - this.transformerFactoryClass, this.messageFactory, - this.detectWebServiceMessageSender); - } - - /** - * Set {@link WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) - * faultMessageResolver} on the underlying. - * @param faultMessageResolver faultMessageResolver may be set to null to disable - * fault handling. - * @return a new builder instance. - **/ public WebServiceTemplateBuilder setFaultMessageResolver( FaultMessageResolver faultMessageResolver) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new FaultMessageResolverCustomizer(faultMessageResolver)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setTransformerFactoryClass(Class) - * setTransformerFactoryClass} on the underlying. - * @param transformerFactoryClass boolean value + * Set the {@link TransformerFactory} implementation to use. + * @param transformerFactoryClass the transformer factory implementation to use * @return a new builder instance. - **/ - + * @see WebServiceTemplate#setTransformerFactoryClass(Class) + */ public WebServiceTemplateBuilder setTransformerFactoryClass( Class transformerFactoryClass) { - Assert.notNull(transformerFactoryClass, - "transformerFactoryClass must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, transformerFactoryClass, this.messageFactory); } /** * Set the default URI to be used on operations that do not have a URI parameter. - * - * Note!Typically, either this property is set, or + *

+ * Typically, either this property is set, or * {@link #setDestinationProvider(DestinationProvider)}, but not both. * @param defaultUri the destination provider URI to be used on operations that do not * have a URI parameter. * @return a new builder instance. + * @see #setDestinationProvider(DestinationProvider) */ public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { - Assert.hasText(defaultUri, "defaultUri must not be empty"); + Assert.hasText(defaultUri, "DefaultUri must not be empty"); return setDestinationProvider(() -> URI.create(defaultUri)); } /** - * Set {@link WebServiceTemplate#setDestinationProvider(DestinationProvider) - * destinationProvider} on the underlying. - * - * Note!Typically, either this property is set, or - * {@link #setDefaultUri(String)}, but not both. - * @param destinationProvider the destination provider URI to be used on operations - * that do not have a URI parameter. + * Set the {@link DestinationProvider} to use + *

+ * Typically, either this property is set, or {@link #setDefaultUri(String)}, but not + * both. + * @param destinationProvider the destination provider to be used on operations that + * do not have a URI parameter. * @return a new builder instance. + * @see WebServiceTemplate#setDestinationProvider(DestinationProvider) */ public WebServiceTemplateBuilder setDestinationProvider( DestinationProvider destinationProvider) { Assert.notNull(destinationProvider, "destinationProvider must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Set if the {@link WebServiceMessageSender} should be detected based on the - * classpath. Default is {@code true}. - * @param detectWebServiceMessageSender if the {@link WebServiceMessageSender} should - * be detected - * @return a new builder instance - */ - public WebServiceTemplateBuilder detectWebServiceMessageSender( - boolean detectWebServiceMessageSender) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + destinationProvider, this.transformerFactoryClass, this.messageFactory); } /** @@ -614,10 +477,9 @@ public WebServiceTemplate build() { * @see WebServiceTemplateBuilder#build() * @see #configure(WebServiceTemplate) */ - public T build(Class webServiceTemplateClass) { Assert.notNull(webServiceTemplateClass, - "webServiceTemplateClass must not be null"); + "WebServiceTemplateClass must not be null"); return configure(BeanUtils.instantiateClass(webServiceTemplateClass)); } @@ -631,97 +493,53 @@ public T build(Class webServiceTemplateClass) */ public T configure(T webServiceTemplate) { Assert.notNull(webServiceTemplate, "webServiceTemplate must not be null"); - - configureSenders(webServiceTemplate); - + configureMessageSenders(webServiceTemplate); if (!CollectionUtils.isEmpty(this.internalCustomizers)) { for (WebServiceTemplateCustomizer internalCustomizer : this.internalCustomizers) { internalCustomizer.customize(webServiceTemplate); } } - if (this.marshaller != null) { webServiceTemplate.setMarshaller(this.marshaller); } - if (this.unmarshaller != null) { webServiceTemplate.setUnmarshaller(this.unmarshaller); } - if (this.destinationProvider != null) { webServiceTemplate.setDestinationProvider(this.destinationProvider); } - if (this.transformerFactoryClass != null) { webServiceTemplate.setTransformerFactoryClass(this.transformerFactoryClass); } - if (this.messageFactory != null) { webServiceTemplate.setMessageFactory(this.messageFactory); } - - if (!CollectionUtils.isEmpty(this.customizers)) { - for (WebServiceTemplateCustomizer customizer : this.customizers) { - customizer.customize(webServiceTemplate); - } - } - if (!CollectionUtils.isEmpty(this.interceptors)) { webServiceTemplate.setInterceptors( append(this.interceptors, webServiceTemplate.getInterceptors()) .toArray(new ClientInterceptor[0])); } - + if (!CollectionUtils.isEmpty(this.customizers)) { + for (WebServiceTemplateCustomizer customizer : this.customizers) { + customizer.customize(webServiceTemplate); + } + } return webServiceTemplate; } - private void configureSenders(T webServiceTemplate) { - - if (!CollectionUtils.isEmpty(this.webServiceMessageSenderSuppliers)) { - Set webServiceMessageSenders = new LinkedHashSet<>(); - for (Supplier webServiceMessageSenderSupplier : this.webServiceMessageSenderSuppliers) { - webServiceMessageSenders.add(webServiceMessageSenderSupplier.get()); - } + private void configureMessageSenders( + T webServiceTemplate) { + if (this.messageSenders.isOnlyAdditional() && this.detectHttpMessageSender) { + Set mergedMessageSenders = append( + this.messageSenders.getMessageSenders(), + new HttpWebServiceMessageSenderBuilder().build()); webServiceTemplate.setMessageSenders( - webServiceMessageSenders.toArray(new WebServiceMessageSender[0])); + mergedMessageSenders.toArray(new WebServiceMessageSender[0])); } - else if (this.detectWebServiceMessageSender) { - webServiceTemplate.setMessageSenders( - new WebServiceMessageSender[] { detectMessageSender() }); - } - - if (!CollectionUtils.isEmpty(this.webServiceMessageSenderCustomizers)) { - if (!ObjectUtils.isEmpty(webServiceTemplate.getMessageSenders())) { - for (WebServiceMessageSender webServiceMessageSender : webServiceTemplate - .getMessageSenders()) { - for (WebServiceMessageSenderCustomizer webServiceMessageSenderCustomizer : this.webServiceMessageSenderCustomizers) { - webServiceMessageSenderCustomizer - .customize(webServiceMessageSender); - } - } - } - } - } - - private WebServiceMessageSender detectMessageSender() { - ClassLoader classLoader = getClass().getClassLoader(); - for (Map.Entry> candidate : MESSAGE_SENDER_FACTORY_CLASSES - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - WebServiceMessageSenderFactory webServiceMessageSenderFactory = BeanUtils - .instantiateClass(candidate.getValue()); - Optional webServiceMessageSender = webServiceMessageSenderFactory - .create(); - if (webServiceMessageSender.isPresent()) { - return webServiceMessageSender.get(); - } - } + else if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) { + webServiceTemplate.setMessageSenders(this.messageSenders.getMessageSenders() + .toArray(new WebServiceMessageSender[0])); } - return new HttpUrlConnectionMessageSender(); - } - - private static Supplier supplier(T value, Function mapper) { - return () -> mapper.apply(value); } private static Set append(Set set, T[] additions) { @@ -741,55 +559,44 @@ private static Set append(Set set, Collection additions) return Collections.unmodifiableSet(result); } - private interface WebServiceMessageSenderFactory { - - Optional create(); - - } - - private interface WebServiceMessageSenderCustomizer { - - void customize(WebServiceMessageSender webServiceMessageSender); + /** + * Collect user-defined {@link WebServiceMessageSender} and whether only additional + * message senders were added or not. + */ + private static class WebServiceMessageSenders { - } + private final boolean onlyAdditional; - private static final class ClientHttpRequestMessageSenderFactory - implements WebServiceMessageSenderFactory { + private Set messageSenders; - private static final Map REQUEST_FACTORY_CANDIDATES; + WebServiceMessageSenders() { + this(true, Collections.emptySet()); + } - static { - Map candidates = new LinkedHashMap<>(); - candidates.put("okhttp3.OkHttpClient", - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); - REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + private WebServiceMessageSenders(boolean onlyAdditional, + Set messageSenders) { + this.onlyAdditional = onlyAdditional; + this.messageSenders = messageSenders; } - @Override - public Optional create() { - ClassLoader classLoader = getClass().getClassLoader(); - for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class factoryClass = ClassUtils - .resolveClassName(candidate.getValue(), classLoader); - ClientHttpRequestFactory clientHttpRequestFactory = (ClientHttpRequestFactory) BeanUtils - .instantiateClass(factoryClass); - return Optional.of( - new ClientHttpRequestMessageSender(clientHttpRequestFactory)); - } - } - return Optional.empty(); + public boolean isOnlyAdditional() { + return this.onlyAdditional; } - } + public Set getMessageSenders() { + return this.messageSenders; + } - private static final class HttpComponentsMessageSenderFactory - implements WebServiceMessageSenderFactory { + public WebServiceMessageSenders set( + Collection messageSenders) { + return new WebServiceMessageSenders(false, + new LinkedHashSet<>(messageSenders)); + } - @Override - public Optional create() { - return Optional.of(new HttpComponentsMessageSender()); + public WebServiceMessageSenders add( + Collection messageSenders) { + return new WebServiceMessageSenders(this.onlyAdditional, + append(this.messageSenders, messageSenders)); } } @@ -855,252 +662,4 @@ public void customize(WebServiceTemplate webServiceTemplate) { } - /** - * {@link WebServiceMessageSenderCustomizer} to set connection timeout. - */ - private static final class ConnectionTimeoutWebServiceMessageSenderCustomizer - extends TimeoutWebServiceMessageSenderCustomizer { - - private ConnectionTimeoutWebServiceMessageSenderCustomizer(int connectTimeout) { - super(connectTimeout, Timeout.CONNECTION); - } - - } - - /** - * {@link WebServiceMessageSenderCustomizer} to set read timeout. - */ - private static final class ReadTimeoutWebServiceMessageSenderCustomizer - extends TimeoutWebServiceMessageSenderCustomizer { - - private ReadTimeoutWebServiceMessageSenderCustomizer(int readTimeout) { - super(readTimeout, Timeout.READ); - } - - } - - private abstract static class TimeoutWebServiceMessageSenderCustomizer - implements WebServiceMessageSenderCustomizer { - - private static final Map>> CUSTOMIZERS; - - static { - Map>> candidates = new LinkedHashMap<>(); - candidates.put( - "org.springframework.ws.transport.http.HttpComponentsMessageSender", - HttpComponentsTimeoutCustomizer.class); - candidates.put( - "org.springframework.ws.transport.http.ClientHttpRequestMessageSender", - ClientHttpRequestTimeoutCustomizer.class); - candidates.put( - "org.springframework.ws.transport.http.HttpUrlConnectionMessageSender", - HttpUrlConnectionTimeoutCustomizer.class); - CUSTOMIZERS = Collections.unmodifiableMap(candidates); - } - - private final Timeout type; - - private final int timeout; - - TimeoutWebServiceMessageSenderCustomizer(int timeout, Timeout type) { - this.timeout = timeout; - this.type = type; - } - - @Override - public final void customize(WebServiceMessageSender webServiceMessageSender) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, webServiceMessageSender, this.type, this.timeout, - classLoader); - - } - - @SuppressWarnings("unchecked") - private static void customize( - Map>> customizers, - T target, Timeout type, int timeout, ClassLoader classLoader) { - for (Map.Entry>> candidate : customizers - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class candidateClass = ClassUtils - .resolveClassName(candidate.getKey(), classLoader); - if (ClassUtils.isAssignable(candidateClass, target.getClass())) { - TimeoutCustomizer timeoutCustomizer = BeanUtils - .instantiateClass(candidate.getValue()); - customize(timeoutCustomizer, target, type, timeout); - return; - } - } - } - throw new IllegalStateException("There is no way to customize '" - + target.getClass() + "' " + "with '" + type.name().toLowerCase() - + "Timeout'. Please use a custom " + "customizer."); - - } - - private static void customize(TimeoutCustomizer customizer, T target, - Timeout type, int timeout) { - if (type == Timeout.CONNECTION) { - customizer.setConnectionTimeout(target, timeout); - } - else if (type == Timeout.READ) { - customizer.setReadTimeout(target, timeout); - } - } - - interface TimeoutCustomizer { - - void setReadTimeout(T source, int timeout); - - void setConnectionTimeout(T source, int timeout); - - } - - enum Timeout { - - READ, CONNECTION - - } - - private static final class HttpComponentsTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpComponentsMessageSender source, int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(HttpComponentsMessageSender source, - int timeout) { - source.setConnectionTimeout(timeout); - } - - } - - private static final class HttpUrlConnectionTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpUrlConnectionMessageSender source, - int timeout) { - source.setReadTimeout(Duration.ofMillis(timeout)); - } - - @Override - public void setConnectionTimeout(HttpUrlConnectionMessageSender source, - int timeout) { - source.setConnectionTimeout(Duration.ofMillis(timeout)); - } - - } - - private static final class ClientHttpRequestTimeoutCustomizer - implements TimeoutCustomizer { - - private static final Map>> CUSTOMIZERS; - - static { - Map>> candidates = new LinkedHashMap<>(); - candidates.put( - "org.springframework.http.client.HttpComponentsClientHttpRequestFactory", - HttpComponentsClientHttpRequestFactoryTimeoutCustomizer.class); - candidates.put( - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory", - OkHttp3ClientHttpRequestFactoryTimeoutCustomizer.class); - candidates.put( - "org.springframework.http.client.SimpleClientHttpRequestFactory", - SimpleClientHttpRequestFactoryTimeoutCustomizer.class); - CUSTOMIZERS = Collections.unmodifiableMap(candidates); - } - - @Override - public void setReadTimeout(ClientHttpRequestMessageSender source, - int timeout) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, getRequestFactory(source), Timeout.READ, timeout, - classLoader); - } - - @Override - public void setConnectionTimeout(ClientHttpRequestMessageSender source, - int timeout) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, getRequestFactory(source), Timeout.CONNECTION, - timeout, classLoader); - } - - private ClientHttpRequestFactory getRequestFactory( - ClientHttpRequestMessageSender source) { - ClientHttpRequestFactory requestFactory = source.getRequestFactory(); - if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { - return requestFactory; - } - Field field = ReflectionUtils.findField( - AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); - Assert.notNull(field, "Field must not be null"); - ReflectionUtils.makeAccessible(field); - do { - requestFactory = (ClientHttpRequestFactory) ReflectionUtils - .getField(field, requestFactory); - } - while (requestFactory instanceof AbstractClientHttpRequestFactoryWrapper); - return requestFactory; - } - - private static final class SimpleClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(SimpleClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(SimpleClientHttpRequestFactory source, - int timeout) { - source.setConnectTimeout(timeout); - } - - } - - private static final class HttpComponentsClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpComponentsClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout( - HttpComponentsClientHttpRequestFactory source, int timeout) { - source.setConnectTimeout(timeout); - } - - } - - private static final class OkHttp3ClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(OkHttp3ClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(OkHttp3ClientHttpRequestFactory source, - int timeout) { - source.setConnectTimeout(timeout); - } - - } - - } - - } - } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java index f619e6f9996b..36a6404ea66b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java @@ -22,6 +22,7 @@ * Callback interface that can be used to customize a {@link WebServiceTemplate}. * * @author Dmytro Nosan + * @since 2.1.0 */ public interface WebServiceTemplateCustomizer { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java index 5e0d4ce13fe2..220d07076f56 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java @@ -17,5 +17,4 @@ /** * Web Services client utilities. */ - package org.springframework.boot.webservices.client; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java similarity index 55% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java rename to spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java index 3d37a488f116..3edea2ae6dd2 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java @@ -22,61 +22,52 @@ import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will - * create ClientHttpRequestMessageSender (OkHttp3ClientHttpRequestFactory) if apache - * client is not present in the classpath + * Tests for {@link HttpWebServiceMessageSenderBuilder} when Http Components is not + * available. * - * @author Dmytro Nosan + * @author Stephane Nicoll */ @RunWith(ModifiedClassPathRunner.class) @ClassPathExclusions("httpclient-*.jar") -public class WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests { +public class HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests { - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + private final HttpWebServiceMessageSenderBuilder builder = new HttpWebServiceMessageSenderBuilder(); @Test - public void build() { - - WebServiceTemplate webServiceTemplate = this.builder.build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(ClientHttpRequestMessageSender.class); - - ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) webServiceTemplate - .getMessageSenders()[0]; - - assertThat(sender.getRequestFactory()) - .isInstanceOf(OkHttp3ClientHttpRequestFactory.class); - + public void buildUseOkHttp3ByDefault() { + WebServiceMessageSender messageSender = this.builder.build(); + assertOkHttp3RequestFactory(messageSender); } @Test - public void setTimeout() { - OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - + public void buildWithCustomTimeouts() { + WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + .setReadTimeout(2000).build(); + OkHttp3ClientHttpRequestFactory factory = assertOkHttp3RequestFactory( + messageSender); OkHttpClient client = (OkHttpClient) ReflectionTestUtils.getField(factory, "client"); - assertThat(client).isNotNull(); - assertThat(client.connectTimeoutMillis()).isEqualTo(5000); assertThat(client.readTimeoutMillis()).isEqualTo(2000); + } + private OkHttp3ClientHttpRequestFactory assertOkHttp3RequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory).isInstanceOf(OkHttp3ClientHttpRequestFactory.class); + return (OkHttp3ClientHttpRequestFactory) requestFactory; } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java new file mode 100644 index 000000000000..361927ff29af --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HttpWebServiceMessageSenderBuilder} when no preferred HTTP clients are + * available + * + * @author Stephane Nicoll + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions({ "httpclient-*.jar", "okhttp*.jar" }) +public class HttpWebServiceMessageSenderBuilderSimpleIntegrationTests { + + private final HttpWebServiceMessageSenderBuilder builder = new HttpWebServiceMessageSenderBuilder(); + + @Test + public void buildUseUseSimpleClientByDefault() { + WebServiceMessageSender messageSender = this.builder.build(); + assertSimpleClientRequestFactory(messageSender); + } + + @Test + public void buildWithCustomTimeouts() { + WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + .setReadTimeout(2000).build(); + SimpleClientHttpRequestFactory requestFactory = assertSimpleClientRequestFactory( + messageSender); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(2000); + } + + private SimpleClientHttpRequestFactory assertSimpleClientRequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory).isInstanceOf(SimpleClientHttpRequestFactory.class); + return (SimpleClientHttpRequestFactory) requestFactory; + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java new file mode 100644 index 000000000000..e844882a1f2f --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2018 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.webservices.client; + +import org.apache.http.client.config.RequestConfig; +import org.junit.Test; + +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link HttpWebServiceMessageSenderBuilder}. + * + * @author Stephane Nicoll + */ +public class HttpWebServiceMessageSenderBuilderTests { + + @Test + public void buildWithRequestFactorySupplier() { + ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class); + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder() + .requestFactory(() -> requestFactory)); + assertThat(messageSender.getRequestFactory()).isSameAs(requestFactory); + } + + @Test + public void buildWithReadAndConnectTimeout() { + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder() + .requestFactory(SimpleClientHttpRequestFactory::new) + .setConnectionTimeout(5000).setReadTimeout(2000)); + SimpleClientHttpRequestFactory requestFactory = (SimpleClientHttpRequestFactory) messageSender + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(2000); + } + + @Test + public void buildUsesHttpComponentsBydefault() { + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder().setConnectionTimeout(5000) + .setReadTimeout(2000)); + ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory(); + assertThat(requestFactory) + .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); + RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils + .getField(requestFactory, "requestConfig"); + assertThat(requestConfig).isNotNull(); + assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); + assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); + } + + private ClientHttpRequestMessageSender build( + HttpWebServiceMessageSenderBuilder builder) { + WebServiceMessageSender messageSender = builder.build(); + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + return ((ClientHttpRequestMessageSender) messageSender); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java deleted file mode 100644 index 8ae3040b9513..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2012-2018 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.webservices.client; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.ws.transport.WebServiceMessageSender; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -/** - * Tests for - * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderCustomsMessageSenderTests { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void unknownSenderReadTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setReadTimeout(3000).setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - - @Test - public void unknownSenderConnectionTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage( - "with 'connectionTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setConnectionTimeout(3000).setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - - @Test - public void unknownRequestFactoryReadTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setReadTimeout(3000) - .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( - Mockito.mock(ClientHttpRequestFactory.class))) - .build(); - } - - @Test - public void unknownRequestFactoryConnectionTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage( - "with 'connectionTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setConnectionTimeout(3000) - .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( - Mockito.mock(ClientHttpRequestFactory.class))) - .build(); - } - - @Test - public void shouldBuildWithoutTimeouts() { - this.builder.setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java deleted file mode 100644 index f2cafa15c7c7..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012-2018 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.webservices.client; - -import org.apache.http.client.config.RequestConfig; -import org.junit.Test; - -import org.springframework.http.client.BufferingClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void setTimeout() { - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils - .getField(factory, "requestConfig"); - assertThat(requestConfig).isNotNull(); - assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); - assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java deleted file mode 100644 index 82f08a27de33..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2012-2018 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.webservices.client; - -import org.apache.http.client.HttpClient; -import org.apache.http.params.HttpConnectionParams; -import org.junit.Test; - -import org.springframework.ws.client.core.WebServiceTemplate; -import org.springframework.ws.transport.http.HttpComponentsMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for - * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. This - * test class check that builder will create HttpComponents by default if apache client is - * present in the classpath. - * - * @author Dmytro Nosan - */ -@SuppressWarnings("deprecation") -public class WebServiceTemplateBuilderHttpComponentsMessageSenderTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void build() { - WebServiceTemplate webServiceTemplate = new WebServiceTemplateBuilder().build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(HttpComponentsMessageSender.class); - - } - - @Test - public void setTimeout() { - HttpComponentsMessageSender sender = new HttpComponentsMessageSender(); - HttpClient httpClient = sender.getHttpClient(); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(HttpConnectionParams.getConnectionTimeout(httpClient.getParams())) - .isEqualTo(5000); - assertThat(HttpConnectionParams.getSoTimeout(httpClient.getParams())) - .isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java deleted file mode 100644 index 3468091f6ee5..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012-2018 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.webservices.client; - -import java.time.Duration; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; -import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.client.core.WebServiceTemplate; -import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will - * create HttpUrlConnectionMessageSender If Ok-http and Apache client are not present in - * the classpath. - * - * @author Dmytro Nosan - */ -@RunWith(ModifiedClassPathRunner.class) -@ClassPathExclusions({ "httpclient-*.jar", "okhttp-*.jar" }) -public class WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void build() { - WebServiceTemplate webServiceTemplate = this.builder.build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(HttpUrlConnectionMessageSender.class); - - } - - @Test - public void setTimeout() { - HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender(); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(ReflectionTestUtils.getField(sender, "connectionTimeout")) - .isEqualTo(Duration.ofMillis(5000)); - assertThat(ReflectionTestUtils.getField(sender, "readTimeout")) - .isEqualTo(Duration.ofMillis(2000)); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java deleted file mode 100644 index e2f3c0a5c369..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012-2018 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.webservices.client; - -import org.junit.Test; - -import org.springframework.http.client.BufferingClientHttpRequestFactory; -import org.springframework.http.client.SimpleClientHttpRequestFactory; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void setTimeout() { - SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(ReflectionTestUtils.getField(factory, "connectTimeout")) - .isEqualTo(5000); - assertThat(ReflectionTestUtils.getField(factory, "readTimeout")).isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java index ffdffd404016..82480b57b511 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java @@ -19,502 +19,362 @@ import java.net.URI; import java.util.Collection; import java.util.Collections; -import java.util.function.Supplier; +import java.util.Set; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; -import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.destination.DestinationProvider; import org.springframework.ws.client.support.interceptor.ClientInterceptor; -import org.springframework.ws.soap.client.core.SoapFaultMessageResolver; -import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Tests for {@link WebServiceTemplateBuilder}. * + * @author Stephane Nicoll * @author Dmytro Nosan */ public class WebServiceTemplateBuilderTests { - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + private final WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - @Test - public void addInterceptors() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + @Rule + public ExpectedException thrown = ExpectedException.none(); - WebServiceTemplate webServiceTemplate = this.builder.addInterceptors(f1) - .addInterceptors(f2).build(); + @Mock + private WebServiceMessageSender messageSender; - assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, - f2); - } - - @Test - public void addInterceptorsCollection() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = this.builder - .addInterceptors(Collections.singletonList(f1)) - .addInterceptors(Collections.singleton(f2)).build(); - - assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, - f2); + @Mock + private ClientInterceptor interceptor; + @Before + public void setup() { + MockitoAnnotations.initMocks(this); } @Test - public void setInterceptors() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = this.builder.setInterceptors(f1) - .setInterceptors(f2).build(); - - assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); - } - - @Test - public void setInterceptorsCollection() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = this.builder - .setInterceptors(Collections.singletonList(f1)) - .setInterceptors(Collections.singleton(f2)).build(); - - assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); - + public void createWithCustomizersShouldApplyCustomizers() { + WebServiceTemplateCustomizer customizer = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = new WebServiceTemplateBuilder(customizer).build(); + verify(customizer).customize(template); } @Test - public void addCustomizers() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder.addCustomizers(customizer) - .addCustomizers(customizer1).build(); - - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - + public void buildShouldDetectHttpMessageSender() { + WebServiceTemplate webServiceTemplate = this.builder.build(); + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + WebServiceMessageSender messageSender = webServiceTemplate.getMessageSenders()[0]; + assertHttpComponentsRequestFactory(messageSender); } @Test - public void addCustomizersCollection() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - + public void detectHttpMessageSenderWhenFalseShouldDisableDetection() { WebServiceTemplate webServiceTemplate = this.builder - .addCustomizers(Collections.singleton(customizer)) - .addCustomizers(Collections.singletonList(customizer1)).build(); - - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + .detectHttpMessageSender(false).build(); + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); } @Test - public void setCustomizers() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder.setCustomizers(customizer) - .setCustomizers(customizer1).build(); - - assertThat(webServiceTemplate.getMarshaller()).isNull(); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - + public void messageSendersWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.messageSenders((WebServiceMessageSender[]) null); } @Test - public void setCustomizersCollection() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder - .setCustomizers(Collections.singleton(customizer)) - .setCustomizers(Collections.singletonList(customizer1)).build(); - - assertThat(webServiceTemplate.getMarshaller()).isNull(); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + public void messageSendersCollectionWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.messageSenders((Collection) null); } @Test - public void addWebServiceMessageSenders() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSenders(Collections.singleton(() -> sender)) - .addWebServiceMessageSenders(Collections.singletonList(() -> sender1)) + public void messageSendersShouldApply() { + WebServiceTemplate template = this.builder.messageSenders(this.messageSender) .build(); - - assertThat(webServiceTemplate.getMessageSenders()) - .containsExactlyInAnyOrder(sender, sender1); + assertThat(template.getMessageSenders()).containsOnly(this.messageSender); } @Test - public void setWebServiceMessageSenders() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSenders(Collections.singleton(() -> sender)) - .setWebServiceMessageSenders(Collections.singletonList(() -> sender1)) - .build(); - - assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) - .contains(sender1); - + public void messageSendersShouldReplaceExisting() { + WebServiceTemplate template = this.builder + .messageSenders(new ClientHttpRequestMessageSender()) + .messageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).containsOnly(this.messageSender); } @Test - public void addWebServiceMessageSenderClass() { - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSender(ClientHttpRequestMessageSender.class) - .addWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(2); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(ClientHttpRequestMessageSender.class); - assertThat(webServiceTemplate.getMessageSenders()[1]) - .isInstanceOf(HttpUrlConnectionMessageSender.class); + public void additionalMessageSendersWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.additionalMessageSenders((WebServiceMessageSender[]) null); } @Test - public void setWebServiceMessageSenderClass() { - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSender(ClientHttpRequestMessageSender.class) - .setWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(HttpUrlConnectionMessageSender.class); - + public void additionalMessageSendersCollectionWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.additionalMessageSenders( + (Collection) null); } @Test - public void addWebServiceMessageSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSender(() -> sender) - .addWebServiceMessageSender(() -> sender1).build(); - - assertThat(webServiceTemplate.getMessageSenders()) - .containsExactlyInAnyOrder(sender, sender1); + public void additionalMessageSendersShouldAddToExisting() { + ClientHttpRequestMessageSender httpMessageSender = new ClientHttpRequestMessageSender(); + WebServiceTemplate template = this.builder.messageSenders(httpMessageSender) + .additionalMessageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).containsOnly(httpMessageSender, + this.messageSender); } @Test - public void setWebServiceMessageSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSender(() -> sender) - .setWebServiceMessageSender(() -> sender1).build(); - - assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) - .contains(sender1); - + public void additionalMessageSendersShouldKeepDetectedHttpMessageSender() { + WebServiceTemplate template = this.builder + .additionalMessageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).contains(this.messageSender); + assertThat(template.getMessageSenders()).hasSize(2); } @Test - public void setCheckConnectionForFault() { - MockWebServiceTemplate webServiceTemplate = this.builder - .setCheckConnectionForFault(false).build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.isCheckConnectionForFault()).isFalse(); + public void interceptorsWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.interceptors((ClientInterceptor[]) null); } @Test - public void setCheckConnectionForError() { - - MockWebServiceTemplate webServiceTemplate = this.builder - .setCheckConnectionForError(false).build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.isCheckConnectionForError()).isFalse(); - + public void interceptorsCollectionWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.interceptors((Collection) null); } @Test - public void setTransformerFactoryClass() { - MockWebServiceTemplate webServiceTemplate = this.builder - .setTransformerFactoryClass(SAXTransformerFactory.class) - .build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.getTransformerFactoryClass()) - .isEqualTo(SAXTransformerFactory.class); - + public void interceptorsShouldApply() { + WebServiceTemplate template = this.builder.interceptors(this.interceptor).build(); + assertThat(template.getInterceptors()).containsOnly(this.interceptor); } @Test - public void setWebServiceMessageFactory() { - - SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(); - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageFactory(messageFactory).build(); - - assertThat(webServiceTemplate.getMessageFactory()).isEqualTo(messageFactory); - + public void interceptorsShouldReplaceExisting() { + WebServiceTemplate template = this.builder + .interceptors(mock(ClientInterceptor.class)) + .interceptors(Collections.singleton(this.interceptor)).build(); + assertThat(template.getInterceptors()).containsOnly(this.interceptor); } @Test - public void setMarshaller() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - - WebServiceTemplate webServiceTemplate = this.builder - .setMarshaller(jaxb2Marshaller).build(); - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + public void additionalInterceptorsWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.additionalInterceptors((ClientInterceptor[]) null); } @Test - public void setUnmarshaller() { - Jaxb2Marshaller jaxb2Unmarshaller = new Jaxb2Marshaller(); - - WebServiceTemplate webServiceTemplate = this.builder - .setUnmarshaller(jaxb2Unmarshaller).build(); - - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Unmarshaller); + public void additionalInterceptorsCollectionWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.additionalInterceptors((Set) null); } @Test - public void setFaultMessageResolver() { - - FaultMessageResolver faultMessageResolver = new SoapFaultMessageResolver(); - WebServiceTemplate webServiceTemplate = this.builder - .setFaultMessageResolver(faultMessageResolver).build(); - - assertThat(webServiceTemplate.getFaultMessageResolver()) - .isEqualTo(faultMessageResolver); + public void additionalInterceptorsShouldAddToExisting() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + WebServiceTemplate template = this.builder.interceptors(interceptor) + .additionalInterceptors(this.interceptor).build(); + assertThat(template.getInterceptors()).containsOnly(interceptor, + this.interceptor); } @Test - public void setDefaultUri() { - URI uri = URI.create("http://localhost:8080"); - - WebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()) - .build(); - - assertThat(webServiceTemplate.getDestinationProvider().getDestination()) - .isEqualTo(uri); - - } - - @Test - public void setDestinationProvider() { - URI uri = URI.create("http://localhost:8080"); - - WebServiceTemplate webServiceTemplate = this.builder - .setDestinationProvider(() -> uri).build(); - - assertThat(webServiceTemplate.getDestinationProvider().getDestination()) - .isEqualTo(uri); - - } - - @Test - public void shouldNotOverrideDefaultSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); - webServiceTemplate.setMessageSender(sender); - - this.builder.detectWebServiceMessageSender(false).configure(webServiceTemplate); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1).contains(sender); - - } - - @Test - public void addInterceptorsToExistingWebServiceTemplate() { + public void additionalInterceptorsShouldAddToExistingWebServiceTemplate() { ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); webServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 }); - - this.builder.addInterceptors(f2).configure(webServiceTemplate); - + this.builder.additionalInterceptors(f2).configure(webServiceTemplate); assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, f1); } - @Test(expected = IllegalArgumentException.class) - public void setInterceptorsArrayNull() { - this.builder.setInterceptors((ClientInterceptor[]) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setInterceptorsCollectionNull() { - this.builder.setInterceptors((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addInterceptorsArrayNull() { - this.builder.addInterceptors((ClientInterceptor[]) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addInterceptorsCollectionNull() { - this.builder.addInterceptors((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setCustomizersArrayNull() { - this.builder.setCustomizers((WebServiceTemplateCustomizer[]) null).build(); + @Test + public void customizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.customizers((WebServiceTemplateCustomizer[]) null); } - @Test(expected = IllegalArgumentException.class) - public void setCustomizersCollectionNull() { + @Test + public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); this.builder - .setCustomizers((Collection) null) - .build(); + .customizers((Collection) null); } - @Test(expected = IllegalArgumentException.class) - public void addCustomizersArrayNull() { - this.builder - .addCustomizers((Collection) null) - .build(); + @Test + public void customizersShouldApply() { + WebServiceTemplateCustomizer customizer = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer).build(); + verify(customizer).customize(template); } - @Test(expected = IllegalArgumentException.class) - public void addCustomizersCollectionNull() { + @Test + public void customizersShouldBeAppliedLast() { + WebServiceTemplate template = spy(new WebServiceTemplate()); this.builder - .addCustomizers((Collection) null) - .build(); + .additionalCustomizers(((webServiceTemplate) -> verify(webServiceTemplate) + .setMessageSenders(any()))); + this.builder.configure(template); } - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSendersNull() { - this.builder.setWebServiceMessageSenders(null).build(); + @Test + public void customizersShouldReplaceExisting() { + WebServiceTemplateCustomizer customizer1 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplateCustomizer customizer2 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer1) + .customizers(Collections.singleton(customizer2)).build(); + verifyZeroInteractions(customizer1); + verify(customizer2).customize(template); } - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSendersNull() { - this.builder.addWebServiceMessageSenders(null).build(); + @Test + public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.additionalCustomizers((WebServiceTemplateCustomizer[]) null); } - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSenderClassNull() { - this.builder.setWebServiceMessageSender( - (Class) null).build(); + @Test + public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.additionalCustomizers( + (Collection) null); } - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSenderClassNull() { - this.builder.addWebServiceMessageSender( - (Class) null).build(); + @Test + public void additionalCustomizersShouldAddToExisting() { + WebServiceTemplateCustomizer customizer1 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplateCustomizer customizer2 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer1) + .additionalCustomizers(customizer2).build(); + verify(customizer1).customize(template); + verify(customizer2).customize(template); } - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSenderSupplierNull() { - this.builder.setWebServiceMessageSender( - (Supplier) null).build(); + @Test + public void setCheckConnectionForFault() { + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setCheckConnectionForFault(false).configure(template); + verify(template).setCheckConnectionForFault(false); } - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSenderSupplierNull() { - this.builder.addWebServiceMessageSender( - (Supplier) null).build(); - } + @Test + public void setCheckConnectionForError() { + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setCheckConnectionForError(false).configure(template); + verify(template).setCheckConnectionForError(false); - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageFactoryNull() { - this.builder.setWebServiceMessageFactory(null).build(); } - @Test(expected = IllegalArgumentException.class) - public void setUnmarshallerNull() { - this.builder.setUnmarshaller(null).build(); + @Test + public void setTransformerFactoryClass() { + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setTransformerFactoryClass(SAXTransformerFactory.class) + .configure(template); + verify(template).setTransformerFactoryClass(SAXTransformerFactory.class); } - @Test(expected = IllegalArgumentException.class) - public void setMarshallerNull() { - this.builder.setMarshaller(null).build(); + @Test + public void setWebServiceMessageFactory() { + WebServiceMessageFactory messageFactory = mock(WebServiceMessageFactory.class); + WebServiceTemplate template = this.builder + .setWebServiceMessageFactory(messageFactory).build(); + assertThat(template.getMessageFactory()).isEqualTo(messageFactory); } - @Test(expected = IllegalArgumentException.class) - public void setTransformerFactoryClassNull() { - this.builder.setTransformerFactoryClass(null).build(); + @Test + public void setMarshaller() { + Marshaller marshaller = mock(Marshaller.class); + WebServiceTemplate template = this.builder.setMarshaller(marshaller).build(); + assertThat(template.getMarshaller()).isEqualTo(marshaller); } - @Test(expected = IllegalArgumentException.class) - public void setDefaultUriNull() { - this.builder.setDefaultUri(null).build(); + @Test + public void setUnmarshaller() { + Unmarshaller unmarshaller = mock(Unmarshaller.class); + WebServiceTemplate webServiceTemplate = this.builder.setUnmarshaller(unmarshaller) + .build(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(unmarshaller); } - @Test(expected = IllegalArgumentException.class) - public void setDestinationProviderNull() { - this.builder.setDestinationProvider(null).build(); + @Test + public void setFaultMessageResolver() { + FaultMessageResolver faultMessageResolver = mock(FaultMessageResolver.class); + WebServiceTemplate webServiceTemplate = this.builder + .setFaultMessageResolver(faultMessageResolver).build(); + assertThat(webServiceTemplate.getFaultMessageResolver()) + .isEqualTo(faultMessageResolver); } - private static class MockWebServiceTemplate extends WebServiceTemplate { - - private boolean checkConnectionForError; - - private boolean checkConnectionForFault; - - private Class transformerFactoryClass; - - boolean isCheckConnectionForError() { - return this.checkConnectionForError; - } - - @Override - public void setCheckConnectionForError(boolean checkConnectionForError) { - this.checkConnectionForError = checkConnectionForError; - } - - boolean isCheckConnectionForFault() { - return this.checkConnectionForFault; - } - - @Override - public void setCheckConnectionForFault(boolean checkConnectionForFault) { - this.checkConnectionForFault = checkConnectionForFault; - } - - Class getTransformerFactoryClass() { - return this.transformerFactoryClass; - } - - @Override - public void setTransformerFactoryClass( - Class transformerFactoryClass) { - this.transformerFactoryClass = transformerFactoryClass; - } + @Test + public void setDefaultUri() { + URI uri = URI.create("http://localhost:8080"); + WebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()) + .build(); + assertThat(webServiceTemplate.getDestinationProvider().getDestination()) + .isEqualTo(uri); + } + @Test + public void setDestinationProvider() { + DestinationProvider destinationProvider = () -> URI + .create("http://localhost:8080"); + WebServiceTemplate webServiceTemplate = this.builder + .setDestinationProvider(destinationProvider).build(); + assertThat(webServiceTemplate.getDestinationProvider()) + .isEqualTo(destinationProvider); + } + + private void assertHttpComponentsRequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory) + .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); } } From 93396aef51ac32cdeb1545f2b7ede923fd9f0efb Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 4 Jun 2018 17:50:29 +0200 Subject: [PATCH 095/701] Polish --- .../src/main/asciidoc/spring-boot-features.adoc | 2 +- .../boot/web/client/RestTemplateBuilder.java | 6 +++--- .../HttpWebServiceMessageSenderBuilder.java | 15 +++++++-------- ...ssageSenderBuilderOkHttp3IntegrationTests.java | 2 +- ...essageSenderBuilderSimpleIntegrationTests.java | 2 +- .../HttpWebServiceMessageSenderBuilderTests.java | 6 +++--- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index bbf55d26a092..07b1af91f4a8 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -7428,7 +7428,7 @@ can also customize read and connection timeouts as follows: @Bean public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { return builder.messageSenders(new HttpWebServiceMessageSenderBuilder() - .setReadTimeout(5000).setConnectionTimeout(2000).build()).build(); + .setConnectTimeout(5000).setReadTimeout(2000).build()).build(); } ---- diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 5038a5ecd0e1..88cf18909ce1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -451,9 +451,9 @@ public RestTemplateBuilder additionalCustomizers( } /** - * Sets the connect timeout in milliseconds on the underlying + * Sets the connection timeout in milliseconds on the underlying * {@link ClientHttpRequestFactory}. - * @param connectTimeout the connect timeout in milliseconds + * @param connectTimeout the connection timeout in milliseconds * @return a new builder instance. */ public RestTemplateBuilder setConnectTimeout(int connectTimeout) { @@ -641,7 +641,7 @@ private static class ReadTimeoutRequestFactoryCustomizer } /** - * {@link RequestFactoryCustomizer} to set the connect timeout. + * {@link RequestFactoryCustomizer} to set the connection timeout. */ private static class ConnectTimeoutRequestFactoryCustomizer extends TimeoutRequestFactoryCustomizer { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java index e5c998b24680..1192a9a1f688 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java @@ -35,7 +35,7 @@ */ public class HttpWebServiceMessageSenderBuilder { - private Integer connectionTimeout; + private Integer connectTimeout; private Integer readTimeout; @@ -43,12 +43,11 @@ public class HttpWebServiceMessageSenderBuilder { /** * Set the connection timeout in milliseconds. - * @param connectionTimeout the connection timeout in milliseconds + * @param connectTimeout the connection timeout in milliseconds * @return a new builder instance */ - public HttpWebServiceMessageSenderBuilder setConnectionTimeout( - int connectionTimeout) { - this.connectionTimeout = connectionTimeout; + public HttpWebServiceMessageSenderBuilder setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; return this; } @@ -80,9 +79,9 @@ public WebServiceMessageSender build() { ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null ? this.requestFactorySupplier.get() : new ClientHttpRequestFactorySupplier().get()); - if (this.connectionTimeout != null) { - new TimeoutRequestFactoryCustomizer(this.connectionTimeout, - "setConnectTimeout").customize(requestFactory); + if (this.connectTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.connectTimeout, "setConnectTimeout") + .customize(requestFactory); } if (this.readTimeout != null) { new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java index 3edea2ae6dd2..cfce3e23484a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java @@ -50,7 +50,7 @@ public void buildUseOkHttp3ByDefault() { @Test public void buildWithCustomTimeouts() { - WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + WebServiceMessageSender messageSender = this.builder.setConnectTimeout(5000) .setReadTimeout(2000).build(); OkHttp3ClientHttpRequestFactory factory = assertOkHttp3RequestFactory( messageSender); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java index 361927ff29af..4f3b93bfaca6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java @@ -49,7 +49,7 @@ public void buildUseUseSimpleClientByDefault() { @Test public void buildWithCustomTimeouts() { - WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + WebServiceMessageSender messageSender = this.builder.setConnectTimeout(5000) .setReadTimeout(2000).build(); SimpleClientHttpRequestFactory requestFactory = assertSimpleClientRequestFactory( messageSender); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java index e844882a1f2f..82cf988dbd4b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java @@ -50,7 +50,7 @@ public void buildWithReadAndConnectTimeout() { ClientHttpRequestMessageSender messageSender = build( new HttpWebServiceMessageSenderBuilder() .requestFactory(SimpleClientHttpRequestFactory::new) - .setConnectionTimeout(5000).setReadTimeout(2000)); + .setConnectTimeout(5000).setReadTimeout(2000)); SimpleClientHttpRequestFactory requestFactory = (SimpleClientHttpRequestFactory) messageSender .getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) @@ -60,9 +60,9 @@ public void buildWithReadAndConnectTimeout() { } @Test - public void buildUsesHttpComponentsBydefault() { + public void buildUsesHttpComponentsByDefault() { ClientHttpRequestMessageSender messageSender = build( - new HttpWebServiceMessageSenderBuilder().setConnectionTimeout(5000) + new HttpWebServiceMessageSenderBuilder().setConnectTimeout(5000) .setReadTimeout(2000)); ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory(); assertThat(requestFactory) From 8be2fe79cb5ce97f8854276848cc8b3a2edec489 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Mon, 4 Jun 2018 23:56:05 +0900 Subject: [PATCH 096/701] Add "Managed dependency upgrade" section Closes gh-13351 --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3dd45a33bffa..c58da9ec1f6c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -18,4 +18,7 @@ STOP!! Please don't raise security vulnerabilities here. Head over to https://pi 🎁 Enhancement Please start by describing the problem that you are trying to solve. There may already be a solution, or there may be a way to solve it that you hadn't considered. + +🙅 Managed dependency upgrade +You DO NOT need to raise an issue for a managed dependency version upgrade as there's a semi-automatic process for checking managed dependencies for new versions before a release. But pull requests for upgrades that are more involved than just a version property change are still most welcome. --> From bd8106d77f6fe983b21ca548b495c68a8ca5711b Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 4 Jun 2018 18:59:17 +0200 Subject: [PATCH 097/701] Upgrade to Spring Framework 5.1 As of Spring Framework 5.1, we're depending on the Reactor Californium release train. Reactor Netty is now at version 0.8 and changed its artifact coordinates, package names and broke several APIs. Spring Framework is now up-to-date with those changes and this commit does the same for Spring Boot. Note that in that process, the `NettyServerCustomizer` has been changed since the former `HttpServerOptions.Builder` API is now gone from Reactor Netty, and we're now relying on immutable server instances instead of a stateful builder pattern. See gh-13321 --- .../pom.xml | 2 +- .../ReactiveCloudFoundrySecurityService.java | 9 ++-- ...FoundryActuatorAutoConfigurationTests.java | 2 +- .../spring-boot-actuator/pom.xml | 2 +- .../spring-boot-autoconfigure/pom.xml | 2 +- ...ReactiveWebServerFactoryConfiguration.java | 2 +- .../servlet/error/BasicErrorController.java | 2 - .../BasicErrorControllerIntegrationTests.java | 1 + .../spring-boot-dependencies/pom.xml | 9 +++- spring-boot-project/spring-boot-docs/pom.xml | 2 +- .../spring-boot-starter-reactor-netty/pom.xml | 2 +- spring-boot-project/spring-boot-test/pom.xml | 2 +- spring-boot-project/spring-boot/pom.xml | 2 +- .../embedded/netty/CompressionCustomizer.java | 14 ++--- .../netty/NettyReactiveWebServerFactory.java | 37 ++++++------- .../embedded/netty/NettyServerCustomizer.java | 18 +++---- .../web/embedded/netty/NettyWebServer.java | 52 +++++++++---------- .../embedded/netty/SslServerCustomizer.java | 43 ++++++++------- .../NettyReactiveWebServerFactoryTests.java | 24 +++------ ...AbstractReactiveWebServerFactoryTests.java | 42 ++++++++------- 20 files changed, 138 insertions(+), 131 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index f8c2c72029ab..256ace35bf1d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -148,7 +148,7 @@ true - io.projectreactor.ipc + io.projectreactor.netty reactor-netty true diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java index 4df82e86915c..269d1a27a187 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java @@ -23,6 +23,7 @@ import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import reactor.core.publisher.Mono; +import reactor.netty.http.client.HttpClient; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel; import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException; @@ -64,9 +65,11 @@ class ReactiveCloudFoundrySecurityService { } protected ReactorClientHttpConnector buildTrustAllSslConnector() { - return new ReactorClientHttpConnector((options) -> options.sslSupport( - (sslContextBuilder) -> sslContextBuilder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE))); + HttpClient client = HttpClient.create() + .secure((sslContextSpec) -> sslContextSpec.forClient() + .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE))); + return new ReactorClientHttpConnector(client); } /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index 5b1d82913b0b..33324e4656a2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -27,7 +27,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import reactor.ipc.netty.http.HttpResources; +import reactor.netty.http.HttpResources; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; diff --git a/spring-boot-project/spring-boot-actuator/pom.xml b/spring-boot-project/spring-boot-actuator/pom.xml index 329876df5172..055feabaf396 100644 --- a/spring-boot-project/spring-boot-actuator/pom.xml +++ b/spring-boot-project/spring-boot-actuator/pom.xml @@ -303,7 +303,7 @@ test - io.projectreactor.ipc + io.projectreactor.netty reactor-netty test diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index d86bef25c03d..7340eb977e73 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -107,7 +107,7 @@ true - io.projectreactor.ipc + io.projectreactor.netty reactor-netty true diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java index 52b0f6283cc5..fc2cf47591f0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryConfiguration.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.web.reactive; import io.undertow.Undertow; -import reactor.ipc.netty.http.server.HttpServer; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java index 7f282437a6e6..ef472ac31ee4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java @@ -33,7 +33,6 @@ import org.springframework.stereotype.Controller; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; /** @@ -95,7 +94,6 @@ public ModelAndView errorHtml(HttpServletRequest request, } @RequestMapping - @ResponseBody public ResponseEntity> error(HttpServletRequest request) { Map body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java index 6b32f333c839..9c25c10b6a1e 100755 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java @@ -169,6 +169,7 @@ public void testRequestBodyValidationForMachineClient() { load("--server.error.include-exception=true"); RequestEntity request = RequestEntity .post(URI.create(createUrl("/bodyValidation"))) + .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).body("{}"); ResponseEntity entity = new TestRestTemplate().exchange(request, Map.class); String resp = entity.getBody().toString(); diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 05ceeb222c65..16541aab2707 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -151,7 +151,7 @@ 1.7.25 1.19 7.2.1 - 5.0.7.BUILD-SNAPSHOT + 5.1.0.BUILD-SNAPSHOT 2.0.3.RELEASE 4.0.1.RELEASE 2.0.2.RELEASE @@ -931,6 +931,13 @@ import pom + + + io.projectreactor.netty + reactor-netty + 0.8.0.BUILD-SNAPSHOT + compile + io.reactivex rxjava diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 0f73d0eb884d..2e4d96a11ae0 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -262,7 +262,7 @@ true - io.projectreactor.ipc + io.projectreactor.netty reactor-netty true diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/pom.xml index 9b0868ce9171..aed714a27f86 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-reactor-netty/pom.xml @@ -15,7 +15,7 @@ - io.projectreactor.ipc + io.projectreactor.netty reactor-netty diff --git a/spring-boot-project/spring-boot-test/pom.xml b/spring-boot-project/spring-boot-test/pom.xml index 1ea05b865286..c178191642d3 100644 --- a/spring-boot-project/spring-boot-test/pom.xml +++ b/spring-boot-project/spring-boot-test/pom.xml @@ -36,7 +36,7 @@ true - io.projectreactor.ipc + io.projectreactor.netty reactor-netty true diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index b268584e087b..c3ff324a6bb8 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -76,7 +76,7 @@ true - io.projectreactor.ipc + io.projectreactor.netty reactor-netty true diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java index 12a8e0186370..396120a499d1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java @@ -21,9 +21,9 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; -import reactor.ipc.netty.http.server.HttpServerOptions; -import reactor.ipc.netty.http.server.HttpServerRequest; -import reactor.ipc.netty.http.server.HttpServerResponse; +import reactor.netty.http.server.HttpServer; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; import org.springframework.boot.web.server.Compression; import org.springframework.util.MimeType; @@ -36,6 +36,7 @@ * * @author Stephane Maldini * @author Phillip Webb + * @author Brian Clozel */ final class CompressionCustomizer implements NettyServerCustomizer { @@ -49,15 +50,16 @@ final class CompressionCustomizer implements NettyServerCustomizer { } @Override - public void customize(HttpServerOptions.Builder builder) { + public HttpServer apply(HttpServer server) { if (this.compression.getMinResponseSize() >= 0) { - builder.compression(this.compression.getMinResponseSize()); + server = server.compress(this.compression.getMinResponseSize()); } CompressionPredicate mimeTypes = getMimeTypesPredicate( this.compression.getMimeTypes()); CompressionPredicate excludedUserAgents = getExcludedUserAgentsPredicate( this.compression.getExcludedUserAgents()); - builder.compression(mimeTypes.and(excludedUserAgents)); + server = server.compress(mimeTypes.and(excludedUserAgents)); + return server; } private CompressionPredicate getMimeTypesPredicate(String[] mimeTypes) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index 970dab8e0630..e3cd870b74d7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -23,8 +23,7 @@ import java.util.Collection; import java.util.List; -import reactor.ipc.netty.http.server.HttpServer; -import reactor.ipc.netty.http.server.HttpServerOptions.Builder; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; @@ -99,20 +98,19 @@ public void setLifecycleTimeout(Duration lifecycleTimeout) { } private HttpServer createHttpServer() { - return HttpServer.builder().options((options) -> { - options.listenAddress(getListenAddress()); - if (getSsl() != null && getSsl().isEnabled()) { - SslServerCustomizer sslServerCustomizer = new SslServerCustomizer( - getSsl(), getSslStoreProvider()); - sslServerCustomizer.customize(options); - } - if (getCompression() != null && getCompression().getEnabled()) { - CompressionCustomizer compressionCustomizer = new CompressionCustomizer( - getCompression()); - compressionCustomizer.customize(options); - } - applyCustomizers(options); - }).build(); + HttpServer server = HttpServer.create().tcpConfiguration( + (tcpServer) -> tcpServer.addressSupplier(() -> getListenAddress())); + if (getSsl() != null && getSsl().isEnabled()) { + SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(getSsl(), + getSslStoreProvider()); + server = sslServerCustomizer.apply(server); + } + if (getCompression() != null && getCompression().getEnabled()) { + CompressionCustomizer compressionCustomizer = new CompressionCustomizer( + getCompression()); + server = compressionCustomizer.apply(server); + } + return applyCustomizers(server); } private InetSocketAddress getListenAddress() { @@ -122,8 +120,11 @@ private InetSocketAddress getListenAddress() { return new InetSocketAddress(getPort()); } - private void applyCustomizers(Builder options) { - this.serverCustomizers.forEach((customizer) -> customizer.customize(options)); + private HttpServer applyCustomizers(HttpServer server) { + for (NettyServerCustomizer customizer : this.serverCustomizers) { + server = customizer.apply(server); + } + return server; } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java index 0817247c9fc3..c98647394320 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyServerCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,22 +16,18 @@ package org.springframework.boot.web.embedded.netty; -import reactor.ipc.netty.http.server.HttpServerOptions; +import java.util.function.Function; + +import reactor.netty.http.server.HttpServer; /** - * Callback interface that can be used to customize a Reactor Netty server builder. + * Mapping function that can be used to customize a Reactor Netty server instance. * * @author Brian Clozel * @see NettyReactiveWebServerFactory - * @since 2.0.0 + * @since 2.1.0 */ @FunctionalInterface -public interface NettyServerCustomizer { - - /** - * Customize the Netty web server. - * @param builder the server options builder to customize - */ - void customize(HttpServerOptions.Builder builder); +public interface NettyServerCustomizer extends Function { } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index a0abe898566b..9ba693a3b09c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -17,15 +17,13 @@ package org.springframework.boot.web.embedded.netty; import java.net.BindException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.time.Duration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import reactor.ipc.netty.http.HttpResources; -import reactor.ipc.netty.http.server.HttpServer; -import reactor.ipc.netty.tcp.BlockingNettyContext; +import reactor.netty.DisposableServer; +import reactor.netty.http.HttpResources; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.WebServer; @@ -53,7 +51,7 @@ public class NettyWebServer implements WebServer { private final Duration lifecycleTimeout; - private BlockingNettyContext nettyContext; + private DisposableServer disposableServer; public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter, Duration lifecycleTimeout) { @@ -66,30 +64,27 @@ public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAd @Override public void start() throws WebServerException { - if (this.nettyContext == null) { + if (this.disposableServer == null) { try { - this.nettyContext = startHttpServer(); + this.disposableServer = startHttpServer(); } catch (Exception ex) { if (findBindException(ex) != null) { - SocketAddress address = this.httpServer.options().getAddress(); - if (address instanceof InetSocketAddress) { - throw new PortInUseException( - ((InetSocketAddress) address).getPort()); - } + throw new PortInUseException(getPort()); } throw new WebServerException("Unable to start Netty", ex); } NettyWebServer.logger.info("Netty started on port(s): " + getPort()); - startDaemonAwaitThread(this.nettyContext); + startDaemonAwaitThread(this.disposableServer); } } - private BlockingNettyContext startHttpServer() { + private DisposableServer startHttpServer() { if (this.lifecycleTimeout != null) { - return this.httpServer.start(this.handlerAdapter, this.lifecycleTimeout); + return this.httpServer.handle(this.handlerAdapter) + .bindNow(this.lifecycleTimeout); } - return this.httpServer.start(this.handlerAdapter); + return this.httpServer.handle(this.handlerAdapter).bindNow(); } private BindException findBindException(Exception ex) { @@ -103,12 +98,12 @@ private BindException findBindException(Exception ex) { return null; } - private void startDaemonAwaitThread(BlockingNettyContext nettyContext) { + private void startDaemonAwaitThread(DisposableServer disposableServer) { Thread awaitThread = new Thread("server") { @Override public void run() { - nettyContext.getContext().onClose().block(); + disposableServer.onDispose().block(); } }; @@ -119,19 +114,24 @@ public void run() { @Override public void stop() throws WebServerException { - if (this.nettyContext != null) { - this.nettyContext.shutdown(); + if (this.disposableServer != null) { // temporary fix for gh-9146 - this.nettyContext.getContext().onClose() - .doOnSuccess((o) -> HttpResources.reset()).block(); - this.nettyContext = null; + this.disposableServer.onDispose() + .doFinally((signal) -> HttpResources.reset()); + if (this.lifecycleTimeout != null) { + this.disposableServer.disposeNow(this.lifecycleTimeout); + } + else { + this.disposableServer.disposeNow(); + } + this.disposableServer = null; } } @Override public int getPort() { - if (this.nettyContext != null) { - return this.nettyContext.getPort(); + if (this.disposableServer != null) { + return this.disposableServer.port(); } return 0; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index abe648b156a1..93672318293a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -19,13 +19,14 @@ import java.net.URL; import java.security.KeyStore; import java.util.Arrays; +import java.util.function.Consumer; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; -import reactor.ipc.netty.http.server.HttpServerOptions; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.SslStoreProvider; @@ -49,30 +50,36 @@ public SslServerCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) { } @Override - public void customize(HttpServerOptions.Builder builder) { - SslContextBuilder sslBuilder = SslContextBuilder - .forServer(getKeyManagerFactory(this.ssl, this.sslStoreProvider)) - .trustManager(getTrustManagerFactory(this.ssl, this.sslStoreProvider)); - if (this.ssl.getEnabledProtocols() != null) { - sslBuilder.protocols(this.ssl.getEnabledProtocols()); - } - if (this.ssl.getCiphers() != null) { - sslBuilder = sslBuilder.ciphers(Arrays.asList(this.ssl.getCiphers())); - } - if (this.ssl.getClientAuth() == Ssl.ClientAuth.NEED) { - sslBuilder = sslBuilder.clientAuth(ClientAuth.REQUIRE); - } - else if (this.ssl.getClientAuth() == Ssl.ClientAuth.WANT) { - sslBuilder = sslBuilder.clientAuth(ClientAuth.OPTIONAL); - } + public HttpServer apply(HttpServer server) { try { - builder.sslContext(sslBuilder.build()); + return server.secure((contextSpec) -> contextSpec.forServer() + .sslContext(getContextBuilderConsumer())); } catch (Exception ex) { throw new IllegalStateException(ex); } } + protected Consumer getContextBuilderConsumer() { + return (builder) -> { + builder.keyManager(getKeyManagerFactory(this.ssl, this.sslStoreProvider)) + .trustManager( + getTrustManagerFactory(this.ssl, this.sslStoreProvider)); + if (this.ssl.getEnabledProtocols() != null) { + builder.protocols(this.ssl.getEnabledProtocols()); + } + if (this.ssl.getCiphers() != null) { + builder.ciphers(Arrays.asList(this.ssl.getCiphers())); + } + if (this.ssl.getClientAuth() == Ssl.ClientAuth.NEED) { + builder.clientAuth(ClientAuth.REQUIRE); + } + else if (this.ssl.getClientAuth() == Ssl.ClientAuth.WANT) { + builder.clientAuth(ClientAuth.OPTIONAL); + } + }; + } + protected KeyManagerFactory getKeyManagerFactory(Ssl ssl, SslStoreProvider sslStoreProvider) { try { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index d485064c7f7a..439833351650 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -16,20 +16,19 @@ package org.springframework.boot.web.embedded.netty; -import java.time.Duration; import java.util.Arrays; +import org.junit.Ignore; import org.junit.Test; import org.mockito.InOrder; -import reactor.ipc.netty.http.server.HttpServerOptions; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests; import org.springframework.boot.web.server.WebServerException; -import org.springframework.test.util.ReflectionTestUtils; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; @@ -47,6 +46,7 @@ protected NettyReactiveWebServerFactory getFactory() { } @Test + @Ignore public void exceptionIsThrownWhenPortIsAlreadyInUse() { AbstractReactiveWebServerFactory factory = getFactory(); factory.setPort(0); @@ -63,25 +63,15 @@ public void nettyCustomizers() { NettyServerCustomizer[] customizers = new NettyServerCustomizer[2]; for (int i = 0; i < customizers.length; i++) { customizers[i] = mock(NettyServerCustomizer.class); + given(customizers[i].apply(any(HttpServer.class))) + .will((invocation) -> invocation.getArgument(0)); } factory.setServerCustomizers(Arrays.asList(customizers[0], customizers[1])); this.webServer = factory.getWebServer(new EchoHandler()); InOrder ordered = inOrder((Object[]) customizers); for (NettyServerCustomizer customizer : customizers) { - ordered.verify(customizer).customize(any(HttpServerOptions.Builder.class)); + ordered.verify(customizer).apply(any(HttpServer.class)); } } - @Test - public void customStartupTimeout() { - Duration timeout = Duration.ofDays(365); - NettyReactiveWebServerFactory factory = getFactory(); - factory.setLifecycleTimeout(timeout); - this.webServer = factory.getWebServer(new EchoHandler()); - this.webServer.start(); - Object context = ReflectionTestUtils.getField(this.webServer, "nettyContext"); - Object actualTimeout = ReflectionTestUtils.getField(context, "lifecycleTimeout"); - assertThat(actualTimeout).isEqualTo(timeout); - } - } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 6fa3cc46f54e..50d4f509ac8b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -23,7 +23,6 @@ import java.security.KeyStore; import java.time.Duration; import java.util.Arrays; -import java.util.function.Consumer; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLException; @@ -39,8 +38,8 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import reactor.core.publisher.Mono; -import reactor.ipc.netty.NettyPipeline; -import reactor.ipc.netty.http.client.HttpClientOptions; +import reactor.netty.NettyPipeline; +import reactor.netty.http.client.HttpClient; import reactor.test.StepVerifier; import org.springframework.boot.testsupport.rule.OutputCapture; @@ -135,9 +134,11 @@ protected final void testBasicSslWithKeyStore(String keyStore, String keyPasswor } protected ReactorClientHttpConnector buildTrustAllSslConnector() { - return new ReactorClientHttpConnector((options) -> options.sslSupport( - (sslContextBuilder) -> sslContextBuilder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE))); + HttpClient client = HttpClient.create().wiretap() + .secure((sslContextSpec) -> sslContextSpec.forClient() + .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE))); + return new ReactorClientHttpConnector(client); } @Test @@ -169,10 +170,12 @@ protected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector() KeyManagerFactory clientKeyManagerFactory = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); clientKeyManagerFactory.init(clientKeyStore, "password".toCharArray()); - return new ReactorClientHttpConnector((options) -> options.sslSupport( - (sslContextBuilder) -> sslContextBuilder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .keyManager(clientKeyManagerFactory))); + HttpClient client = HttpClient.create().wiretap() + .secure((sslContextSpec) -> sslContextSpec.forClient() + .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .keyManager(clientKeyManagerFactory))); + return new ReactorClientHttpConnector(client); } protected void testClientAuthSuccess(Ssl sslConfiguration, @@ -228,16 +231,13 @@ protected void testClientAuthFailure(Ssl sslConfiguration, } protected WebClient.Builder getWebClient() { - return getWebClient((options) -> { - }); + return getWebClient(HttpClient.create().wiretap()); } - protected WebClient.Builder getWebClient( - Consumer clientOptions) { + protected WebClient.Builder getWebClient(HttpClient client) { InetSocketAddress address = new InetSocketAddress(this.webServer.getPort()); String baseUrl = "http://" + address.getHostString() + ":" + address.getPort(); - return WebClient.builder() - .clientConnector(new ReactorClientHttpConnector(clientOptions)) + return WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)) .baseUrl(baseUrl); } @@ -302,10 +302,12 @@ protected WebClient prepareCompressionTest(Compression compression) { this.webServer = factory .getWebServer(new CharsHandler(3000, MediaType.TEXT_PLAIN)); this.webServer.start(); - return getWebClient((options) -> options.compression(true) - .afterChannelInit((channel) -> channel.pipeline().addBefore( - NettyPipeline.HttpDecompressor, "CompressionTest", - new CompressionDetectionHandler()))).build(); + + HttpClient client = HttpClient.create().wiretap().compress().tcpConfiguration( + (tcpClient) -> tcpClient.doOnConnected((connection) -> connection + .channel().pipeline().addBefore(NettyPipeline.HttpDecompressor, + "CompressionTest", new CompressionDetectionHandler()))); + return getWebClient(client).build(); } protected void assertResponseIsCompressed(ResponseEntity response) { From ef5301d0798d61dd600c5d058219f61d1ef78c62 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 4 Jun 2018 12:12:29 -0700 Subject: [PATCH 098/701] Add saaj and jax-ws dependencies for Java 9 build Add test dependencies for saaj-impl and jax-ws since Java 9+ no longer includes them. See gh-1270 --- .../spring-boot-autoconfigure/pom.xml | 13 ++++++++++++- .../spring-boot-dependencies/pom.xml | 15 ++++++++++++++- spring-boot-project/spring-boot/pom.xml | 13 ++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 7340eb977e73..60bfeb0db173 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -719,11 +720,21 @@ json-path test + + com.sun.xml.messaging.saaj + saaj-impl + test + javax.json javax.json-api test + + javax.xml.ws + jaxws-api + test + mysql mysql-connector-java diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 16541aab2707..7926990c3751 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -82,6 +83,7 @@ 3.0.8 1.3.2 1.1.0 + 2.3.0 2.3.0 2.0.1 1.1.2 @@ -169,6 +171,7 @@ 3.21.0.1 3.1.0 ${javax-mail.version} + 1.4.0 3.0.9.RELEASE 3.0.2.RELEASE 2.3.0 @@ -717,6 +720,11 @@ javax.mail ${sun-mail.version} + + com.sun.xml.messaging.saaj + saaj-impl + ${saaj-impl.version} + com.timgroup java-statsd-client @@ -1063,6 +1071,11 @@ jaxb-api ${javax-jaxb.version} + + javax.xml.ws + jaxws-api + ${javax-jaxws.version} + jaxen jaxen diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index c3ff324a6bb8..756f14f5443b 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -337,11 +338,21 @@ okhttp test + + com.sun.xml.messaging.saaj + saaj-impl + test + io.projectreactor reactor-test test + + javax.xml.ws + jaxws-api + test + mysql mysql-connector-java From 87af880446a2117df3eafa1d13bda205fd554bf8 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 4 Jun 2018 22:03:51 +0200 Subject: [PATCH 099/701] Reactor BOM is now declaring reactor-netty 0.8 See gh-13321 --- spring-boot-project/spring-boot-dependencies/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 7926990c3751..b50538c65def 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -939,13 +939,6 @@ import pom - - - io.projectreactor.netty - reactor-netty - 0.8.0.BUILD-SNAPSHOT - compile - io.reactivex rxjava From c1ab3eab69bc9473b518254bd078e5d13c0e0e75 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 4 Jun 2018 12:54:26 -0700 Subject: [PATCH 100/701] Polish --- .../client/WebServiceTemplateBuilder.java | 97 +++++++++---------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java index c8d831c3fbbe..a855d780cace 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -26,6 +26,7 @@ import javax.xml.transform.TransformerFactory; import org.springframework.beans.BeanUtils; +import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; @@ -76,9 +77,17 @@ public class WebServiceTemplateBuilder { private final WebServiceMessageFactory messageFactory; public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) { - this(true, Collections.emptySet(), Collections.emptySet(), - append(Collections.emptySet(), customizers), - new WebServiceMessageSenders(), null, null, null, null, null); + this.detectHttpMessageSender = true; + this.interceptors = null; + this.internalCustomizers = null; + this.customizers = Collections + .unmodifiableSet(new LinkedHashSet<>(Arrays.asList(customizers))); + this.messageSenders = new WebServiceMessageSenders(); + this.marshaller = null; + this.unmarshaller = null; + this.destinationProvider = null; + this.transformerFactoryClass = null; + this.messageFactory = null; } private WebServiceTemplateBuilder(boolean detectHttpMessageSender, @@ -89,11 +98,11 @@ private WebServiceTemplateBuilder(boolean detectHttpMessageSender, Unmarshaller unmarshaller, DestinationProvider destinationProvider, Class transformerFactoryClass, WebServiceMessageFactory messageFactory) { + this.detectHttpMessageSender = detectHttpMessageSender; this.interceptors = interceptors; this.internalCustomizers = internalCustomizers; this.customizers = customizers; this.messageSenders = messageSenders; - this.detectHttpMessageSender = detectHttpMessageSender; this.marshaller = marshaller; this.unmarshaller = unmarshaller; this.destinationProvider = destinationProvider; @@ -357,7 +366,7 @@ public WebServiceTemplateBuilder setCheckConnectionForError( **/ public WebServiceTemplateBuilder setWebServiceMessageFactory( WebServiceMessageFactory messageFactory) { - Assert.notNull(messageFactory, "messageFactory must not be null"); + Assert.notNull(messageFactory, "MessageFactory must not be null"); return new WebServiceTemplateBuilder(this.detectHttpMessageSender, this.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, @@ -425,7 +434,6 @@ public WebServiceTemplateBuilder setTransformerFactoryClass( /** * Set the default URI to be used on operations that do not have a URI parameter. - *

* Typically, either this property is set, or * {@link #setDestinationProvider(DestinationProvider)}, but not both. * @param defaultUri the destination provider URI to be used on operations that do not @@ -439,10 +447,8 @@ public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { } /** - * Set the {@link DestinationProvider} to use - *

- * Typically, either this property is set, or {@link #setDefaultUri(String)}, but not - * both. + * Set the {@link DestinationProvider} to use. Typically, either this property is set, + * or {@link #setDefaultUri(String)}, but not both. * @param destinationProvider the destination provider to be used on operations that * do not have a URI parameter. * @return a new builder instance. @@ -450,7 +456,7 @@ public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { */ public WebServiceTemplateBuilder setDestinationProvider( DestinationProvider destinationProvider) { - Assert.notNull(destinationProvider, "destinationProvider must not be null"); + Assert.notNull(destinationProvider, "DestinationProvider must not be null"); return new WebServiceTemplateBuilder(this.detectHttpMessageSender, this.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, @@ -492,49 +498,45 @@ public T build(Class webServiceTemplateClass) * @see #build(Class) */ public T configure(T webServiceTemplate) { - Assert.notNull(webServiceTemplate, "webServiceTemplate must not be null"); + Assert.notNull(webServiceTemplate, "WebServiceTemplate must not be null"); configureMessageSenders(webServiceTemplate); - if (!CollectionUtils.isEmpty(this.internalCustomizers)) { - for (WebServiceTemplateCustomizer internalCustomizer : this.internalCustomizers) { - internalCustomizer.customize(webServiceTemplate); - } - } - if (this.marshaller != null) { - webServiceTemplate.setMarshaller(this.marshaller); - } - if (this.unmarshaller != null) { - webServiceTemplate.setUnmarshaller(this.unmarshaller); - } - if (this.destinationProvider != null) { - webServiceTemplate.setDestinationProvider(this.destinationProvider); - } - if (this.transformerFactoryClass != null) { - webServiceTemplate.setTransformerFactoryClass(this.transformerFactoryClass); - } - if (this.messageFactory != null) { - webServiceTemplate.setMessageFactory(this.messageFactory); - } + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + applyCustomizers(webServiceTemplate, this.internalCustomizers); + map.from(() -> this.marshaller).to(webServiceTemplate::setMarshaller); + map.from(() -> this.unmarshaller).to(webServiceTemplate::setUnmarshaller); + map.from(() -> this.destinationProvider) + .to(webServiceTemplate::setDestinationProvider); + map.from(() -> this.transformerFactoryClass) + .to(webServiceTemplate::setTransformerFactoryClass); + map.from(() -> this.messageFactory).to(webServiceTemplate::setMessageFactory); if (!CollectionUtils.isEmpty(this.interceptors)) { - webServiceTemplate.setInterceptors( - append(this.interceptors, webServiceTemplate.getInterceptors()) - .toArray(new ClientInterceptor[0])); - } - if (!CollectionUtils.isEmpty(this.customizers)) { - for (WebServiceTemplateCustomizer customizer : this.customizers) { - customizer.customize(webServiceTemplate); + Set merged = new LinkedHashSet<>(this.interceptors); + if (webServiceTemplate.getInterceptors() != null) { + merged.addAll(Arrays.asList(webServiceTemplate.getInterceptors())); } + webServiceTemplate.setInterceptors(merged.toArray(new ClientInterceptor[0])); } + applyCustomizers(webServiceTemplate, this.customizers); return webServiceTemplate; } + private void applyCustomizers(WebServiceTemplate webServiceTemplate, + Set customizers) { + if (!CollectionUtils.isEmpty(customizers)) { + for (WebServiceTemplateCustomizer internalCustomizer : customizers) { + internalCustomizer.customize(webServiceTemplate); + } + } + } + private void configureMessageSenders( T webServiceTemplate) { if (this.messageSenders.isOnlyAdditional() && this.detectHttpMessageSender) { - Set mergedMessageSenders = append( + Set merged = append( this.messageSenders.getMessageSenders(), new HttpWebServiceMessageSenderBuilder().build()); - webServiceTemplate.setMessageSenders( - mergedMessageSenders.toArray(new WebServiceMessageSender[0])); + webServiceTemplate + .setMessageSenders(merged.toArray(new WebServiceMessageSender[0])); } else if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) { webServiceTemplate.setMessageSenders(this.messageSenders.getMessageSenders() @@ -542,15 +544,8 @@ else if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) { } } - private static Set append(Set set, T[] additions) { - return append(set, additions != null - ? new LinkedHashSet<>(Arrays.asList(additions)) : Collections.emptySet()); - } - - private static Set append(Set set, T addition) { - Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); - result.add(addition); - return Collections.unmodifiableSet(result); + private Set append(Set set, T addition) { + return append(set, Collections.singleton(addition)); } private static Set append(Set set, Collection additions) { From ce3420748f41bb7e4288e38be592a5cacfd5848a Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 4 Jun 2018 18:16:08 +0300 Subject: [PATCH 101/701] RestTemplateCustomizers should be applied at the end See gh-13358 --- .../boot/web/client/RestTemplateBuilder.java | 3 +- .../web/client/RestTemplateBuilderTests.java | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 88cf18909ce1..4cdf7bcdcf2e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -531,12 +531,13 @@ public T configure(T restTemplate) { if (this.basicAuthorization != null) { restTemplate.getInterceptors().add(this.basicAuthorization); } + restTemplate.getInterceptors().addAll(this.interceptors); + if (!CollectionUtils.isEmpty(this.restTemplateCustomizers)) { for (RestTemplateCustomizer customizer : this.restTemplateCustomizers) { customizer.customize(restTemplate); } } - restTemplate.getInterceptors().addAll(this.interceptors); return restTemplate; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index d94e3f955733..58c7a44591ca 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -32,6 +32,7 @@ import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.InterceptingClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthorizationInterceptor; @@ -497,6 +498,38 @@ public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { .isInstanceOf(BufferingClientHttpRequestFactory.class); } + @Test + public void customizerShouldBeAppliedInTheEnd() { + + ClientHttpRequestInterceptor interceptor = this.interceptor; + HttpMessageConverter messageConverter = this.messageConverter; + ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); + + this.builder.interceptors(interceptor).messageConverters(messageConverter) + .rootUri("http://localhost:8080").errorHandler(errorHandler) + .basicAuthorization("spring", "boot") + .requestFactory(HttpComponentsClientHttpRequestFactory.class) + .customizers((restTemplate) -> { + ClientHttpRequestFactory requestFactory = restTemplate + .getRequestFactory(); + assertThat(restTemplate.getInterceptors()).hasSize(2) + .contains(interceptor).anyMatch( + (ic) -> ic instanceof BasicAuthorizationInterceptor); + assertThat(restTemplate.getMessageConverters()) + .contains(messageConverter); + assertThat(restTemplate.getUriTemplateHandler()) + .isInstanceOf(RootUriTemplateHandler.class); + assertThat(restTemplate.getErrorHandler()).isEqualTo(errorHandler); + assertThat(requestFactory) + .isInstanceOf(InterceptingClientHttpRequestFactory.class); + assertThat(ReflectionTestUtils.getField(requestFactory, + "requestFactory")).isInstanceOf( + HttpComponentsClientHttpRequestFactory.class); + + }).build(); + + } + public static class RestTemplateSubclass extends RestTemplate { } From c612ed26950396789ae85d1ee1ce2a509f8b74ea Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 09:45:19 +0200 Subject: [PATCH 102/701] Polish "RestTemplateCustomizers should be applied at the end" Closes gh-13358 --- .../boot/web/client/RestTemplateBuilder.java | 1 - .../web/client/RestTemplateBuilderTests.java | 58 +++++++++---------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 4cdf7bcdcf2e..ad1efb715909 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -532,7 +532,6 @@ public T configure(T restTemplate) { restTemplate.getInterceptors().add(this.basicAuthorization); } restTemplate.getInterceptors().addAll(this.interceptors); - if (!CollectionUtils.isEmpty(this.restTemplateCustomizers)) { for (RestTemplateCustomizer customizer : this.restTemplateCustomizers) { customizer.customize(restTemplate); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 58c7a44591ca..cd87b9a8617e 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -389,6 +389,32 @@ public void additionalCustomizersShouldAddToExisting() { verify(customizer2).customize(template); } + @Test + public void customizerShouldBeAppliedInTheEnd() { + ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); + ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + this.builder.interceptors(this.interceptor) + .messageConverters(this.messageConverter).rootUri("http://localhost:8080") + .errorHandler(errorHandler).basicAuthorization("spring", "boot") + .requestFactory(() -> requestFactory).customizers((restTemplate) -> { + assertThat(restTemplate.getInterceptors()).hasSize(2) + .contains(this.interceptor).anyMatch( + (ic) -> ic instanceof BasicAuthorizationInterceptor); + assertThat(restTemplate.getMessageConverters()) + .contains(this.messageConverter); + assertThat(restTemplate.getUriTemplateHandler()) + .isInstanceOf(RootUriTemplateHandler.class); + assertThat(restTemplate.getErrorHandler()).isEqualTo(errorHandler); + ClientHttpRequestFactory actualRequestFactory = restTemplate + .getRequestFactory(); + assertThat(actualRequestFactory) + .isInstanceOf(InterceptingClientHttpRequestFactory.class); + assertThat(ReflectionTestUtils.getField(actualRequestFactory, + "requestFactory")).isSameAs(requestFactory); + }).build(); + + } + @Test public void buildShouldReturnRestTemplate() { RestTemplate template = this.builder.build(); @@ -498,38 +524,6 @@ public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { .isInstanceOf(BufferingClientHttpRequestFactory.class); } - @Test - public void customizerShouldBeAppliedInTheEnd() { - - ClientHttpRequestInterceptor interceptor = this.interceptor; - HttpMessageConverter messageConverter = this.messageConverter; - ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); - - this.builder.interceptors(interceptor).messageConverters(messageConverter) - .rootUri("http://localhost:8080").errorHandler(errorHandler) - .basicAuthorization("spring", "boot") - .requestFactory(HttpComponentsClientHttpRequestFactory.class) - .customizers((restTemplate) -> { - ClientHttpRequestFactory requestFactory = restTemplate - .getRequestFactory(); - assertThat(restTemplate.getInterceptors()).hasSize(2) - .contains(interceptor).anyMatch( - (ic) -> ic instanceof BasicAuthorizationInterceptor); - assertThat(restTemplate.getMessageConverters()) - .contains(messageConverter); - assertThat(restTemplate.getUriTemplateHandler()) - .isInstanceOf(RootUriTemplateHandler.class); - assertThat(restTemplate.getErrorHandler()).isEqualTo(errorHandler); - assertThat(requestFactory) - .isInstanceOf(InterceptingClientHttpRequestFactory.class); - assertThat(ReflectionTestUtils.getField(requestFactory, - "requestFactory")).isInstanceOf( - HttpComponentsClientHttpRequestFactory.class); - - }).build(); - - } - public static class RestTemplateSubclass extends RestTemplate { } From ca3659059aa8c648603d2f6a5318860327aa55e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 16 May 2018 01:10:22 -0500 Subject: [PATCH 103/701] Add support to set visibility via JacksonProperties This commit allows to configure properties visibility. See gh-13214 --- .../jackson/JacksonAutoConfiguration.java | 9 +++++++ .../jackson/JacksonProperties.java | 15 ++++++++++++ .../JacksonAutoConfigurationTests.java | 24 +++++++++++++++++++ .../appendix-application-properties.adoc | 1 + 4 files changed, 49 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index 5a52655ba67a..aa4320b06dbd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -27,7 +27,9 @@ import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; @@ -73,6 +75,7 @@ * @author Sebastien Deleuze * @author Johannes Edmeier * @author Phillip Webb + * @author Eddú Meléndez * @since 1.1.0 */ @Configuration @@ -249,6 +252,7 @@ public void customize(Jackson2ObjectMapperBuilder builder) { configurePropertyNamingStrategy(builder); configureModules(builder); configureLocale(builder); + configureVisibility(builder, this.jacksonProperties.getAccessor()); } private void configureFeatures(Jackson2ObjectMapperBuilder builder, @@ -347,6 +351,11 @@ private void configureLocale(Jackson2ObjectMapperBuilder builder) { } } + private void configureVisibility(Jackson2ObjectMapperBuilder builder, + Map accessors) { + accessors.forEach(builder::visibility); + } + private static Collection getBeans(ListableBeanFactory beanFactory, Class type) { return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java index be580863de85..067c3076e931 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java @@ -21,7 +21,9 @@ import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -105,6 +107,12 @@ public class JacksonProperties { */ private Locale locale; + /** + * Jackson visibilities to auto-detect properties. + */ + private Map accessor = new EnumMap<>( + PropertyAccessor.class); + public String getDateFormat() { return this.dateFormat; } @@ -174,4 +182,11 @@ public void setLocale(Locale locale) { this.locale = locale; } + public Map getAccessor() { + return this.accessor; + } + + public void setAccessor(Map accessor) { + this.accessor = accessor; + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index 9e7e9754a0ef..8d5405993d8f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -459,6 +459,19 @@ public void writeDatesAsTimestampsDefault() { }); } + @Test + public void writeWithVisibility() { + this.contextRunner.withPropertyValues("spring.jackson.accessor.getter:NONE", + "spring.jackson.accessor.field:ANY") + .run((context) -> { + ObjectMapper mapper = context.getBean(ObjectMapper.class); + String json = mapper.writeValueAsString(new VisibilityBean()); + assertThat(json).contains("property1"); + assertThat(json).contains("property2"); + assertThat(json).doesNotContain("property3"); + }); + } + private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class... configClasses) { this.contextRunner.withUserConfiguration(configClasses).run((context) -> { @@ -614,4 +627,15 @@ Set getOwners() { } + private static class VisibilityBean { + + private String property1; + + public String property2; + + public String getProperty3() { + return null; + } + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 1c605b4d4f13..86fb51842e65 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -329,6 +329,7 @@ content into your application. Rather, pick only the properties that you need. spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access. # JACKSON ({sc-spring-boot-autoconfigure}/jackson/JacksonProperties.{sc-ext}[JacksonProperties]) + spring.jackson.accessor.*= # Jackson visibilities to auto-detect properties. spring.jackson.date-format= # Date format string or a fully-qualified date format class name. For instance, `yyyy-MM-dd HH:mm:ss`. spring.jackson.default-property-inclusion= # Controls the inclusion of properties during serialization. Configured with one of the values in Jackson's JsonInclude.Include enumeration. spring.jackson.deserialization.*= # Jackson on/off features that affect the way Java objects are deserialized. From 51cf4e5d7412b605e813a5c0d681ddd164824ce1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 10:30:15 +0200 Subject: [PATCH 104/701] Polish "Add support to set visibility via JacksonProperties" Closes gh-13214 --- .../jackson/JacksonAutoConfiguration.java | 12 +++++----- .../jackson/JacksonProperties.java | 24 +++++++++---------- .../JacksonAutoConfigurationTests.java | 8 +++---- .../appendix-application-properties.adoc | 2 +- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index aa4320b06dbd..9e72b7c07c89 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -243,6 +243,7 @@ public void customize(Jackson2ObjectMapperBuilder builder) { builder.timeZone(this.jacksonProperties.getTimeZone()); } configureFeatures(builder, FEATURE_DEFAULTS); + configureVisibility(builder, this.jacksonProperties.getVisibility()); configureFeatures(builder, this.jacksonProperties.getDeserialization()); configureFeatures(builder, this.jacksonProperties.getSerialization()); configureFeatures(builder, this.jacksonProperties.getMapper()); @@ -252,7 +253,6 @@ public void customize(Jackson2ObjectMapperBuilder builder) { configurePropertyNamingStrategy(builder); configureModules(builder); configureLocale(builder); - configureVisibility(builder, this.jacksonProperties.getAccessor()); } private void configureFeatures(Jackson2ObjectMapperBuilder builder, @@ -269,6 +269,11 @@ private void configureFeatures(Jackson2ObjectMapperBuilder builder, }); } + private void configureVisibility(Jackson2ObjectMapperBuilder builder, + Map accessors) { + accessors.forEach(builder::visibility); + } + private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { // We support a fully qualified class name extending DateFormat or a date // pattern string value @@ -351,11 +356,6 @@ private void configureLocale(Jackson2ObjectMapperBuilder builder) { } } - private void configureVisibility(Jackson2ObjectMapperBuilder builder, - Map accessors) { - accessors.forEach(builder::visibility); - } - private static Collection getBeans(ListableBeanFactory beanFactory, Class type) { return BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, type) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java index 067c3076e931..624f942dc79a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java @@ -61,6 +61,13 @@ public class JacksonProperties { */ private String propertyNamingStrategy; + /** + * Jackson visibility thresholds that can be used to limit which methods (and fields) + * are auto-detected. + */ + private Map visibility = new EnumMap<>( + PropertyAccessor.class); + /** * Jackson on/off features that affect the way Java objects are serialized. */ @@ -107,12 +114,6 @@ public class JacksonProperties { */ private Locale locale; - /** - * Jackson visibilities to auto-detect properties. - */ - private Map accessor = new EnumMap<>( - PropertyAccessor.class); - public String getDateFormat() { return this.dateFormat; } @@ -137,6 +138,10 @@ public void setPropertyNamingStrategy(String propertyNamingStrategy) { this.propertyNamingStrategy = propertyNamingStrategy; } + public Map getVisibility() { + return this.visibility; + } + public Map getSerialization() { return this.serialization; } @@ -182,11 +187,4 @@ public void setLocale(Locale locale) { this.locale = locale; } - public Map getAccessor() { - return this.accessor; - } - - public void setAccessor(Map accessor) { - this.accessor = accessor; - } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index 8d5405993d8f..4e9e90e4787f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -461,15 +461,14 @@ public void writeDatesAsTimestampsDefault() { @Test public void writeWithVisibility() { - this.contextRunner.withPropertyValues("spring.jackson.accessor.getter:NONE", - "spring.jackson.accessor.field:ANY") - .run((context) -> { + this.contextRunner.withPropertyValues("spring.jackson.visibility.getter:none", + "spring.jackson.visibility.field:any").run((context) -> { ObjectMapper mapper = context.getBean(ObjectMapper.class); String json = mapper.writeValueAsString(new VisibilityBean()); assertThat(json).contains("property1"); assertThat(json).contains("property2"); assertThat(json).doesNotContain("property3"); - }); + }); } private void assertParameterNamesModuleCreatorBinding(Mode expectedMode, @@ -636,6 +635,7 @@ private static class VisibilityBean { public String getProperty3() { return null; } + } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 86fb51842e65..d01e0a67318c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -329,7 +329,6 @@ content into your application. Rather, pick only the properties that you need. spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access. # JACKSON ({sc-spring-boot-autoconfigure}/jackson/JacksonProperties.{sc-ext}[JacksonProperties]) - spring.jackson.accessor.*= # Jackson visibilities to auto-detect properties. spring.jackson.date-format= # Date format string or a fully-qualified date format class name. For instance, `yyyy-MM-dd HH:mm:ss`. spring.jackson.default-property-inclusion= # Controls the inclusion of properties during serialization. Configured with one of the values in Jackson's JsonInclude.Include enumeration. spring.jackson.deserialization.*= # Jackson on/off features that affect the way Java objects are deserialized. @@ -341,6 +340,7 @@ content into your application. Rather, pick only the properties that you need. spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy. Can also be a fully-qualified class name of a PropertyNamingStrategy subclass. spring.jackson.serialization.*= # Jackson on/off features that affect the way Java objects are serialized. spring.jackson.time-zone= # Time zone used when formatting dates. For instance, "America/Los_Angeles" or "GMT+10". + spring.jackson.visibility.*= # Jackson visibility thresholds that can be used to limit which methods (and fields) are auto-detected. # GSON ({sc-spring-boot-autoconfigure}/gson/GsonProperties.{sc-ext}[GsonProperties]) spring.gson.date-format= # Format to use when serializing Date objects. From 47634f558739cf31e87774f03a4a81928324f36b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 13:21:03 +0200 Subject: [PATCH 105/701] Polish --- .../metrics/orm/jpa/HibernateMetricsAutoConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java index 4a7b1585b72e..9009e5f8633e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -41,6 +41,7 @@ * * @author Rui Figueira * @author Stephane Nicoll + * @since 2.1.0 */ @Configuration @AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class, From 8691d01aaf87e230ceca4ab05114e0e6263f732f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 15:44:52 +0200 Subject: [PATCH 106/701] Polish "Add duration support for setConnectTimout and setReadTimeout" See gh-13355 --- .../boot/web/client/RestTemplateBuilder.java | 212 ++++++++++-------- 1 file changed, 117 insertions(+), 95 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index ad1efb715909..8a4d2eb6ccf3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -19,12 +19,14 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Supplier; import org.springframework.beans.BeanUtils; @@ -76,7 +78,7 @@ public class RestTemplateBuilder { private final Set restTemplateCustomizers; - private final Set requestFactoryCustomizers; + private final RequestFactoryCustomizer requestFactoryCustomizer; private final Set interceptors; @@ -96,7 +98,7 @@ public RestTemplateBuilder(RestTemplateCustomizer... customizers) { this.basicAuthorization = null; this.restTemplateCustomizers = Collections .unmodifiableSet(new LinkedHashSet<>(Arrays.asList(customizers))); - this.requestFactoryCustomizers = Collections.emptySet(); + this.requestFactoryCustomizer = new RequestFactoryCustomizer(); this.interceptors = Collections.emptySet(); } @@ -106,7 +108,7 @@ private RestTemplateBuilder(boolean detectRequestFactory, String rootUri, UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler, BasicAuthorizationInterceptor basicAuthorization, Set restTemplateCustomizers, - Set requestFactoryCustomizers, + RequestFactoryCustomizer requestFactoryCustomizer, Set interceptors) { this.detectRequestFactory = detectRequestFactory; this.rootUri = rootUri; @@ -116,7 +118,7 @@ private RestTemplateBuilder(boolean detectRequestFactory, String rootUri, this.errorHandler = errorHandler; this.basicAuthorization = basicAuthorization; this.restTemplateCustomizers = restTemplateCustomizers; - this.requestFactoryCustomizers = requestFactoryCustomizers; + this.requestFactoryCustomizer = requestFactoryCustomizer; this.interceptors = interceptors; } @@ -131,7 +133,7 @@ public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) { return new RestTemplateBuilder(detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, this.interceptors); } @@ -145,7 +147,7 @@ public RestTemplateBuilder rootUri(String rootUri) { return new RestTemplateBuilder(this.detectRequestFactory, rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, this.interceptors); } @@ -179,7 +181,7 @@ public RestTemplateBuilder messageConverters( new LinkedHashSet>(messageConverters)), this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -209,7 +211,7 @@ public RestTemplateBuilder additionalMessageConverters( append(this.messageConverters, messageConverters), this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -225,7 +227,7 @@ public RestTemplateBuilder defaultMessageConverters() { new LinkedHashSet<>(new RestTemplate().getMessageConverters())), this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -258,7 +260,7 @@ public RestTemplateBuilder interceptors( return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, Collections.unmodifiableSet(new LinkedHashSet<>(interceptors))); } @@ -290,7 +292,7 @@ public RestTemplateBuilder additionalInterceptors( return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, append(this.interceptors, interceptors)); } @@ -332,7 +334,7 @@ public RestTemplateBuilder requestFactory( return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -346,7 +348,7 @@ public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHand return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -360,7 +362,7 @@ public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) { return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, this.interceptors); } @@ -376,7 +378,7 @@ public RestTemplateBuilder basicAuthorization(String username, String password) this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, new BasicAuthorizationInterceptor(username, password), - this.restTemplateCustomizers, this.requestFactoryCustomizers, + this.restTemplateCustomizers, this.requestFactoryCustomizer, this.interceptors); } @@ -414,7 +416,7 @@ public RestTemplateBuilder customizers( this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, Collections.unmodifiableSet(new LinkedHashSet( restTemplateCustomizers)), - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); } /** @@ -447,7 +449,22 @@ public RestTemplateBuilder additionalCustomizers( this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, append(this.restTemplateCustomizers, customizers), - this.requestFactoryCustomizers, this.interceptors); + this.requestFactoryCustomizer, this.interceptors); + } + + /** + * Sets the connection timeout on the underlying {@link ClientHttpRequestFactory}. + * @param connectTimeout the connection timeout + * @return a new builder instance. + * @since 2.1.0 + */ + public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) { + return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, + this.messageConverters, this.requestFactorySupplier, + this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, + this.restTemplateCustomizers, + this.requestFactoryCustomizer.connectTimeout(connectTimeout), + this.interceptors); } /** @@ -455,14 +472,25 @@ public RestTemplateBuilder additionalCustomizers( * {@link ClientHttpRequestFactory}. * @param connectTimeout the connection timeout in milliseconds * @return a new builder instance. + * @deprecated since 2.1.0 in favor of {@link #setConnectTimeout(Duration)} */ + @Deprecated public RestTemplateBuilder setConnectTimeout(int connectTimeout) { + return setConnectTimeout(Duration.ofMillis(connectTimeout)); + } + + /** + * Sets the read timeout on the underlying {@link ClientHttpRequestFactory}. + * @param readTimeout the read timeout + * @return a new builder instance. + * @since 2.1.0 + */ + public RestTemplateBuilder setReadTimeout(Duration readTimeout) { return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, - append(this.requestFactoryCustomizers, - new ConnectTimeoutRequestFactoryCustomizer(connectTimeout)), + this.requestFactoryCustomizer.readTimeout(readTimeout), this.interceptors); } @@ -471,15 +499,11 @@ public RestTemplateBuilder setConnectTimeout(int connectTimeout) { * {@link ClientHttpRequestFactory}. * @param readTimeout the read timeout in milliseconds * @return a new builder instance. + * @deprecated since 2.1.0 in favour of {@link #setReadTimeout(Duration)} */ + @Deprecated public RestTemplateBuilder setReadTimeout(int readTimeout) { - return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, - this.messageConverters, this.requestFactorySupplier, - this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, - this.restTemplateCustomizers, - append(this.requestFactoryCustomizers, - new ReadTimeoutRequestFactoryCustomizer(readTimeout)), - this.interceptors); + return setReadTimeout(Duration.ofMillis(readTimeout)); } /** @@ -549,105 +573,103 @@ else if (this.detectRequestFactory) { requestFactory = new ClientHttpRequestFactorySupplier().get(); } if (requestFactory != null) { - ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary( - requestFactory); - for (RequestFactoryCustomizer customizer : this.requestFactoryCustomizers) { - customizer.customize(unwrappedRequestFactory); + if (this.requestFactoryCustomizer != null) { + this.requestFactoryCustomizer.accept(requestFactory); } restTemplate.setRequestFactory(requestFactory); } } - private ClientHttpRequestFactory unwrapRequestFactoryIfNecessary( - ClientHttpRequestFactory requestFactory) { - if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { - return requestFactory; - } - ClientHttpRequestFactory unwrappedRequestFactory = requestFactory; - Field field = ReflectionUtils.findField( - AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); - ReflectionUtils.makeAccessible(field); - do { - unwrappedRequestFactory = (ClientHttpRequestFactory) ReflectionUtils - .getField(field, unwrappedRequestFactory); - } - while (unwrappedRequestFactory instanceof AbstractClientHttpRequestFactoryWrapper); - return unwrappedRequestFactory; - } - - private Set append(Set set, T addition) { - Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); - result.add(addition); - return Collections.unmodifiableSet(result); - } - private Set append(Set set, Collection additions) { Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); result.addAll(additions); return Collections.unmodifiableSet(result); } - /** - * Strategy interface used to customize the {@link ClientHttpRequestFactory}. - */ - private interface RequestFactoryCustomizer { + private static class RequestFactoryCustomizer + implements Consumer { - void customize(ClientHttpRequestFactory factory); + private final Duration connectTimeout; - } + private final Duration readTimeout; - /** - * {@link RequestFactoryCustomizer} to call a "set timeout" method. - */ - private abstract static class TimeoutRequestFactoryCustomizer - implements RequestFactoryCustomizer { + RequestFactoryCustomizer() { + this(null, null); + } - private final int timeout; + private RequestFactoryCustomizer(Duration connectTimeout, Duration readTimeout) { + this.connectTimeout = connectTimeout; + this.readTimeout = readTimeout; + } - private final String methodName; + public RequestFactoryCustomizer connectTimeout(Duration connectTimeout) { + return new RequestFactoryCustomizer(connectTimeout, this.readTimeout); + } - TimeoutRequestFactoryCustomizer(int timeout, String methodName) { - this.timeout = timeout; - this.methodName = methodName; + public RequestFactoryCustomizer readTimeout(Duration readTimeout) { + return new RequestFactoryCustomizer(this.connectTimeout, readTimeout); } @Override - public void customize(ClientHttpRequestFactory factory) { - ReflectionUtils.invokeMethod(findMethod(factory), factory, this.timeout); + public void accept(ClientHttpRequestFactory requestFactory) { + ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary( + requestFactory); + if (this.connectTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.connectTimeout, + "setConnectTimeout").customize(unwrappedRequestFactory); + } + if (this.readTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") + .customize(unwrappedRequestFactory); + } } - private Method findMethod(ClientHttpRequestFactory factory) { - Method method = ReflectionUtils.findMethod(factory.getClass(), - this.methodName, int.class); - if (method != null) { - return method; + private ClientHttpRequestFactory unwrapRequestFactoryIfNecessary( + ClientHttpRequestFactory requestFactory) { + if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { + return requestFactory; + } + ClientHttpRequestFactory unwrappedRequestFactory = requestFactory; + Field field = ReflectionUtils.findField( + AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); + ReflectionUtils.makeAccessible(field); + do { + unwrappedRequestFactory = (ClientHttpRequestFactory) ReflectionUtils + .getField(field, unwrappedRequestFactory); } - throw new IllegalStateException("Request factory " + factory.getClass() - + " does not have a " + this.methodName + "(int) method"); + while (unwrappedRequestFactory instanceof AbstractClientHttpRequestFactoryWrapper); + return unwrappedRequestFactory; } - } + /** + * {@link ClientHttpRequestFactory} customizer to call a "set timeout" method. + */ + private static final class TimeoutRequestFactoryCustomizer { - /** - * {@link RequestFactoryCustomizer} to set the read timeout. - */ - private static class ReadTimeoutRequestFactoryCustomizer - extends TimeoutRequestFactoryCustomizer { + private final Duration timeout; - ReadTimeoutRequestFactoryCustomizer(int readTimeout) { - super(readTimeout, "setReadTimeout"); - } + private final String methodName; - } + TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) { + this.timeout = timeout; + this.methodName = methodName; + } - /** - * {@link RequestFactoryCustomizer} to set the connection timeout. - */ - private static class ConnectTimeoutRequestFactoryCustomizer - extends TimeoutRequestFactoryCustomizer { + void customize(ClientHttpRequestFactory factory) { + ReflectionUtils.invokeMethod(findMethod(factory), factory, + Math.toIntExact(this.timeout.toMillis())); + } + + private Method findMethod(ClientHttpRequestFactory factory) { + Method method = ReflectionUtils.findMethod(factory.getClass(), + this.methodName, int.class); + if (method != null) { + return method; + } + throw new IllegalStateException("Request factory " + factory.getClass() + + " does not have a " + this.methodName + "(int) method"); + } - ConnectTimeoutRequestFactoryCustomizer(int connectTimeout) { - super(connectTimeout, "setConnectTimeout"); } } From 36f3c1b883a0f3c0b8482ce680d58648cfea6b60 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 4 Jun 2018 15:53:09 +0300 Subject: [PATCH 107/701] Add duration support for setConnectTimeout and setReadTimeout See gh-13355 --- .../web/client/RestTemplateBuilderTests.java | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index cd87b9a8617e..0c8a13315f7b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.web.client; +import java.time.Duration; import java.util.Collections; import java.util.Set; import java.util.function.Supplier; @@ -60,6 +61,7 @@ * @author Stephane Nicoll * @author Phillip Webb * @author Andy Wilkinson + * @author Dmytro Nosan */ public class RestTemplateBuilderTests { @@ -390,7 +392,7 @@ public void additionalCustomizersShouldAddToExisting() { } @Test - public void customizerShouldBeAppliedInTheEnd() { + public void customizerShouldBeAppliedAtTheEnd() { ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); this.builder.interceptors(this.interceptor) @@ -439,7 +441,7 @@ public void configureShouldApply() { public void connectTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(HttpComponentsClientHttpRequestFactory.class) - .setConnectTimeout(1234).build().getRequestFactory(); + .setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(((RequestConfig) ReflectionTestUtils.getField(requestFactory, "requestConfig")).getConnectTimeout()).isEqualTo(1234); } @@ -448,7 +450,7 @@ public void connectTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() { public void readTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(HttpComponentsClientHttpRequestFactory.class) - .setReadTimeout(1234).build().getRequestFactory(); + .setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(((RequestConfig) ReflectionTestUtils.getField(requestFactory, "requestConfig")).getSocketTimeout()).isEqualTo(1234); } @@ -457,7 +459,7 @@ public void readTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() { public void connectTimeoutCanBeConfiguredOnSimpleRequestFactory() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(SimpleClientHttpRequestFactory.class) - .setConnectTimeout(1234).build().getRequestFactory(); + .setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) .isEqualTo(1234); } @@ -465,8 +467,8 @@ public void connectTimeoutCanBeConfiguredOnSimpleRequestFactory() { @Test public void readTimeoutCanBeConfiguredOnSimpleRequestFactory() { ClientHttpRequestFactory requestFactory = this.builder - .requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(1234) - .build().getRequestFactory(); + .requestFactory(SimpleClientHttpRequestFactory.class) + .setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) .isEqualTo(1234); } @@ -475,7 +477,7 @@ public void readTimeoutCanBeConfiguredOnSimpleRequestFactory() { public void connectTimeoutCanBeConfiguredOnOkHttp3RequestFactory() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(OkHttp3ClientHttpRequestFactory.class) - .setConnectTimeout(1234).build().getRequestFactory(); + .setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(ReflectionTestUtils.getField( ReflectionTestUtils.getField(requestFactory, "client"), "connectTimeout")) .isEqualTo(1234); @@ -485,7 +487,7 @@ public void connectTimeoutCanBeConfiguredOnOkHttp3RequestFactory() { public void readTimeoutCanBeConfiguredOnOkHttp3RequestFactory() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(OkHttp3ClientHttpRequestFactory.class) - .setReadTimeout(1234).build().getRequestFactory(); + .setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory(); assertThat(ReflectionTestUtils.getField( ReflectionTestUtils.getField(requestFactory, "client"), "readTimeout")) .isEqualTo(1234); @@ -497,7 +499,7 @@ public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() { this.builder .requestFactory( () -> new BufferingClientHttpRequestFactory(requestFactory)) - .setConnectTimeout(1234).build(); + .setConnectTimeout(Duration.ofMillis(1234)).build(); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) .isEqualTo(1234); } @@ -508,7 +510,7 @@ public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() { this.builder .requestFactory( () -> new BufferingClientHttpRequestFactory(requestFactory)) - .setReadTimeout(1234).build(); + .setReadTimeout(Duration.ofMillis(1234)).build(); assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) .isEqualTo(1234); } @@ -524,6 +526,46 @@ public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { .isInstanceOf(BufferingClientHttpRequestFactory.class); } + @Test + @SuppressWarnings("deprecation") + public void deprecatedReadTimeout() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(1234) + .build().getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(1234); + } + + @Test + @SuppressWarnings("deprecation") + public void deprecatedConnectTimeout() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class) + .setConnectTimeout(1234).build().getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(1234); + } + + @Test + public void readTimeoutShouldBeIgnored() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class) + .setReadTimeout(Duration.ofSeconds(5)).setReadTimeout(null).build() + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(-1); + } + + @Test + public void connectionTimeoutShouldBeIgnored() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class) + .setConnectTimeout(Duration.ofSeconds(5)).setConnectTimeout(null).build() + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(-1); + } + public static class RestTemplateSubclass extends RestTemplate { } From e9c3df4ad2a3bab74a9e75be7fbff360f5d29260 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 15:54:53 +0200 Subject: [PATCH 108/701] Polish "Add duration support for setConnectTimeout and setReadTimeout" Closes gh-13355 --- .../web/client/RestTemplateBuilderTests.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 0c8a13315f7b..25bf0974b16d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -392,7 +392,7 @@ public void additionalCustomizersShouldAddToExisting() { } @Test - public void customizerShouldBeAppliedAtTheEnd() { + public void customizerShouldBeAppliedInTheEnd() { ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); this.builder.interceptors(this.interceptor) @@ -437,6 +437,26 @@ public void configureShouldApply() { .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); } + @Test + public void connectTimeoutCanBeNullToUseDefault() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class) + .setConnectTimeout(Duration.ofSeconds(5)).setConnectTimeout(null).build() + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(-1); + } + + @Test + public void readTimeoutCanBeNullToUseDefault() { + ClientHttpRequestFactory requestFactory = this.builder + .requestFactory(SimpleClientHttpRequestFactory.class) + .setReadTimeout(Duration.ofSeconds(5)).setReadTimeout(null).build() + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(-1); + } + @Test public void connectTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() { ClientHttpRequestFactory requestFactory = this.builder @@ -528,17 +548,7 @@ public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { @Test @SuppressWarnings("deprecation") - public void deprecatedReadTimeout() { - ClientHttpRequestFactory requestFactory = this.builder - .requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(1234) - .build().getRequestFactory(); - assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) - .isEqualTo(1234); - } - - @Test - @SuppressWarnings("deprecation") - public void deprecatedConnectTimeout() { + public void connectTimeoutCanBeSetWithInteger() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(SimpleClientHttpRequestFactory.class) .setConnectTimeout(1234).build().getRequestFactory(); @@ -547,23 +557,13 @@ public void deprecatedConnectTimeout() { } @Test - public void readTimeoutShouldBeIgnored() { + @SuppressWarnings("deprecation") + public void readTimeoutCanBeSetWithInteger() { ClientHttpRequestFactory requestFactory = this.builder - .requestFactory(SimpleClientHttpRequestFactory.class) - .setReadTimeout(Duration.ofSeconds(5)).setReadTimeout(null).build() - .getRequestFactory(); + .requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(1234) + .build().getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) - .isEqualTo(-1); - } - - @Test - public void connectionTimeoutShouldBeIgnored() { - ClientHttpRequestFactory requestFactory = this.builder - .requestFactory(SimpleClientHttpRequestFactory.class) - .setConnectTimeout(Duration.ofSeconds(5)).setConnectTimeout(null).build() - .getRequestFactory(); - assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) - .isEqualTo(-1); + .isEqualTo(1234); } public static class RestTemplateSubclass extends RestTemplate { From 909722f14382881bcc5c1d32f5d37e51bbb8e2af Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 5 Jun 2018 16:02:32 +0200 Subject: [PATCH 109/701] Polish --- .../boot/web/client/RestTemplateBuilderTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 25bf0974b16d..0bef0e49cf0f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -392,7 +392,7 @@ public void additionalCustomizersShouldAddToExisting() { } @Test - public void customizerShouldBeAppliedInTheEnd() { + public void customizerShouldBeAppliedAtTheEnd() { ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); this.builder.interceptors(this.interceptor) From 5b159a6bd099ca2801223ab7840d76205a3908fa Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Tue, 5 Jun 2018 13:00:05 +0300 Subject: [PATCH 110/701] Use Duration in HttpWebServiceMessageSenderBuilder Closes gh-13364 --- .../HttpWebServiceMessageSenderBuilder.java | 24 ++++++++++--------- ...eSenderBuilderOkHttp3IntegrationTests.java | 7 ++++-- ...geSenderBuilderSimpleIntegrationTests.java | 7 ++++-- ...tpWebServiceMessageSenderBuilderTests.java | 10 +++++--- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java index 1192a9a1f688..2c97d952ba35 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java @@ -17,6 +17,7 @@ package org.springframework.boot.webservices.client; import java.lang.reflect.Method; +import java.time.Duration; import java.util.function.Supplier; import org.springframework.boot.web.client.ClientHttpRequestFactorySupplier; @@ -35,28 +36,28 @@ */ public class HttpWebServiceMessageSenderBuilder { - private Integer connectTimeout; + private Duration connectTimeout; - private Integer readTimeout; + private Duration readTimeout; private Supplier requestFactorySupplier; /** - * Set the connection timeout in milliseconds. - * @param connectTimeout the connection timeout in milliseconds + * Set the connection timeout. + * @param connectTimeout the connection timeout * @return a new builder instance */ - public HttpWebServiceMessageSenderBuilder setConnectTimeout(int connectTimeout) { + public HttpWebServiceMessageSenderBuilder setConnectTimeout(Duration connectTimeout) { this.connectTimeout = connectTimeout; return this; } /** - * Set the read timeout in milliseconds. - * @param readTimeout the read timeout in milliseconds + * Set the read timeout. + * @param readTimeout the read timeout * @return a new builder instance */ - public HttpWebServiceMessageSenderBuilder setReadTimeout(int readTimeout) { + public HttpWebServiceMessageSenderBuilder setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout; return this; } @@ -95,17 +96,18 @@ public WebServiceMessageSender build() { */ private static class TimeoutRequestFactoryCustomizer { - private final int timeout; + private final Duration timeout; private final String methodName; - TimeoutRequestFactoryCustomizer(int timeout, String methodName) { + TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) { this.timeout = timeout; this.methodName = methodName; } public void customize(ClientHttpRequestFactory factory) { - ReflectionUtils.invokeMethod(findMethod(factory), factory, this.timeout); + ReflectionUtils.invokeMethod(findMethod(factory), factory, + Math.toIntExact(this.timeout.toMillis())); } private Method findMethod(ClientHttpRequestFactory factory) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java index cfce3e23484a..6c1b93dc81bb 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.webservices.client; +import java.time.Duration; + import okhttp3.OkHttpClient; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,8 +52,9 @@ public void buildUseOkHttp3ByDefault() { @Test public void buildWithCustomTimeouts() { - WebServiceMessageSender messageSender = this.builder.setConnectTimeout(5000) - .setReadTimeout(2000).build(); + WebServiceMessageSender messageSender = this.builder + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(2)).build(); OkHttp3ClientHttpRequestFactory factory = assertOkHttp3RequestFactory( messageSender); OkHttpClient client = (OkHttpClient) ReflectionTestUtils.getField(factory, diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java index 4f3b93bfaca6..4892675c5549 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.webservices.client; +import java.time.Duration; + import org.junit.Test; import org.junit.runner.RunWith; @@ -49,8 +51,9 @@ public void buildUseUseSimpleClientByDefault() { @Test public void buildWithCustomTimeouts() { - WebServiceMessageSender messageSender = this.builder.setConnectTimeout(5000) - .setReadTimeout(2000).build(); + WebServiceMessageSender messageSender = this.builder + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(2)).build(); SimpleClientHttpRequestFactory requestFactory = assertSimpleClientRequestFactory( messageSender); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java index 82cf988dbd4b..02cffe982f65 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.webservices.client; +import java.time.Duration; + import org.apache.http.client.config.RequestConfig; import org.junit.Test; @@ -50,7 +52,8 @@ public void buildWithReadAndConnectTimeout() { ClientHttpRequestMessageSender messageSender = build( new HttpWebServiceMessageSenderBuilder() .requestFactory(SimpleClientHttpRequestFactory::new) - .setConnectTimeout(5000).setReadTimeout(2000)); + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(2))); SimpleClientHttpRequestFactory requestFactory = (SimpleClientHttpRequestFactory) messageSender .getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) @@ -62,8 +65,9 @@ public void buildWithReadAndConnectTimeout() { @Test public void buildUsesHttpComponentsByDefault() { ClientHttpRequestMessageSender messageSender = build( - new HttpWebServiceMessageSenderBuilder().setConnectTimeout(5000) - .setReadTimeout(2000)); + new HttpWebServiceMessageSenderBuilder() + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(2))); ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory(); assertThat(requestFactory) .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); From 56ab0da2872de71fddf55ef035aedd5b04b99960 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 5 Jun 2018 17:18:45 +0200 Subject: [PATCH 111/701] Support EncodedResourceResolver in resource chain As of https://jira.spring.io/browse/SPR-16381, Spring Framework now supports both gzip and Brotli as compression formats for static resources resolved by the resource chain. The `GzipResourceResolver` has been deprecated and replaced by the `EncodedResourceResolver`. This commit uses this new resolver and adapts the configuration key to reflect those changes. Note that this resolver is now configured ahead of the `VersionResourceResolver`. Closes gh-13242 --- .../boot/autoconfigure/web/ResourceProperties.java | 14 +++++++------- .../web/reactive/WebFluxAutoConfiguration.java | 8 ++++---- .../web/servlet/WebMvcAutoConfiguration.java | 8 ++++---- .../additional-spring-configuration-metadata.json | 9 +++++++++ .../web/servlet/WebMvcAutoConfigurationTests.java | 10 +++++----- .../asciidoc/appendix-application-properties.adoc | 2 +- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java index 30f0aff9198e..491b1ffdc9e0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java @@ -112,10 +112,10 @@ public static class Chain { private boolean htmlApplicationCache = false; /** - * Whether to enable resolution of already gzipped resources. Checks for a - * resource name variant with the "*.gz" extension. + * Whether to enable resolution of already compressed resources. Checks for a + * resource name with the '.gz' or '.br' file extensions. */ - private boolean gzipped = false; + private boolean compressed = false; private final Strategy strategy = new Strategy(); @@ -154,12 +154,12 @@ public void setHtmlApplicationCache(boolean htmlApplicationCache) { this.htmlApplicationCache = htmlApplicationCache; } - public boolean isGzipped() { - return this.gzipped; + public boolean isCompressed() { + return this.compressed; } - public void setGzipped(boolean gzipped) { - this.gzipped = gzipped; + public void setCompressed(boolean compressed) { + this.compressed = compressed; } static Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 351b08f79eea..3033c98a92cc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -64,7 +64,7 @@ import org.springframework.web.reactive.config.WebFluxConfigurationSupport; import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.resource.AppCacheManifestTransformer; -import org.springframework.web.reactive.resource.GzipResourceResolver; +import org.springframework.web.reactive.resource.EncodedResourceResolver; import org.springframework.web.reactive.resource.ResourceResolver; import org.springframework.web.reactive.resource.VersionResourceResolver; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; @@ -275,12 +275,12 @@ public void customize(ResourceHandlerRegistration registration) { private void configureResourceChain(ResourceProperties.Chain properties, ResourceChainRegistration chain) { ResourceProperties.Strategy strategy = properties.getStrategy(); + if (properties.isCompressed()) { + chain.addResolver(new EncodedResourceResolver()); + } if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) { chain.addResolver(getVersionResourceResolver(strategy)); } - if (properties.isGzipped()) { - chain.addResolver(new GzipResourceResolver()); - } if (properties.isHtmlApplicationCache()) { chain.addTransformer(new AppCacheManifestTransformer()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 4299cd148a82..e7672233ab41 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -115,7 +115,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.resource.AppCacheManifestTransformer; -import org.springframework.web.servlet.resource.GzipResourceResolver; +import org.springframework.web.servlet.resource.EncodedResourceResolver; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.servlet.resource.ResourceResolver; import org.springframework.web.servlet.resource.VersionResourceResolver; @@ -602,12 +602,12 @@ public void customize(ResourceHandlerRegistration registration) { private void configureResourceChain(ResourceProperties.Chain properties, ResourceChainRegistration chain) { Strategy strategy = properties.getStrategy(); + if (properties.isCompressed()) { + chain.addResolver(new EncodedResourceResolver()); + } if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) { chain.addResolver(getVersionResourceResolver(strategy)); } - if (properties.isGzipped()) { - chain.addResolver(new GzipResourceResolver()); - } if (properties.isHtmlApplicationCache()) { chain.addTransformer(new AppCacheManifestTransformer()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index dafabc25def5..b0f2e0fe1ffc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -455,6 +455,15 @@ "name": "spring.mvc.locale-resolver", "defaultValue": "accept-header" }, + { + "name" : "spring.resources.chain.gzipped", + "type" : "java.lang.Boolean", + "description" : "Whether to enable resolution of already gzipped resources. Checks for a resource name variant with the \"*.gz\" extension.", + "deprecation" : { + "replacement" : "spring.resources.chain.compressed", + "level" : "error" + } + }, { "name": "spring.quartz.jdbc.initialize-schema", "defaultValue": "embedded" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index d1e30f4fb0c4..986fedc20a56 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -90,8 +90,8 @@ import org.springframework.web.servlet.resource.CachingResourceTransformer; import org.springframework.web.servlet.resource.ContentVersionStrategy; import org.springframework.web.servlet.resource.CssLinkResourceTransformer; +import org.springframework.web.servlet.resource.EncodedResourceResolver; import org.springframework.web.servlet.resource.FixedVersionStrategy; -import org.springframework.web.servlet.resource.GzipResourceResolver; import org.springframework.web.servlet.resource.PathResourceResolver; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.servlet.resource.ResourceResolver; @@ -276,21 +276,21 @@ public void resourceHandlerChainCustomized() { "spring.resources.chain.strategy.fixed.version:test", "spring.resources.chain.strategy.fixed.paths:/**/*.js", "spring.resources.chain.html-application-cache:true", - "spring.resources.chain.gzipped:true").run((context) -> { + "spring.resources.chain.compressed:true").run((context) -> { assertThat(getResourceResolvers(context, "/webjars/**")).hasSize(3); assertThat(getResourceTransformers(context, "/webjars/**")) .hasSize(2); assertThat(getResourceResolvers(context, "/**")) .extractingResultOf("getClass") - .containsOnly(VersionResourceResolver.class, - GzipResourceResolver.class, + .containsOnly(EncodedResourceResolver.class, + VersionResourceResolver.class, PathResourceResolver.class); assertThat(getResourceTransformers(context, "/**")) .extractingResultOf("getClass") .containsOnly(CssLinkResourceTransformer.class, AppCacheManifestTransformer.class); VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers( - context, "/**").get(0); + context, "/**").get(1); Map strategyMap = resolver.getStrategyMap(); assertThat(strategyMap.get("/*.png")) .isInstanceOf(ContentVersionStrategy.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index d01e0a67318c..b44fee4a1293 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -435,8 +435,8 @@ content into your application. Rather, pick only the properties that you need. spring.resources.cache.cachecontrol.stale-while-revalidate= # Maximum time the response can be served after it becomes stale, in seconds if no duration suffix is not specified. spring.resources.cache.period= # Cache period for the resources served by the resource handler. If a duration suffix is not specified, seconds will be used. spring.resources.chain.cache=true # Whether to enable caching in the Resource chain. + spring.resources.chain.compressed=false # Whether to enable resolution of already compressed resources (gzip, brotli). spring.resources.chain.enabled= # Whether to enable the Spring Resource Handling chain. By default, disabled unless at least one strategy has been enabled. - spring.resources.chain.gzipped=false # Whether to enable resolution of already gzipped resources. spring.resources.chain.html-application-cache=false # Whether to enable HTML5 application cache manifest rewriting. spring.resources.chain.strategy.content.enabled=false # Whether to enable the content Version Strategy. spring.resources.chain.strategy.content.paths=/** # Comma-separated list of patterns to apply to the content Version Strategy. From 66be6c3396fb572cb8a6678f97ae2f6d60cdb642 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 5 Jun 2018 17:44:51 -0700 Subject: [PATCH 112/701] Polish --- .../ReactiveCloudFoundrySecurityService.java | 12 ++++++++---- .../jackson/JacksonAutoConfigurationTests.java | 1 + .../boot/web/client/RestTemplateBuilderTests.java | 1 - 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java index 269d1a27a187..49d2b38d8fac 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; +import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import reactor.core.publisher.Mono; @@ -65,13 +66,16 @@ class ReactiveCloudFoundrySecurityService { } protected ReactorClientHttpConnector buildTrustAllSslConnector() { - HttpClient client = HttpClient.create() - .secure((sslContextSpec) -> sslContextSpec.forClient() - .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE))); + HttpClient client = HttpClient.create().secure((sslContextSpec) -> sslContextSpec + .forClient().sslContext(this::configureSsl)); return new ReactorClientHttpConnector(client); } + private SslContextBuilder configureSsl(SslContextBuilder builder) { + return builder.sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE); + } + /** * Return a Mono of the access level that should be granted to the given token. * @param token the token diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index 4e9e90e4787f..3c4a2803fcdb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -626,6 +626,7 @@ Set getOwners() { } + @SuppressWarnings("unused") private static class VisibilityBean { private String property1; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 0bef0e49cf0f..7972841fa219 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -414,7 +414,6 @@ public void customizerShouldBeAppliedAtTheEnd() { assertThat(ReflectionTestUtils.getField(actualRequestFactory, "requestFactory")).isSameAs(requestFactory); }).build(); - } @Test From e0ae805924e1e7415c7be18924e48b325ab80191 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 5 Jun 2018 17:45:09 -0700 Subject: [PATCH 113/701] Update copyright header --- .../autoconfigure/elasticsearch/jest/JestAutoConfiguration.java | 2 +- .../OAuth2ClientRegistrationRepositoryConfiguration.java | 2 +- .../oauth2/client/servlet/OAuth2WebSecurityConfiguration.java | 2 +- .../OAuth2ClientRegistrationRepositoryConfigurationTests.java | 2 +- .../web/reactive/HttpHandlerAutoConfigurationTests.java | 2 +- .../web/servlet/error/RemappedErrorViewIntegrationTests.java | 2 +- .../springframework/boot/loader/jar/JarURLConnectionTests.java | 2 +- .../src/main/java/org/test/SampleApplication.java | 2 +- .../src/main/java/org/test/SampleApplication.java | 2 +- .../actuator/ServletPathSampleActuatorApplicationTests.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java index 3c1a23ebd485..02fa06ca9081 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java index 8be5b23eb6ca..5323a944e917 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index 953c41262cdb..8ece42f6437e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java index 039f4c476b55..dcea65025c52 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java index bbd370f89feb..28e4614b4da2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java index 89b1176eb8bc..6dd62658dc30 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/RemappedErrorViewIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarURLConnectionTests.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarURLConnectionTests.java index f98b5d43be0f..65f0261c8dad 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarURLConnectionTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarURLConnectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java index 8a5b6691293a..24689463ea65 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-main/src/main/java/org/test/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java index e8784d4593d1..24689463ea65 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/it/jar-classifier-source/src/main/java/org/test/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2018 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-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java index 9fa9d8ba9208..a2d2647fa604 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ServletPathSampleActuatorApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. From ab19db19a3d05e3135a1d38cb3a3680351b5d427 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 6 Jun 2018 11:47:22 +0200 Subject: [PATCH 114/701] Move Hibernate settings to a dedicated class Closes gh-1327 --- .../jpa/DataSourceInitializedPublisher.java | 16 +- .../orm/jpa/HibernateJpaConfiguration.java | 13 +- .../orm/jpa/HibernateProperties.java | 183 ++++++++++++++++++ .../autoconfigure/orm/jpa/JpaProperties.java | 158 --------------- ...tomHibernateJpaAutoConfigurationTests.java | 12 +- .../orm/jpa/HibernatePropertiesTests.java | 167 ++++++++++++++++ .../orm/jpa/JpaPropertiesTests.java | 117 ----------- 7 files changed, 378 insertions(+), 288 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java index b880a816a2e0..fdfc2815f8bf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java @@ -48,7 +48,9 @@ class DataSourceInitializedPublisher implements BeanPostProcessor { private DataSource dataSource; - private JpaProperties properties; + private JpaProperties jpaProperties; + + private HibernateProperties hibernateProperties; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) @@ -64,7 +66,10 @@ public Object postProcessAfterInitialization(Object bean, String beanName) this.dataSource = (DataSource) bean; } if (bean instanceof JpaProperties) { - this.properties = (JpaProperties) bean; + this.jpaProperties = (JpaProperties) bean; + } + if (bean instanceof HibernateProperties) { + this.hibernateProperties = (HibernateProperties) bean; } if (bean instanceof EntityManagerFactory) { publishEventIfRequired((EntityManagerFactory) bean); @@ -88,13 +93,14 @@ private DataSource findDataSource(EntityManagerFactory entityManagerFactory) { } private boolean isInitializingDatabase(DataSource dataSource) { - if (this.properties == null) { + if (this.jpaProperties == null || this.hibernateProperties == null) { return true; // better safe than sorry } Supplier defaultDdlAuto = () -> (EmbeddedDatabaseConnection .isEmbedded(dataSource) ? "create-drop" : "none"); - Map hibernate = this.properties - .getHibernateProperties(new HibernateSettings().ddlAuto(defaultDdlAuto)); + Map hibernate = this.hibernateProperties + .determineHibernateProperties(this.jpaProperties.getProperties(), + new HibernateSettings().ddlAuto(defaultDdlAuto)); if (hibernate.containsKey("hibernate.hbm2ddl.auto")) { return true; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 6273a398322a..5141bbf60970 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.SchemaManagementProvider; import org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider; import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata; @@ -57,6 +58,7 @@ * @since 2.0.0 */ @Configuration +@EnableConfigurationProperties(HibernateProperties.class) @ConditionalOnSingleCandidate(DataSource.class) class HibernateJpaConfiguration extends JpaBaseConfiguration { @@ -81,6 +83,8 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { "org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform", "org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform" }; + private final HibernateProperties hibernateProperties; + private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider; private DataSourcePoolMetadataProvider poolMetadataProvider; @@ -90,6 +94,7 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { HibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties, ObjectProvider jtaTransactionManager, ObjectProvider transactionManagerCustomizers, + HibernateProperties hibernateProperties, ObjectProvider> metadataProviders, ObjectProvider> providers, ObjectProvider physicalNamingStrategy, @@ -97,6 +102,7 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { ObjectProvider> hibernatePropertiesCustomizers) { super(dataSource, jpaProperties, jtaTransactionManager, transactionManagerCustomizers); + this.hibernateProperties = hibernateProperties; this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider( providers.getIfAvailable(Collections::emptyList)); this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider( @@ -130,9 +136,10 @@ protected AbstractJpaVendorAdapter createJpaVendorAdapter() { protected Map getVendorProperties() { Supplier defaultDdlMode = () -> this.defaultDdlAutoProvider .getDefaultDdlAuto(getDataSource()); - return new LinkedHashMap<>( - getProperties().getHibernateProperties(new HibernateSettings() - .ddlAuto(defaultDdlMode).hibernatePropertiesCustomizers( + return new LinkedHashMap<>(this.hibernateProperties.determineHibernateProperties( + getProperties().getProperties(), + new HibernateSettings().ddlAuto(defaultDdlMode) + .hibernatePropertiesCustomizers( this.hibernatePropertiesCustomizers))); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java new file mode 100644 index 000000000000..25fb54a7ee2c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -0,0 +1,183 @@ +/* + * Copyright 2012-2018 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.autoconfigure.orm.jpa; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * Configuration properties for Hibernate. + * + * @author Stephane Nicoll + * @since 2.1.0 + * @see JpaProperties + */ +@ConfigurationProperties("spring.jpa.hibernate") +public class HibernateProperties { + + private static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id." + + "new_generator_mappings"; + + private final Naming naming = new Naming(); + + /** + * DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property. + * Defaults to "create-drop" when using an embedded database and no schema manager was + * detected. Otherwise, defaults to "none". + */ + private String ddlAuto; + + /** + * Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. + * This is actually a shortcut for the "hibernate.id.new_generator_mappings" property. + * When not specified will default to "true". + */ + private Boolean useNewIdGeneratorMappings; + + public String getDdlAuto() { + return this.ddlAuto; + } + + public void setDdlAuto(String ddlAuto) { + this.ddlAuto = ddlAuto; + } + + public Boolean isUseNewIdGeneratorMappings() { + return this.useNewIdGeneratorMappings; + } + + public void setUseNewIdGeneratorMappings(Boolean useNewIdGeneratorMappings) { + this.useNewIdGeneratorMappings = useNewIdGeneratorMappings; + } + + public Naming getNaming() { + return this.naming; + } + + /** + * Determine the configuration properties for the initialization of the main Hibernate + * EntityManagerFactory based on standard JPA properties and + * {@link HibernateSettings}. + * @param jpaProperties standard jpa properties + * @param settings the settings to apply when determining the configuration properties + * @return the Hibernate properties to use + */ + public Map determineHibernateProperties( + Map jpaProperties, HibernateSettings settings) { + Assert.notNull(jpaProperties, "JpaProperties must not be null"); + Assert.notNull(settings, "Settings must not be null"); + return getAdditionalProperties(jpaProperties, settings); + } + + private Map getAdditionalProperties(Map existing, + HibernateSettings settings) { + Map result = new HashMap<>(existing); + applyNewIdGeneratorMappings(result); + getNaming().applyNamingStrategies(result); + String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto); + if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) { + result.put("hibernate.hbm2ddl.auto", ddlAuto); + } + else { + result.remove("hibernate.hbm2ddl.auto"); + } + Collection customizers = settings + .getHibernatePropertiesCustomizers(); + if (!ObjectUtils.isEmpty(customizers)) { + customizers.forEach((customizer) -> customizer.customize(result)); + } + return result; + } + + private void applyNewIdGeneratorMappings(Map result) { + if (this.useNewIdGeneratorMappings != null) { + result.put(USE_NEW_ID_GENERATOR_MAPPINGS, + this.useNewIdGeneratorMappings.toString()); + } + else if (!result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) { + result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "true"); + } + } + + private String determineDdlAuto(Map existing, + Supplier defaultDdlAuto) { + String ddlAuto = existing.get("hibernate.hbm2ddl.auto"); + if (ddlAuto != null) { + return ddlAuto; + } + return (this.ddlAuto != null ? this.ddlAuto : defaultDdlAuto.get()); + } + + public static class Naming { + + private static final String DEFAULT_PHYSICAL_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"; + + private static final String DEFAULT_IMPLICIT_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"; + + /** + * Fully qualified name of the implicit naming strategy. + */ + private String implicitStrategy; + + /** + * Fully qualified name of the physical naming strategy. + */ + private String physicalStrategy; + + public String getImplicitStrategy() { + return this.implicitStrategy; + } + + public void setImplicitStrategy(String implicitStrategy) { + this.implicitStrategy = implicitStrategy; + } + + public String getPhysicalStrategy() { + return this.physicalStrategy; + } + + public void setPhysicalStrategy(String physicalStrategy) { + this.physicalStrategy = physicalStrategy; + } + + private void applyNamingStrategies(Map properties) { + applyNamingStrategy(properties, "hibernate.implicit_naming_strategy", + this.implicitStrategy, DEFAULT_IMPLICIT_STRATEGY); + applyNamingStrategy(properties, "hibernate.physical_naming_strategy", + this.physicalStrategy, DEFAULT_PHYSICAL_STRATEGY); + } + + private void applyNamingStrategy(Map properties, String key, + Object strategy, Object defaultStrategy) { + if (strategy != null) { + properties.put(key, strategy); + } + else if (defaultStrategy != null && !properties.containsKey(key)) { + properties.put(key, defaultStrategy); + } + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java index 3587f9b05572..e4ece17f1655 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java @@ -17,18 +17,14 @@ package org.springframework.boot.autoconfigure.orm.jpa; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import javax.sql.DataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.orm.jpa.vendor.Database; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** * External configuration properties for a JPA EntityManagerFactory created by Spring. @@ -81,8 +77,6 @@ public class JpaProperties { */ private Boolean openInView; - private Hibernate hibernate = new Hibernate(); - public Map getProperties() { return this.properties; } @@ -135,24 +129,6 @@ public void setOpenInView(Boolean openInView) { this.openInView = openInView; } - public Hibernate getHibernate() { - return this.hibernate; - } - - public void setHibernate(Hibernate hibernate) { - this.hibernate = hibernate; - } - - /** - * Get configuration properties for the initialization of the main Hibernate - * EntityManagerFactory. - * @param settings the settings to apply when determining the configuration properties - * @return some Hibernate properties for configuration - */ - public Map getHibernateProperties(HibernateSettings settings) { - return this.hibernate.getAdditionalProperties(this.properties, settings); - } - /** * Determine the {@link Database} to use based on this configuration and the primary * {@link DataSource}. @@ -166,138 +142,4 @@ public Database determineDatabase(DataSource dataSource) { return DatabaseLookup.getDatabase(dataSource); } - public static class Hibernate { - - private static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id." - + "new_generator_mappings"; - - /** - * DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" - * property. Defaults to "create-drop" when using an embedded database and no - * schema manager was detected. Otherwise, defaults to "none". - */ - private String ddlAuto; - - /** - * Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and - * SEQUENCE. This is actually a shortcut for the - * "hibernate.id.new_generator_mappings" property. When not specified will default - * to "true". - */ - private Boolean useNewIdGeneratorMappings; - - private final Naming naming = new Naming(); - - public String getDdlAuto() { - return this.ddlAuto; - } - - public void setDdlAuto(String ddlAuto) { - this.ddlAuto = ddlAuto; - } - - public Boolean isUseNewIdGeneratorMappings() { - return this.useNewIdGeneratorMappings; - } - - public void setUseNewIdGeneratorMappings(Boolean useNewIdGeneratorMappings) { - this.useNewIdGeneratorMappings = useNewIdGeneratorMappings; - } - - public Naming getNaming() { - return this.naming; - } - - private Map getAdditionalProperties(Map existing, - HibernateSettings settings) { - Map result = new HashMap<>(existing); - applyNewIdGeneratorMappings(result); - getNaming().applyNamingStrategies(result); - String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto); - if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) { - result.put("hibernate.hbm2ddl.auto", ddlAuto); - } - else { - result.remove("hibernate.hbm2ddl.auto"); - } - Collection customizers = settings - .getHibernatePropertiesCustomizers(); - if (!ObjectUtils.isEmpty(customizers)) { - customizers.forEach((customizer) -> customizer.customize(result)); - } - return result; - } - - private void applyNewIdGeneratorMappings(Map result) { - if (this.useNewIdGeneratorMappings != null) { - result.put(USE_NEW_ID_GENERATOR_MAPPINGS, - this.useNewIdGeneratorMappings.toString()); - } - else if (!result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) { - result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "true"); - } - } - - private String determineDdlAuto(Map existing, - Supplier defaultDdlAuto) { - String ddlAuto = existing.get("hibernate.hbm2ddl.auto"); - if (ddlAuto != null) { - return ddlAuto; - } - return (this.ddlAuto != null ? this.ddlAuto : defaultDdlAuto.get()); - } - - } - - public static class Naming { - - private static final String DEFAULT_PHYSICAL_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"; - - private static final String DEFAULT_IMPLICIT_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"; - - /** - * Fully qualified name of the implicit naming strategy. - */ - private String implicitStrategy; - - /** - * Fully qualified name of the physical naming strategy. - */ - private String physicalStrategy; - - public String getImplicitStrategy() { - return this.implicitStrategy; - } - - public void setImplicitStrategy(String implicitStrategy) { - this.implicitStrategy = implicitStrategy; - } - - public String getPhysicalStrategy() { - return this.physicalStrategy; - } - - public void setPhysicalStrategy(String physicalStrategy) { - this.physicalStrategy = physicalStrategy; - } - - private void applyNamingStrategies(Map properties) { - applyNamingStrategy(properties, "hibernate.implicit_naming_strategy", - this.implicitStrategy, DEFAULT_IMPLICIT_STRATEGY); - applyNamingStrategy(properties, "hibernate.physical_naming_strategy", - this.physicalStrategy, DEFAULT_PHYSICAL_STRATEGY); - } - - private void applyNamingStrategy(Map properties, String key, - Object strategy, Object defaultStrategy) { - if (strategy != null) { - properties.put(key, strategy); - } - else if (defaultStrategy != null && !properties.containsKey(key)) { - properties.put(key, defaultStrategy); - } - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java index c4314c12d71a..bb65355b3006 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/CustomHibernateJpaAutoConfigurationTests.java @@ -67,11 +67,13 @@ public void namingStrategyDelegatorTakesPrecedence() { "spring.jpa.properties.hibernate.ejb.naming_strategy_delegator:" + "org.hibernate.cfg.naming.ImprovedNamingStrategyDelegator") .run((context) -> { - JpaProperties bean = context.getBean(JpaProperties.class); - Map hibernateProperties = bean - .getHibernateProperties(new HibernateSettings()); - assertThat(hibernateProperties.get("hibernate.ejb.naming_strategy")) - .isNull(); + JpaProperties jpaProperties = context.getBean(JpaProperties.class); + HibernateProperties hibernateProperties = context + .getBean(HibernateProperties.class); + Map properties = hibernateProperties + .determineHibernateProperties(jpaProperties.getProperties(), + new HibernateSettings()); + assertThat(properties.get("hibernate.ejb.naming_strategy")).isNull(); }); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java new file mode 100644 index 000000000000..3a3ee40e1cb8 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -0,0 +1,167 @@ +/* + * Copyright 2012-2018 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.autoconfigure.orm.jpa; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.hibernate.cfg.AvailableSettings; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; +import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link HibernateProperties}. + * + * @author Stephane Nicoll + */ +public class HibernatePropertiesTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(TestConfiguration.class); + + @Mock + private Supplier ddlAutoSupplier; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void noCustomNamingStrategy() { + this.contextRunner.run(assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties) + .doesNotContainKeys("hibernate.ejb.naming_strategy"); + assertThat(hibernateProperties).containsEntry( + "hibernate.physical_naming_strategy", + SpringPhysicalNamingStrategy.class.getName()); + assertThat(hibernateProperties).containsEntry( + "hibernate.implicit_naming_strategy", + SpringImplicitNamingStrategy.class.getName()); + })); + } + + @Test + public void hibernate5CustomNamingStrategies() { + this.contextRunner.withPropertyValues( + "spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit", + "spring.jpa.hibernate.naming.physical-strategy:com.example.Physical") + .run(assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties).contains( + entry("hibernate.implicit_naming_strategy", + "com.example.Implicit"), + entry("hibernate.physical_naming_strategy", + "com.example.Physical")); + assertThat(hibernateProperties) + .doesNotContainKeys("hibernate.ejb.naming_strategy"); + })); + } + + @Test + public void hibernate5CustomNamingStrategiesViaJpaProperties() { + this.contextRunner.withPropertyValues( + "spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit", + "spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical") + .run(assertHibernateProperties((hibernateProperties) -> { + // You can override them as we don't provide any default + assertThat(hibernateProperties).contains( + entry("hibernate.implicit_naming_strategy", + "com.example.Implicit"), + entry("hibernate.physical_naming_strategy", + "com.example.Physical")); + assertThat(hibernateProperties) + .doesNotContainKeys("hibernate.ejb.naming_strategy"); + })); + } + + @Test + public void useNewIdGeneratorMappingsDefault() { + this.contextRunner.run(assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties).containsEntry( + AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true"); + })); + } + + @Test + public void useNewIdGeneratorMappingsFalse() { + this.contextRunner + .withPropertyValues( + "spring.jpa.hibernate.use-new-id-generator-mappings:false") + .run(assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties).containsEntry( + AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false"); + })); + } + + @Test + public void defaultDdlAutoIsNotInvokedIfPropertyIsSet() { + this.contextRunner.withPropertyValues("spring.jpa.hibernate.ddl-auto=validate") + .run(assertDefaultDdlAutoNotInvoked("validate")); + } + + @Test + public void defaultDdlAutoIsNotInvokedIfHibernateSpecificPropertyIsSet() { + this.contextRunner + .withPropertyValues("spring.jpa.properties.hibernate.hbm2ddl.auto=create") + .run(assertDefaultDdlAutoNotInvoked("create")); + } + + private ContextConsumer assertDefaultDdlAutoNotInvoked( + String expectedDdlAuto) { + return assertHibernateProperties((hibernateProperties) -> { + assertThat(hibernateProperties).containsEntry("hibernate.hbm2ddl.auto", + expectedDdlAuto); + verify(this.ddlAutoSupplier, never()).get(); + }); + } + + private ContextConsumer assertHibernateProperties( + Consumer> consumer) { + return (context) -> { + assertThat(context).hasSingleBean(JpaProperties.class); + assertThat(context).hasSingleBean(HibernateProperties.class); + Map hibernateProperties = context + .getBean(HibernateProperties.class).determineHibernateProperties( + context.getBean(JpaProperties.class).getProperties(), + new HibernateSettings().ddlAuto(this.ddlAutoSupplier)); + consumer.accept(hibernateProperties); + }; + } + + @Configuration + @EnableConfigurationProperties({ JpaProperties.class, HibernateProperties.class }) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/JpaPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/JpaPropertiesTests.java index a3aedabd53b2..2932e3892831 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/JpaPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/JpaPropertiesTests.java @@ -19,21 +19,13 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.util.Map; import java.util.function.Consumer; -import java.util.function.Supplier; import javax.sql.DataSource; -import org.hibernate.cfg.AvailableSettings; -import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; -import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; @@ -41,7 +33,6 @@ import org.springframework.orm.jpa.vendor.Database; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -57,90 +48,6 @@ public class JpaPropertiesTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(TestConfiguration.class); - @Mock - private Supplier ddlAutoSupplier; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void noCustomNamingStrategy() { - this.contextRunner.run(assertJpaProperties((properties) -> { - Map hibernateProperties = properties - .getHibernateProperties(new HibernateSettings()); - assertThat(hibernateProperties) - .doesNotContainKeys("hibernate.ejb.naming_strategy"); - assertThat(hibernateProperties).containsEntry( - "hibernate.physical_naming_strategy", - SpringPhysicalNamingStrategy.class.getName()); - assertThat(hibernateProperties).containsEntry( - "hibernate.implicit_naming_strategy", - SpringImplicitNamingStrategy.class.getName()); - })); - } - - @Test - public void hibernate5CustomNamingStrategies() { - this.contextRunner.withPropertyValues( - "spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit", - "spring.jpa.hibernate.naming.physical-strategy:com.example.Physical") - .run(assertJpaProperties((properties) -> { - Map hibernateProperties = properties - .getHibernateProperties(new HibernateSettings()); - assertThat(hibernateProperties).contains( - entry("hibernate.implicit_naming_strategy", - "com.example.Implicit"), - entry("hibernate.physical_naming_strategy", - "com.example.Physical")); - assertThat(hibernateProperties) - .doesNotContainKeys("hibernate.ejb.naming_strategy"); - })); - } - - @Test - public void hibernate5CustomNamingStrategiesViaJpaProperties() { - this.contextRunner.withPropertyValues( - "spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit", - "spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical") - .run(assertJpaProperties((properties) -> { - Map hibernateProperties = properties - .getHibernateProperties(new HibernateSettings()); - // You can override them as we don't provide any default - assertThat(hibernateProperties).contains( - entry("hibernate.implicit_naming_strategy", - "com.example.Implicit"), - entry("hibernate.physical_naming_strategy", - "com.example.Physical")); - assertThat(hibernateProperties) - .doesNotContainKeys("hibernate.ejb.naming_strategy"); - })); - } - - @Test - public void useNewIdGeneratorMappingsDefault() { - this.contextRunner.run(assertJpaProperties((properties) -> { - Map hibernateProperties = properties - .getHibernateProperties(new HibernateSettings()); - assertThat(hibernateProperties).containsEntry( - AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true"); - })); - } - - @Test - public void useNewIdGeneratorMappingsFalse() { - this.contextRunner - .withPropertyValues( - "spring.jpa.hibernate.use-new-id-generator-mappings:false") - .run(assertJpaProperties((properties) -> { - Map hibernateProperties = properties - .getHibernateProperties(new HibernateSettings()); - assertThat(hibernateProperties).containsEntry( - AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false"); - })); - } - @Test public void determineDatabaseNoCheckIfDatabaseIsSet() { this.contextRunner.withPropertyValues("spring.jpa.database=postgresql") @@ -176,30 +83,6 @@ public void determineDatabaseWithKnownUrlAndUserConfig() { })); } - @Test - public void defaultDdlAutoIsNotInvokedIfPropertyIsSet() { - this.contextRunner.withPropertyValues("spring.jpa.hibernate.ddl-auto=validate") - .run(assertDefaultDdlAutoNotInvoked("validate")); - } - - @Test - public void defaultDdlAutoIsNotInvokedIfHibernateSpecificPropertyIsSet() { - this.contextRunner - .withPropertyValues("spring.jpa.properties.hibernate.hbm2ddl.auto=create") - .run(assertDefaultDdlAutoNotInvoked("create")); - } - - private ContextConsumer assertDefaultDdlAutoNotInvoked( - String expectedDdlAuto) { - return assertJpaProperties((properties) -> { - Map hibernateProperties = properties.getHibernateProperties( - new HibernateSettings().ddlAuto(this.ddlAutoSupplier)); - assertThat(hibernateProperties).containsEntry("hibernate.hbm2ddl.auto", - expectedDdlAuto); - verify(this.ddlAutoSupplier, never()).get(); - }); - } - @Test public void determineDatabaseWithUnknownUrl() { this.contextRunner.run(assertJpaProperties((properties) -> { From 0004550f7b7aa05f297a6c03d9c29426b295ffbb Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 6 Jun 2018 17:32:24 +0200 Subject: [PATCH 115/701] Document Reactor Netty server configuration This commit regroups the documentation on how to configure a web server in Spring Boot. The same concepts apply, whether the server is Tomcat/Netty/Jetty/Undertow, or if it's deployed for a Servlet or Reactive web application. Closes gh-13315 --- .../src/main/asciidoc/howto.adoc | 277 +++++++++--------- 1 file changed, 144 insertions(+), 133 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 2942966a6630..b9cd1126724b 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -576,87 +576,6 @@ your `application.properties`, as shown in the following example: -[[howto-configure-jetty]] -=== Configure Jetty -Generally, you can follow the advice from -"`<>`" about -`@ConfigurationProperties` (`ServerProperties` is the main one here). However, you should -also look at -{dc-spring-boot}/web/server/WebServerFactoryCustomizer.html[`WebServerFactoryCustomizer`]. -The Jetty APIs are quite rich, so, once you have access to the -`JettyServletWebServerFactory`, you can modify it in a number of ways. Alternatively, if -you need more control and customization, you can add your own -`JettyServletWebServerFactory`. - - - -[[howto-add-a-servlet-filter-or-listener]] -=== Add a Servlet, Filter, or Listener to an Application -There are two ways to add `Servlet`, `Filter`, `ServletContextListener`, and the other -listeners supported by the Servlet spec to your application: - -* <> -* <> - - - -[[howto-add-a-servlet-filter-or-listener-as-spring-bean]] -==== Add a Servlet, Filter, or Listener by Using a Spring Bean -To add a `Servlet`, `Filter`, or Servlet `*Listener` by using a Spring bean, you must -provide a `@Bean` definition for it. Doing so can be very useful when you want to inject -configuration or dependencies. However, you must be very careful that they do not cause -eager initialization of too many other beans, because they have to be installed in the -container very early in the application lifecycle. (For example, it is not a good idea to -have them depend on your `DataSource` or JPA configuration.) You can work around such -restrictions by initializing the beans lazily when first used instead of on -initialization. - -In the case of `Filters` and `Servlets`, you can also add mappings and init parameters by -adding a `FilterRegistrationBean` or a `ServletRegistrationBean` instead of or in -addition to the underlying component. - -[NOTE] -==== -If no `dispatcherType` is specified on a filter registration, `REQUEST` is used. This -aligns with the Servlet Specification's default dispatcher type. -==== - -Like any other Spring bean, you can define the order of Servlet filter beans; please -make sure to check the -"`<>`" -section. - - - -[[howto-disable-registration-of-a-servlet-or-filter]] -===== Disable Registration of a Servlet or Filter -As <>, any -`Servlet` or `Filter` beans are registered with the servlet container automatically. To -disable registration of a particular `Filter` or `Servlet` bean, create a registration -bean for it and mark it as disabled, as shown in the following example: - -[source,java,indent=0,subs="verbatim,quotes,attributes"] ----- - @Bean - public FilterRegistrationBean registration(MyFilter filter) { - FilterRegistrationBean registration = new FilterRegistrationBean(filter); - registration.setEnabled(false); - return registration; - } ----- - - - -[[howto-add-a-servlet-filter-or-listener-using-scanning]] -==== Add Servlets, Filters, and Listeners by Using Classpath Scanning -`@WebServlet`, `@WebFilter`, and `@WebListener` annotated classes can be automatically -registered with an embedded servlet container by annotating a `@Configuration` class -with `@ServletComponentScan` and specifying the package(s) containing the components -that you want to register. By default, `@ServletComponentScan` scans from the package -of the annotated class. - - - [[howto-change-the-http-port]] === Change the HTTP Port In a standalone application, the main HTTP port defaults to `8080` but can be set with @@ -720,6 +639,32 @@ processed early (before the value is actually available). +[[how-to-enable-http-response-compression]] +=== Enable HTTP Response Compression +HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabled +in `application.properties`, as follows: + +[source,properties,indent=0,subs="verbatim,quotes,attributes"] +---- + server.compression.enabled=true +---- + +By default, responses must be at least 2048 bytes in length for compression to be +performed. You can configure this behavior by setting the +`server.compression.min-response-size` property. + +By default, responses are compressed only if their content type is one of the +following: + +* `text/html` +* `text/xml` +* `text/plain` +* `text/css` + +You can configure this behavior by setting the `server.compression.mime-types` property. + + + [[howto-configure-ssl]] === Configure SSL SSL can be configured declaratively by setting the various `+server.ssl.*+` properties, @@ -804,6 +749,124 @@ the version of your choice. +[[howto-configure-webserver]] +=== Configure the Web Server + +Generally, you should first consider using one of the many available configuration keys +and customize your web server by adding new entries in your `application.properties` (or +`application.yml`, or environment, etc. see +"`<>`"). The `server.{asterisk}` +namespace is quite useful here, and it includes namespaces like `server.tomcat.{asterisk}`, +`server.jetty.{asterisk}` and others, for server-specific features. +See the list of <>. + +The previous sections covered already many common use cases, such as compression, SSL +or HTTP/2. However, if a configuration key doesn't exist for your use case, you should +then look at +{dc-spring-boot}/web/server/WebServerFactoryCustomizer.html[`WebServerFactoryCustomizer`]. +You can declare such a component and get access to the server factory relevant to your +choice: you should select the variant for the chosen Server (Tomcat, Jetty, Reactor Netty, +Undertow) and the chosen web stack (Servlet or Reactive). + +In the following example, we're using Tomcat in a Servlet-based web application: + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Component + public class MyTomcatWebServerCustomizer + implements WebServerFactoryCustomizer { + + @Override + public void customize(TomcatServletWebServerFactory factory) { + // customize the factory here + } + } +---- + +Spring Boot currently provides: + +* `TomcatServletWebServerFactory` and `TomcatReactiveWebServerFactory` for Tomcat +* `JettyServletWebServerFactory` and `JettyReactiveWebServerFactory` for Jetty +* `UndertowServletWebServerFactory` and `UndertowReactiveWebServerFactory` for Undertow +* `NettyReactiveWebServerFactory` for Reactor Netty + +Once you've got access to a `WebServerFactory`, you can often add customizers to it to +configure specific parts, like connectors, server resources, or the server itself - all +using server-specific APIs. + +As a last resort, you can also declare your own `WebServerFactory` component, which will +override the one provided by Spring Boot. In this case, you can't rely on configuration +properties in the `server` namespace anymore. + + + +[[howto-add-a-servlet-filter-or-listener]] +=== Add a Servlet, Filter, or Listener to an Application +There are two ways to add `Servlet`, `Filter`, `ServletContextListener`, and the other +listeners supported by the Servlet spec to your application: + +* <> +* <> + + + +[[howto-add-a-servlet-filter-or-listener-as-spring-bean]] +==== Add a Servlet, Filter, or Listener by Using a Spring Bean +To add a `Servlet`, `Filter`, or Servlet `*Listener` by using a Spring bean, you must +provide a `@Bean` definition for it. Doing so can be very useful when you want to inject +configuration or dependencies. However, you must be very careful that they do not cause +eager initialization of too many other beans, because they have to be installed in the +container very early in the application lifecycle. (For example, it is not a good idea to +have them depend on your `DataSource` or JPA configuration.) You can work around such +restrictions by initializing the beans lazily when first used instead of on +initialization. + +In the case of `Filters` and `Servlets`, you can also add mappings and init parameters by +adding a `FilterRegistrationBean` or a `ServletRegistrationBean` instead of or in +addition to the underlying component. + +[NOTE] +==== +If no `dispatcherType` is specified on a filter registration, `REQUEST` is used. This +aligns with the Servlet Specification's default dispatcher type. +==== + +Like any other Spring bean, you can define the order of Servlet filter beans; please +make sure to check the +"`<>`" +section. + + + +[[howto-disable-registration-of-a-servlet-or-filter]] +===== Disable Registration of a Servlet or Filter +As <>, any +`Servlet` or `Filter` beans are registered with the servlet container automatically. To +disable registration of a particular `Filter` or `Servlet` bean, create a registration +bean for it and mark it as disabled, as shown in the following example: + +[source,java,indent=0,subs="verbatim,quotes,attributes"] +---- + @Bean + public FilterRegistrationBean registration(MyFilter filter) { + FilterRegistrationBean registration = new FilterRegistrationBean(filter); + registration.setEnabled(false); + return registration; + } +---- + + + +[[howto-add-a-servlet-filter-or-listener-using-scanning]] +==== Add Servlets, Filters, and Listeners by Using Classpath Scanning +`@WebServlet`, `@WebFilter`, and `@WebListener` annotated classes can be automatically +registered with an embedded servlet container by annotating a `@Configuration` class +with `@ServletComponentScan` and specifying the package(s) containing the components +that you want to register. By default, `@ServletComponentScan` scans from the package +of the annotated class. + + + [[howto-configure-accesslogs]] === Configure Access Logging Access logs can be configured for Tomcat, Undertow, and Jetty through their respective @@ -904,19 +967,6 @@ adding a new valve instance in a `TomcatServletWebServerFactory` bean. -[[howto-configure-tomcat]] -=== Configure Tomcat -Generally, you can follow the advice from -"`<>`" about -`@ConfigurationProperties` (`ServerProperties` is the main one here). However, you should -also look at `WebServerFactoryCustomizer` and various Tomcat-specific -`+*Customizers+` that you can add. The Tomcat APIs are quite rich. Consequently, once you -have access to the `TomcatServletWebServerFactory`, you can modify it in a number of ways. -Alternatively, if you need more control and customization, you can add your own -`TomcatServletWebServerFactory`. - - - [[howto-enable-multiple-connectors-in-tomcat]] === Enable Multiple Connectors with Tomcat You can add an `org.apache.catalina.connector.Connector` to the @@ -982,19 +1032,6 @@ include::{code-examples}/context/embedded/TomcatLegacyCookieProcessorExample.jav -[[howto-configure-undertow]] -=== Configure Undertow -Generally you can follow the advice from -"`<>`" about -`@ConfigurationProperties` (`ServerProperties` and `ServerProperties.Undertow` are the -main ones here). However, you should also look at `WebServerFactoryCustomizer`. -Once you have access to the `UndertowServletWebServerFactory`, you can use an -`UndertowBuilderCustomizer` to modify Undertow's configuration to meet your needs. -Alternatively, if you need more control and customization, you can add your own -`UndertowServletWebServerFactory`. - - - [[howto-enable-multiple-listeners-in-undertow]] === Enable Multiple Listeners with Undertow Add an `UndertowBuilderCustomizer` to the `UndertowServletWebServerFactory` and @@ -1040,32 +1077,6 @@ this role is performed by a servlet container initializer, and the -[[how-to-enable-http-response-compression]] -=== Enable HTTP Response Compression -HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabled -in `application.properties`, as follows: - -[source,properties,indent=0,subs="verbatim,quotes,attributes"] ----- - server.compression.enabled=true ----- - -By default, responses must be at least 2048 bytes in length for compression to be -performed. You can configure this behavior by setting the -`server.compression.min-response-size` property. - -By default, responses are compressed only if their content type is one of the -following: - -* `text/html` -* `text/xml` -* `text/plain` -* `text/css` - -You can configure this behavior by setting the `server.compression.mime-types` property. - - - [[howto-spring-mvc]] == Spring MVC From 9570cd41727b8d09451c2a0c625474af09c96e97 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 6 Jun 2018 14:36:39 -0700 Subject: [PATCH 116/701] Add saaj and jax-ws to webservices starter Closes gh-13360 --- .../spring-boot-starter-web-services/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml index f493afaf8eab..0bbfd9e860f6 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml @@ -14,6 +14,14 @@ ${basedir}/../../.. + + com.sun.xml.messaging.saaj + saaj-impl + + + javax.xml.ws + jaxws-api + org.springframework.boot spring-boot-starter From cb621024e480fb08a79277273f81aa169aed14df Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 6 Jun 2018 15:17:20 -0700 Subject: [PATCH 117/701] Include error stacktrace by default when devtools is in use Fixes gh-828 --- ...DevToolsPropertyDefaultsPostProcessor.java | 1 + .../DevToolPropertiesIntegrationTests.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index 175a2eb6a6aa..d5e181b33fa4 100755 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -56,6 +56,7 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro devToolsProperties.put("spring.resources.chain.cache", "false"); devToolsProperties.put("spring.template.provider.cache", "false"); devToolsProperties.put("spring.mvc.log-resolved-exception", "true"); + devToolsProperties.put("server.error.include-stacktrace", "ALWAYS"); devToolsProperties.put("server.servlet.jsp.init-parameters.development", "true"); devToolsProperties.put("spring.reactor.stacktrace-mode.enabled", "true"); PROPERTIES = Collections.unmodifiableMap(devToolsProperties); diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java index 1570e6516692..125dd6bb4ffe 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java @@ -29,11 +29,15 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.devtools.restart.RestartInitializer; import org.springframework.boot.devtools.restart.Restarter; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.ConfigurableEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; /** * Integration tests for the configuration of development-time properties @@ -103,6 +107,22 @@ public void postProcessWhenRestarterDisabledAndRemoteSecretSetShouldAddPropertyS this.context.getBean(MyBean.class); } + @Test + public void postProcessEnablesIncludeStackTraceProperty() { + SpringApplication application = new SpringApplication(TestConfiguration.class); + application.setWebApplicationType(WebApplicationType.NONE); + this.context = application.run(); + ConfigurableEnvironment environment = this.context.getEnvironment(); + String property = environment.getProperty("server.error.include-stacktrace"); + assertThat(property) + .isEqualTo(ErrorProperties.IncludeStacktrace.ALWAYS.toString()); + } + + @Configuration + static class TestConfiguration { + + } + @Configuration @ConditionalOnProperty("spring.h2.console.enabled") static class ClassConditionConfiguration { From a0b6547acaf9661d5c74af7153b1d9b7206db811 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 6 Jun 2018 17:31:19 -0700 Subject: [PATCH 118/701] Don't fail build on duplicate module-info classes Update the duplicate-finder-maven-plugin configuration to ignore module-info classes. Closes gh-13403 --- spring-boot-project/spring-boot-starters/pom.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-starters/pom.xml b/spring-boot-project/spring-boot-starters/pom.xml index 5bf466d03545..6876c002b2b8 100644 --- a/spring-boot-project/spring-boot-starters/pom.xml +++ b/spring-boot-project/spring-boot-starters/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -145,6 +146,9 @@ changelog.txt + + module-info + From 34167dc163035baa120916e4f3cffce724304e51 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 7 Jun 2018 13:34:18 +0200 Subject: [PATCH 119/701] Polish --- .../autoconfigure/jms/activemq/ActiveMQProperties.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java index 2a6b696de5c5..a951fe270828 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java @@ -70,9 +70,9 @@ public class ActiveMQProperties { */ private Duration sendTimeout = Duration.ofMillis(0); - private Pool pool = new Pool(); + private final Pool pool = new Pool(); - private Packages packages = new Packages(); + private final Packages packages = new Packages(); public String getBrokerUrl() { return this.brokerUrl; @@ -134,10 +134,6 @@ public Pool getPool() { return this.pool; } - public void setPool(Pool pool) { - this.pool = pool; - } - public Packages getPackages() { return this.packages; } From a4ee33bf563133c114cb29404d9616fb00e07bf4 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 6 Jun 2018 13:09:37 -0400 Subject: [PATCH 120/701] Follow-up dates for web server config documentation See gh-13315 --- .../src/main/asciidoc/howto.adoc | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index b9cd1126724b..f48d482408e2 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -506,15 +506,17 @@ configure the embedded server. This section answers those questions. [[howto-use-another-web-server]] === Use Another Web Server -Many Spring Boot starters include default embedded containers. `spring-boot-starter-web` -includes Tomcat by including `spring-boot-starter-tomcat`, but you can use -`spring-boot-starter-jetty` or `spring-boot-starter-undertow` instead. -`spring-boot-starter-webflux` includes Reactor Netty by including -`spring-boot-starter-reactor-netty`, but you can use `spring-boot-starter-tomcat`, +Many Spring Boot starters include default embedded containers. + +* For servlet stack applications, the `spring-boot-starter-web` includes Tomcat by including +`spring-boot-starter-tomcat`, but you can use `spring-boot-starter-jetty` or +`spring-boot-starter-undertow` instead. +* For reactive stack applications, the `spring-boot-starter-webflux` includes Reactor Netty +by including `spring-boot-starter-reactor-netty`, but you can use `spring-boot-starter-tomcat`, `spring-boot-starter-jetty`, or `spring-boot-starter-undertow` instead. -If you need to use a different HTTP server, you need to exclude the default dependencies -and include the one you need. Spring Boot provides separate starters for +When switching to a different HTTP server, you need to exclude the default dependencies +in addition to including the one you need. Spring Boot provides separate starters for HTTP servers to help make this process as easy as possible. The following Maven example shows how to exclude Tomcat and include Jetty for Spring MVC: @@ -768,7 +770,7 @@ You can declare such a component and get access to the server factory relevant t choice: you should select the variant for the chosen Server (Tomcat, Jetty, Reactor Netty, Undertow) and the chosen web stack (Servlet or Reactive). -In the following example, we're using Tomcat in a Servlet-based web application: +The example below is for Tomcat with the `spring-boot-starter-web` (Servlet stack): [source,java,indent=0,subs="verbatim,quotes,attributes"] ---- @@ -783,12 +785,30 @@ In the following example, we're using Tomcat in a Servlet-based web application: } ---- -Spring Boot currently provides: +In addition Spring Boot provides: + +[[howto-configure-webserver-customizers]] +[cols="1,2,2", options="header"] +|=== +| Server | Servlet stack | Reactive stack + +| Tomcat +| `TomcatServletWebServerFactory` +| `TomcatReactiveWebServerFactory` -* `TomcatServletWebServerFactory` and `TomcatReactiveWebServerFactory` for Tomcat -* `JettyServletWebServerFactory` and `JettyReactiveWebServerFactory` for Jetty -* `UndertowServletWebServerFactory` and `UndertowReactiveWebServerFactory` for Undertow -* `NettyReactiveWebServerFactory` for Reactor Netty +| Jetty +| `JettyServletWebServerFactory` +| `JettyReactiveWebServerFactory` + +| Undertow +| `UndertowServletWebServerFactory` +| `UndertowReactiveWebServerFactory` + +| Reactor +| N/A +| `NettyReactiveWebServerFactory` + +|=== Once you've got access to a `WebServerFactory`, you can often add customizers to it to configure specific parts, like connectors, server resources, or the server itself - all @@ -801,9 +821,10 @@ properties in the `server` namespace anymore. [[howto-add-a-servlet-filter-or-listener]] -=== Add a Servlet, Filter, or Listener to an Application -There are two ways to add `Servlet`, `Filter`, `ServletContextListener`, and the other -listeners supported by the Servlet spec to your application: +=== Add a Servlet, Filter, or Listener to a Application +In a servlet stack application, i.e. with the `spring-boot-starter-web`, there are two +ways to add `Servlet`, `Filter`, `ServletContextListener`, and the other listeners +supported by the Servlet API to your application: * <> * <> From 751a2b438e80b88490916ce90d5b1f826df30651 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 7 Jun 2018 15:24:32 +0200 Subject: [PATCH 121/701] Upgrade duplicate finder maven plugin to 1.3.0 Closes gh-13411 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- spring-boot-project/spring-boot-starters/pom.xml | 3 --- .../spring-boot-starter-groovy-templates/pom.xml | 5 ----- .../spring-boot-starters/spring-boot-starter-jersey/pom.xml | 1 - 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 318033ff1e02..e8107df0e810 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -327,7 +327,7 @@ org.basepom.maven duplicate-finder-maven-plugin - 1.2.1 + 1.3.0 org.codehaus.cargo diff --git a/spring-boot-project/spring-boot-starters/pom.xml b/spring-boot-project/spring-boot-starters/pom.xml index 6876c002b2b8..079a12f28543 100644 --- a/spring-boot-project/spring-boot-starters/pom.xml +++ b/spring-boot-project/spring-boot-starters/pom.xml @@ -146,9 +146,6 @@ changelog.txt - - module-info - diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml index 56ee425cf494..aaa98bfbeb86 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml @@ -39,11 +39,6 @@ check - - - module-info - - diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml index 6ec2591f6dce..0c858d9b0c73 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml @@ -124,7 +124,6 @@ org.aopalliance.* javax.annotation.* - module-info From c908445bff1c5ed47e7a4c0cd025bf703762c314 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 12 Jun 2018 14:56:02 +0900 Subject: [PATCH 122/701] Use a precompiled pattern in WebClientExchangeTags.extractPath() --- .../metrics/web/reactive/client/WebClientExchangeTags.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index 22394d4e9675..5dcb729dadd6 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.metrics.web.reactive.client; import java.io.IOException; +import java.util.regex.Pattern; import io.micrometer.core.instrument.Tag; @@ -41,6 +42,9 @@ public final class WebClientExchangeTags { private static final Tag CLIENT_ERROR = Tag.of("status", "CLIENT_ERROR"); + private static final Pattern PATTERN_BEFORE_PATH = Pattern + .compile("^https?://[^/]+/"); + private WebClientExchangeTags() { } @@ -66,7 +70,7 @@ public static Tag uri(ClientRequest request) { } private static String extractPath(String url) { - String path = url.replaceFirst("^https?://[^/]+/", ""); + String path = PATTERN_BEFORE_PATH.matcher(url).replaceFirst(""); return (path.startsWith("/") ? path : "/" + path); } From de3c3cd7559e879b0fcd89603cbe93d71bea9103 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 12 Jun 2018 12:41:11 +0900 Subject: [PATCH 123/701] Add CLIENT_NAME_NONE to WebClientExchangeTags --- .../metrics/web/reactive/client/WebClientExchangeTags.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index 5dcb729dadd6..c70aa216500e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -45,6 +45,8 @@ public final class WebClientExchangeTags { private static final Pattern PATTERN_BEFORE_PATH = Pattern .compile("^https?://[^/]+/"); + private static final Tag CLIENT_NAME_NONE = Tag.of("clientName", "none"); + private WebClientExchangeTags() { } @@ -104,7 +106,7 @@ public static Tag status(Throwable throwable) { public static Tag clientName(ClientRequest request) { String host = request.url().getHost(); if (host == null) { - host = "none"; + return CLIENT_NAME_NONE; } return Tag.of("clientName", host); } From cb6c8f76e267a303bc616c782dc7531c0a68e8e3 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 13 Jun 2018 14:53:18 +0200 Subject: [PATCH 124/701] Configure X-Forwarded-* support with Reactor Netty This commit configures the new X-Forwarded-* / Forwarded HTTP headers support with Reactor Netty in its 0.8.0 version. Closes gh-10900 --- ...veManagementChildContextConfiguration.java | 4 +- ...verFactoryCustomizerAutoConfiguration.java | 16 ++++ .../NettyWebServerFactoryCustomizer.java | 65 ++++++++++++++++ .../NettyWebServerFactoryCustomizerTests.java | 75 +++++++++++++++++++ .../netty/NettyReactiveWebServerFactory.java | 11 +++ .../JettyReactiveWebServerFactoryTests.java | 7 ++ .../NettyReactiveWebServerFactoryTests.java | 7 ++ .../TomcatReactiveWebServerFactoryTests.java | 10 +++ ...UndertowReactiveWebServerFactoryTests.java | 9 ++- ...AbstractReactiveWebServerFactoryTests.java | 22 ++++++ 10 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java index df658c06c5f6..3725785ae4ef 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/reactive/ReactiveManagementChildContextConfiguration.java @@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.web.embedded.JettyWebServerFactoryCustomizer; +import org.springframework.boot.autoconfigure.web.embedded.NettyWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer; import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryCustomizer; @@ -64,7 +65,8 @@ class ReactiveManagementWebServerFactoryCustomizer extends super(beanFactory, ReactiveWebServerFactoryCustomizer.class, TomcatWebServerFactoryCustomizer.class, JettyWebServerFactoryCustomizer.class, - UndertowWebServerFactoryCustomizer.class); + UndertowWebServerFactoryCustomizer.class, + NettyWebServerFactoryCustomizer.class); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java index 25a3cc66278b..e973058f92ee 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/EmbeddedWebServerFactoryCustomizerAutoConfiguration.java @@ -23,6 +23,7 @@ import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.webapp.WebAppContext; import org.xnio.SslClientAuthMode; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -84,4 +85,19 @@ public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer( } + /** + * Nested configuration if Netty is being used. + */ + @Configuration + @ConditionalOnClass(HttpServer.class) + public static class NettyWebServerFactoryCustomizerConfiguration { + + @Bean + public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer( + Environment environment, ServerProperties serverProperties) { + return new NettyWebServerFactoryCustomizer(environment, serverProperties); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java new file mode 100644 index 000000000000..74ff91f6834c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.embedded; + +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.cloud.CloudPlatform; +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; + +/** + * Customization for Netty-specific features. + * + * @author Brian Clozel + * @since 2.1.0 + */ +public class NettyWebServerFactoryCustomizer + implements WebServerFactoryCustomizer, Ordered { + + private final Environment environment; + + private final ServerProperties serverProperties; + + public NettyWebServerFactoryCustomizer(Environment environment, + ServerProperties serverProperties) { + this.environment = environment; + this.serverProperties = serverProperties; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void customize(NettyReactiveWebServerFactory factory) { + factory.setUseForwardHeaders( + getOrDeduceUseForwardHeaders(this.serverProperties, this.environment)); + } + + private boolean getOrDeduceUseForwardHeaders(ServerProperties serverProperties, + Environment environment) { + if (serverProperties.isUseForwardHeaders() != null) { + return serverProperties.isUseForwardHeaders(); + } + CloudPlatform platform = CloudPlatform.getActive(environment); + return platform != null && platform.isUsingForwardHeaders(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java new file mode 100644 index 000000000000..c2069b34c182 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.embedded; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.mock.env.MockEnvironment; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link NettyWebServerFactoryCustomizer}. + * + * @author Brian Clozel + */ +public class NettyWebServerFactoryCustomizerTests { + + private MockEnvironment environment; + + private ServerProperties serverProperties; + + private NettyWebServerFactoryCustomizer customizer; + + @Before + public void setup() { + this.environment = new MockEnvironment(); + this.serverProperties = new ServerProperties(); + ConfigurationPropertySources.attach(this.environment); + this.customizer = new NettyWebServerFactoryCustomizer(this.environment, + this.serverProperties); + } + + @Test + public void deduceUseForwardHeadersUndertow() { + this.environment.setProperty("DYNO", "-"); + NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); + this.customizer.customize(factory); + verify(factory).setUseForwardHeaders(true); + } + + @Test + public void defaultUseForwardHeadersUndertow() { + NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); + this.customizer.customize(factory); + verify(factory).setUseForwardHeaders(false); + } + + @Test + public void setUseForwardHeadersUndertow() { + this.serverProperties.setUseForwardHeaders(true); + NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); + this.customizer.customize(factory); + verify(factory).setUseForwardHeaders(true); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index e3cd870b74d7..4cd40180c2ba 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -44,6 +44,8 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact private Duration lifecycleTimeout; + private boolean useForwardHeaders; + public NettyReactiveWebServerFactory() { } @@ -97,6 +99,14 @@ public void setLifecycleTimeout(Duration lifecycleTimeout) { this.lifecycleTimeout = lifecycleTimeout; } + /** + * Set if x-forward-* headers should be processed. + * @param useForwardHeaders if x-forward headers should be used + */ + public void setUseForwardHeaders(boolean useForwardHeaders) { + this.useForwardHeaders = useForwardHeaders; + } + private HttpServer createHttpServer() { HttpServer server = HttpServer.create().tcpConfiguration( (tcpServer) -> tcpServer.addressSupplier(() -> getListenAddress())); @@ -110,6 +120,7 @@ private HttpServer createHttpServer() { getCompression()); server = compressionCustomizer.apply(server); } + server = (this.useForwardHeaders ? server.forwarded() : server.noForwarded()); return applyCustomizers(server); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java index 067ea60d450f..9c70d43ef42f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java @@ -93,4 +93,11 @@ public void specificIPAddressNotReverseResolved() throws Exception { .isEqualTo(localhost.getHostAddress()); } + @Test + public void useForwardedHeaders() { + JettyReactiveWebServerFactory factory = getFactory(); + factory.setUseForwardHeaders(true); + assertForwardHeaderIsUsed(factory); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index 439833351650..55c8a446785f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -74,4 +74,11 @@ public void nettyCustomizers() { } } + @Test + public void useForwardedHeaders() { + NettyReactiveWebServerFactory factory = getFactory(); + factory.setUseForwardHeaders(true); + assertForwardHeaderIsUsed(factory); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java index 3333ae1f187c..894669150edd 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java @@ -23,6 +23,7 @@ import org.apache.catalina.LifecycleListener; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.AprLifecycleListener; +import org.apache.catalina.valves.RemoteIpValve; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; @@ -133,4 +134,13 @@ public void tomcatConnectorCustomizersShouldBeInvoked() { } } + @Test + public void useForwardedHeaders() { + TomcatReactiveWebServerFactory factory = getFactory(); + RemoteIpValve valve = new RemoteIpValve(); + valve.setProtocolHeader("X-Forwarded-Proto"); + factory.addEngineValves(valve); + assertForwardHeaderIsUsed(factory); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java index 873c2d1357c7..a57627ec036f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -76,4 +76,11 @@ public void builderCustomizersShouldBeInvoked() { } } + @Test + public void useForwardedHeaders() { + UndertowReactiveWebServerFactory factory = getFactory(); + factory.setUseForwardHeaders(true); + assertForwardHeaderIsUsed(factory); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 50d4f509ac8b..40d6f1e8e18d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -47,6 +47,7 @@ import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.WebServer; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -318,6 +319,14 @@ protected void assertResponseIsNotCompressed(ResponseEntity response) { assertThat(response.getHeaders().keySet()).doesNotContain("X-Test-Compressed"); } + protected void assertForwardHeaderIsUsed(AbstractReactiveWebServerFactory factory) { + this.webServer = factory.getWebServer(new XForwardedHandler()); + this.webServer.start(); + String body = getWebClient().build().get().header("X-Forwarded-Proto", "https") + .retrieve().bodyToMono(String.class).block(); + assertThat(body).isEqualTo("https"); + } + protected static class EchoHandler implements HttpHandler { public EchoHandler() { @@ -374,4 +383,17 @@ public Mono handle(ServerHttpRequest request, ServerHttpResponse response) } + protected static class XForwardedHandler implements HttpHandler { + + @Override + public Mono handle(ServerHttpRequest request, ServerHttpResponse response) { + String scheme = request.getURI().getScheme(); + DataBufferFactory bufferFactory = new DefaultDataBufferFactory(); + DataBuffer buffer = bufferFactory + .wrap(scheme.getBytes(StandardCharsets.UTF_8)); + return response.writeWith(Mono.just(buffer)); + } + + } + } From ec845c93f2230d473f781b4684822894f46b1dbd Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 15 Jun 2018 03:53:19 +0900 Subject: [PATCH 125/701] Polish HibernateProperties and its test Closes gh-13484 --- .../orm/jpa/HibernateProperties.java | 31 +++++++++---------- .../orm/jpa/HibernatePropertiesTests.java | 14 ++++----- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index 25fb54a7ee2c..eb56d17fec8e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -21,7 +21,11 @@ import java.util.Map; import java.util.function.Supplier; +import org.hibernate.cfg.AvailableSettings; + import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; +import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -36,9 +40,6 @@ @ConfigurationProperties("spring.jpa.hibernate") public class HibernateProperties { - private static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id." - + "new_generator_mappings"; - private final Naming naming = new Naming(); /** @@ -97,10 +98,10 @@ private Map getAdditionalProperties(Map existing getNaming().applyNamingStrategies(result); String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto); if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) { - result.put("hibernate.hbm2ddl.auto", ddlAuto); + result.put(AvailableSettings.HBM2DDL_AUTO, ddlAuto); } else { - result.remove("hibernate.hbm2ddl.auto"); + result.remove(AvailableSettings.HBM2DDL_AUTO); } Collection customizers = settings .getHibernatePropertiesCustomizers(); @@ -112,17 +113,17 @@ private Map getAdditionalProperties(Map existing private void applyNewIdGeneratorMappings(Map result) { if (this.useNewIdGeneratorMappings != null) { - result.put(USE_NEW_ID_GENERATOR_MAPPINGS, + result.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, this.useNewIdGeneratorMappings.toString()); } - else if (!result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) { - result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "true"); + else if (!result.containsKey(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS)) { + result.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true"); } } private String determineDdlAuto(Map existing, Supplier defaultDdlAuto) { - String ddlAuto = existing.get("hibernate.hbm2ddl.auto"); + String ddlAuto = existing.get(AvailableSettings.HBM2DDL_AUTO); if (ddlAuto != null) { return ddlAuto; } @@ -131,10 +132,6 @@ private String determineDdlAuto(Map existing, public static class Naming { - private static final String DEFAULT_PHYSICAL_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"; - - private static final String DEFAULT_IMPLICIT_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"; - /** * Fully qualified name of the implicit naming strategy. */ @@ -162,10 +159,10 @@ public void setPhysicalStrategy(String physicalStrategy) { } private void applyNamingStrategies(Map properties) { - applyNamingStrategy(properties, "hibernate.implicit_naming_strategy", - this.implicitStrategy, DEFAULT_IMPLICIT_STRATEGY); - applyNamingStrategy(properties, "hibernate.physical_naming_strategy", - this.physicalStrategy, DEFAULT_PHYSICAL_STRATEGY); + applyNamingStrategy(properties, AvailableSettings.IMPLICIT_NAMING_STRATEGY, + this.implicitStrategy, SpringImplicitNamingStrategy.class.getName()); + applyNamingStrategy(properties, AvailableSettings.PHYSICAL_NAMING_STRATEGY, + this.physicalStrategy, SpringPhysicalNamingStrategy.class.getName()); } private void applyNamingStrategy(Map properties, String key, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java index 3a3ee40e1cb8..b3d362e5e0a3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -63,10 +63,10 @@ public void noCustomNamingStrategy() { assertThat(hibernateProperties) .doesNotContainKeys("hibernate.ejb.naming_strategy"); assertThat(hibernateProperties).containsEntry( - "hibernate.physical_naming_strategy", + AvailableSettings.PHYSICAL_NAMING_STRATEGY, SpringPhysicalNamingStrategy.class.getName()); assertThat(hibernateProperties).containsEntry( - "hibernate.implicit_naming_strategy", + AvailableSettings.IMPLICIT_NAMING_STRATEGY, SpringImplicitNamingStrategy.class.getName()); })); } @@ -78,9 +78,9 @@ public void hibernate5CustomNamingStrategies() { "spring.jpa.hibernate.naming.physical-strategy:com.example.Physical") .run(assertHibernateProperties((hibernateProperties) -> { assertThat(hibernateProperties).contains( - entry("hibernate.implicit_naming_strategy", + entry(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), - entry("hibernate.physical_naming_strategy", + entry(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); assertThat(hibernateProperties) .doesNotContainKeys("hibernate.ejb.naming_strategy"); @@ -95,9 +95,9 @@ public void hibernate5CustomNamingStrategiesViaJpaProperties() { .run(assertHibernateProperties((hibernateProperties) -> { // You can override them as we don't provide any default assertThat(hibernateProperties).contains( - entry("hibernate.implicit_naming_strategy", + entry(AvailableSettings.IMPLICIT_NAMING_STRATEGY, "com.example.Implicit"), - entry("hibernate.physical_naming_strategy", + entry(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "com.example.Physical")); assertThat(hibernateProperties) .doesNotContainKeys("hibernate.ejb.naming_strategy"); @@ -139,7 +139,7 @@ public void defaultDdlAutoIsNotInvokedIfHibernateSpecificPropertyIsSet() { private ContextConsumer assertDefaultDdlAutoNotInvoked( String expectedDdlAuto) { return assertHibernateProperties((hibernateProperties) -> { - assertThat(hibernateProperties).containsEntry("hibernate.hbm2ddl.auto", + assertThat(hibernateProperties).containsEntry(AvailableSettings.HBM2DDL_AUTO, expectedDdlAuto); verify(this.ddlAutoSupplier, never()).get(); }); From 403f8927c359c911ad6ad237ed0a9526591a06c6 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 15 Jun 2018 17:09:48 +0900 Subject: [PATCH 126/701] Polish CachesEndpoint Closes gh-13487 --- .../boot/actuate/cache/CachesEndpoint.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 62b5c43635b5..26d73e0303e8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -16,7 +16,6 @@ package org.springframework.boot.actuate.cache; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -112,21 +111,19 @@ public boolean clearCache(@Selector String cache, @Nullable String cacheManager) private List getCacheEntries(Predicate cacheNamePredicate, Predicate cacheManagerNamePredicate) { - List entries = new ArrayList<>(); - this.cacheManagers.keySet().stream().filter(cacheManagerNamePredicate) - .forEach((cacheManagerName) -> entries - .addAll(getCacheEntries(cacheManagerName, cacheNamePredicate))); - return entries; + return this.cacheManagers.keySet().stream().filter(cacheManagerNamePredicate) + .flatMap((cacheManagerName) -> getCacheEntries(cacheManagerName, + cacheNamePredicate).stream()) + .collect(Collectors.toList()); } private List getCacheEntries(String cacheManagerName, Predicate cacheNamePredicate) { CacheManager cacheManager = this.cacheManagers.get(cacheManagerName); - List entries = new ArrayList<>(); - cacheManager.getCacheNames().stream().filter(cacheNamePredicate) + return cacheManager.getCacheNames().stream().filter(cacheNamePredicate) .map(cacheManager::getCache).filter(Objects::nonNull) - .forEach((cache) -> entries.add(new CacheEntry(cache, cacheManagerName))); - return entries; + .map((cache) -> new CacheEntry(cache, cacheManagerName)) + .collect(Collectors.toList()); } private CacheEntry extractUniqueCacheEntry(String cache, List entries) { From 3b0c1354cbaf90b3ddda2810a34ad8688bf9b284 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 17 Jun 2018 16:43:27 +0200 Subject: [PATCH 127/701] Upgrade to Maven Surefire/Failsafe Plugin 2.22.0 Closes gh-13500 --- spring-boot-project/spring-boot-dependencies/pom.xml | 4 ++-- .../spring-boot-sample-junit-jupiter/pom.xml | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index adea2bd7511e..a6441abc2b47 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -197,7 +197,7 @@ 2.8.2 2.10 3.0.0-M1 - 2.21.0 + 2.22.0 2.5.2 3.1.0 2.2 @@ -207,7 +207,7 @@ 2.4.3 3.6 3.0.1 - 2.21.0 + 2.22.0 3.1.0 2.3 1.0.1 diff --git a/spring-boot-samples/spring-boot-sample-junit-jupiter/pom.xml b/spring-boot-samples/spring-boot-sample-junit-jupiter/pom.xml index f59301f5032f..13fe211ce335 100644 --- a/spring-boot-samples/spring-boot-sample-junit-jupiter/pom.xml +++ b/spring-boot-samples/spring-boot-sample-junit-jupiter/pom.xml @@ -13,7 +13,6 @@ Spring Boot JUnit Jupiter Sample ${basedir}/../.. - 2.19.1 @@ -51,13 +50,6 @@ org.apache.maven.plugins maven-surefire-plugin - - - org.junit.platform - junit-platform-surefire-provider - ${junit-platform.version} - - From fa7da40640569c275a53b33275c8b77e9818e2c9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 18 Jun 2018 09:19:01 +0200 Subject: [PATCH 128/701] Upgrade to JUnit 5.2.0 Closes gh-13118 --- .../spring-boot-dependencies/pom.xml | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index ce6345ad0c3e..c727b00943be 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -114,8 +114,7 @@ 1.2 1.3.1 4.12 - 5.1.1 - 1.1.0 + 5.2.0 1.1.0 1.2.41 5.1.0.M1 @@ -2288,24 +2287,11 @@ ${jooq.version} - org.junit.jupiter - junit-jupiter-api - ${junit-jupiter.version} - - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - - - org.junit.jupiter - junit-jupiter-params - ${junit-jupiter.version} - - - org.junit.vintage - junit-vintage-engine + org.junit + junit-bom ${junit-jupiter.version} + import + pom org.liquibase From 0c4176f596f97217fe85d2d18a1b7c468c297477 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 18 Jun 2018 10:11:50 +0200 Subject: [PATCH 129/701] Drop JsonSimpleJsonParser and JSON simple dependency Closes gh-13471 --- .../spring-boot-dependencies/pom.xml | 12 ----- spring-boot-project/spring-boot-docs/pom.xml | 5 -- spring-boot-project/spring-boot/pom.xml | 5 -- .../boot/json/JsonParserFactory.java | 11 ++--- .../boot/json/JsonSimpleJsonParser.java | 49 ------------------- .../boot/json/JsonSimpleJsonParserTests.java | 31 ------------ 6 files changed, 3 insertions(+), 110 deletions(-) delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonSimpleJsonParserTests.java diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c727b00943be..e5c583127d1d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -148,7 +148,6 @@ 2.29.3 4.1.2 3.1.0 - 1.1.1 1.7.25 1.19 7.2.1 @@ -623,17 +622,6 @@ gson ${gson.version} - - com.googlecode.json-simple - json-simple - ${simple-json.version} - - - junit - junit - - - com.h2database h2 diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 2e4d96a11ae0..c88b648a221d 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -131,11 +131,6 @@ gson true - - com.googlecode.json-simple - json-simple - true - com.hazelcast hazelcast diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index 756f14f5443b..f8682f0da0f2 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -56,11 +56,6 @@ gson true - - com.googlecode.json-simple - json-simple - true - com.samskivert jmustache diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java index 95c6dd26fc4e..737af957ef98 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,15 +25,13 @@ * @see JacksonJsonParser * @see GsonJsonParser * @see YamlJsonParser - * @see JsonSimpleJsonParser * @see BasicJsonParser */ public abstract class JsonParserFactory { /** - * Static factory for the "best" JSON parser available on the classpath. Tries Jackson - * 2, then Gson, Snake YAML, Simple JSON, JSON (from eclipse), and then falls back to - * the {@link BasicJsonParser}. + * Static factory for the "best" JSON parser available on the classpath. Tries + * Jackson, then Gson, Snake YAML,and then falls back to the {@link BasicJsonParser}. * @return a {@link JsonParser} */ public static JsonParser getJsonParser() { @@ -46,9 +44,6 @@ public static JsonParser getJsonParser() { if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { return new YamlJsonParser(); } - if (ClassUtils.isPresent("org.json.simple.JSONObject", null)) { - return new JsonSimpleJsonParser(); - } return new BasicJsonParser(); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java deleted file mode 100644 index bdede7e0599f..000000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonSimpleJsonParser.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2018 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.json; - -import java.util.List; -import java.util.Map; - -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -/** - * Thin wrapper to adapt {@link org.json.simple.JSONObject} to a {@link JsonParser}. - * - * @author Dave Syer - * @author Jean de Klerk - * @since 1.2.0 - * @see JsonParserFactory - */ -public class JsonSimpleJsonParser extends AbstractJsonParser { - - @Override - @SuppressWarnings("unchecked") - public Map parseMap(String json) { - return (Map) tryParse(() -> new JSONParser().parse(json), - ParseException.class); - } - - @Override - @SuppressWarnings("unchecked") - public List parseList(String json) { - return (List) tryParse(() -> new JSONParser().parse(json), - ParseException.class); - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonSimpleJsonParserTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonSimpleJsonParserTests.java deleted file mode 100644 index 5a6c50e74f04..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JsonSimpleJsonParserTests.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012-2017 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.json; - -/** - * Tests for {@link JsonSimpleJsonParser}. - * - * @author Dave Syer - */ -public class JsonSimpleJsonParserTests extends AbstractJsonParserTests { - - @Override - protected JsonParser getParser() { - return new JsonSimpleJsonParser(); - } - -} From a89b2ae46ea6cb40846cd547085f636e31232272 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 15 Jun 2018 16:29:40 +0200 Subject: [PATCH 130/701] Support profile expression in yml profile matching Closes gh-12469 --- .../main/asciidoc/spring-boot-features.adoc | 18 +++++++-- .../config/ConfigFileApplicationListener.java | 8 ++-- .../org/springframework/boot/ReproTests.java | 7 +++- .../boot/SpringApplicationTests.java | 3 +- .../SpringApplicationBuilderTests.java | 39 ++++++++++--------- .../ConfigFileApplicationListenerTests.java | 34 +++++++++++++--- .../test/resources/testprofileexpression.yml | 14 +++++++ 7 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/resources/testprofileexpression.yml diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5f27d29a550c..e6be4dd59649 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -756,15 +756,25 @@ example: address: 127.0.0.1 --- spring: - profiles: production + profiles: production & eu-central server: address: 192.168.1.120 ---- In the preceding example, if the `development` profile is active, the `server.address` -property is `127.0.0.1`. Similarly, if the `production` profile is active, the -`server.address` property is `192.168.1.120`. If the `development` and `production` -profiles are *not* enabled, then the value for the property is `192.168.1.100`. +property is `127.0.0.1`. Similarly, if the `production` *and* `eu-central` profiles are +active, the `server.address` property is `192.168.1.120`. If the `development` and +`production` and `eu-central` profiles are *not* enabled, then the value for the property +is `192.168.1.100`. + +[NOTE] +==== +`spring.profiles` can therefore contains a simple profile name (for example `production`) +or a profile expression. A profile expression allows for more complicated profile logic +to be expressed, for example `production & (eu-central | eu-west)`. Check the +{spring-reference}core.html#beans-definition-profiles-java[reference guide] for more +details. +==== If none are explicitly active when the application context starts, the default profiles are activated. So, in the following YAML, we set a value for `spring.security.user.password` diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 62a61f77d45c..b4e95385ce60 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -57,6 +57,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.Profiles; import org.springframework.core.env.PropertySource; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; @@ -411,14 +412,15 @@ private DocumentFilter getPositiveProfileFilter(Profile profile) { } return ObjectUtils.containsElement(document.getProfiles(), profile.getName()) - && this.environment.acceptsProfiles(document.getProfiles()); + && this.environment + .acceptsProfiles(Profiles.of(document.getProfiles())); }; } private DocumentFilter getNegativeProfileFilter(Profile profile) { return (Document document) -> (profile == null - && !ObjectUtils.isEmpty(document.getProfiles()) - && this.environment.acceptsProfiles(document.getProfiles())); + && !ObjectUtils.isEmpty(document.getProfiles()) && this.environment + .acceptsProfiles(Profiles.of(document.getProfiles()))); } private DocumentConsumer addToLoaded( diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ReproTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ReproTests.java index 8493091f1214..e077b1a5ef9c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ReproTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ReproTests.java @@ -21,6 +21,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Profiles; import static org.assertj.core.api.Assertions.assertThat; @@ -50,8 +51,10 @@ public void enableProfileViaApplicationProperties() { this.context = application.run( "--spring.config.name=enableprofileviaapplicationproperties", "--spring.profiles.active=dev"); - assertThat(this.context.getEnvironment().acceptsProfiles("dev")).isTrue(); - assertThat(this.context.getEnvironment().acceptsProfiles("a")).isTrue(); + assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("dev"))) + .isTrue(); + assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("a"))) + .isTrue(); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 7740fb0c33cb..e31a5b6a670a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -83,6 +83,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.Profiles; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ClassPathResource; @@ -525,7 +526,7 @@ public void addProfiles() { ConfigurableEnvironment environment = new StandardEnvironment(); application.setEnvironment(environment); this.context = application.run(); - assertThat(environment.acceptsProfiles("foo")).isTrue(); + assertThat(environment.acceptsProfiles(Profiles.of("foo"))).isTrue(); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java index ea6eff78e466..2ee328983e47 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java @@ -31,6 +31,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Profiles; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; @@ -72,7 +73,8 @@ public void profileAndProperties() { this.context = application.run(); assertThat(this.context).isInstanceOf(StaticApplicationContext.class); assertThat(this.context.getEnvironment().getProperty("foo")).isEqualTo("bucket"); - assertThat(this.context.getEnvironment().acceptsProfiles("foo")).isTrue(); + assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("foo"))) + .isTrue(); } @Test @@ -205,11 +207,12 @@ public void parentFirstCreationWithProfileAndDefaultArgs() { ExampleConfig.class).profiles("node").properties("transport=redis") .child(ChildConfig.class).web(WebApplicationType.NONE); this.context = application.run(); - assertThat(this.context.getEnvironment().acceptsProfiles("node")).isTrue(); + assertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of("node"))) + .isTrue(); assertThat(this.context.getEnvironment().getProperty("transport")) .isEqualTo("redis"); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles("node")) - .isTrue(); + assertThat(this.context.getParent().getEnvironment() + .acceptsProfiles(Profiles.of("node"))).isTrue(); assertThat(this.context.getParent().getEnvironment().getProperty("transport")) .isEqualTo("redis"); // only defined in node profile @@ -223,10 +226,10 @@ public void parentFirstWithDifferentProfile() { .child(ChildConfig.class).profiles("admin") .web(WebApplicationType.NONE); this.context = application.run(); - assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin")) - .isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin")) - .isFalse(); + assertThat(this.context.getEnvironment() + .acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); + assertThat(this.context.getParent().getEnvironment() + .acceptsProfiles(Profiles.of("admin"))).isFalse(); } @Test @@ -237,12 +240,12 @@ public void parentWithDifferentProfile() { .profiles("admin").web(WebApplicationType.NONE); shared.profiles("parent"); this.context = application.run(); - assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin")) - .isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles("node", - "parent")).isTrue(); - assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin")) - .isFalse(); + assertThat(this.context.getEnvironment() + .acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); + assertThat(this.context.getParent().getEnvironment() + .acceptsProfiles(Profiles.of("node", "parent"))).isTrue(); + assertThat(this.context.getParent().getEnvironment() + .acceptsProfiles(Profiles.of("admin"))).isFalse(); } @Test @@ -253,12 +256,12 @@ public void parentFirstWithDifferentProfileAndExplicitEnvironment() { .child(ChildConfig.class).profiles("admin") .web(WebApplicationType.NONE); this.context = application.run(); - assertThat(this.context.getEnvironment().acceptsProfiles("node", "admin")) - .isTrue(); + assertThat(this.context.getEnvironment() + .acceptsProfiles(Profiles.of("node", "admin"))).isTrue(); // Now they share an Environment explicitly so there's no way to keep the profiles // separate - assertThat(this.context.getParent().getEnvironment().acceptsProfiles("admin")) - .isTrue(); + assertThat(this.context.getParent().getEnvironment() + .acceptsProfiles(Profiles.of("admin"))).isTrue(); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java index 1d82d42e113c..48b80669a572 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigFileApplicationListenerTests.java @@ -54,6 +54,7 @@ import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.Profiles; import org.springframework.core.env.SimpleCommandLinePropertySource; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ByteArrayResource; @@ -504,6 +505,29 @@ public void yamlTwoProfiles() { assertThat(property).isEqualTo("notempty"); } + @Test + public void yamlProfileExpressionsAnd() { + assertProfileExpression("devandother", "dev", "other"); + } + + @Test + public void yamlProfileExpressionsComplex() { + assertProfileExpression("devorotherandanother", "dev", "another"); + } + + @Test + public void yamlProfileExpressionsNoMatch() { + assertProfileExpression("fromyamlfile", "dev"); + } + + private void assertProfileExpression(String value, String... activeProfiles) { + this.environment.setActiveProfiles(activeProfiles); + this.initializer.setSearchNames("testprofileexpression"); + this.initializer.postProcessEnvironment(this.environment, this.application); + String property = this.environment.getProperty("my.property"); + assertThat(property).isEqualTo(value); + } + @Test public void yamlNegatedProfiles() { // gh-8011 @@ -827,7 +851,7 @@ public void customDefaultProfileAndActiveFromFile() { assertThat(environment.containsProperty("customprofile")).isTrue(); assertThat(environment.containsProperty("customprofile-specific")).isTrue(); assertThat(environment.containsProperty("customprofile-customdefault")).isTrue(); - assertThat(environment.acceptsProfiles("customdefault")).isTrue(); + assertThat(environment.acceptsProfiles(Profiles.of("customdefault"))).isTrue(); } @Test @@ -899,7 +923,7 @@ public void includeLoop() { application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.config.name=applicationloop"); ConfigurableEnvironment environment = this.context.getEnvironment(); - assertThat(environment.acceptsProfiles("loop")).isTrue(); + assertThat(environment.acceptsProfiles(Profiles.of("loop"))).isTrue(); } @Test @@ -909,8 +933,8 @@ public void multiValueSpringProfiles() { application.setWebApplicationType(WebApplicationType.NONE); this.context = application.run("--spring.config.name=applicationmultiprofiles"); ConfigurableEnvironment environment = this.context.getEnvironment(); - assertThat(environment.acceptsProfiles("test")).isTrue(); - assertThat(environment.acceptsProfiles("another-test")).isTrue(); + assertThat(environment.acceptsProfiles(Profiles.of("test"))).isTrue(); + assertThat(environment.acceptsProfiles(Profiles.of("another-test"))).isTrue(); assertThat(environment.getProperty("message")).isEqualTo("multiprofile"); } @@ -932,7 +956,7 @@ private Condition matchingProfile(String profile) { @Override public boolean matches(ConfigurableEnvironment value) { - return value.acceptsProfiles(profile); + return value.acceptsProfiles(Profiles.of(profile)); } }; diff --git a/spring-boot-project/spring-boot/src/test/resources/testprofileexpression.yml b/spring-boot-project/spring-boot/src/test/resources/testprofileexpression.yml new file mode 100644 index 000000000000..78ddcfe64e39 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/testprofileexpression.yml @@ -0,0 +1,14 @@ +--- +my: + property: fromyamlfile +--- +spring: + profiles: dev & other +my: + property: devandother +--- +spring: + profiles: (dev | other) & another +my: + property: devorotherandanother +--- \ No newline at end of file From b4584e6a286d22f4fc99d2f3de675cb5a8e0bbc0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 18 Jun 2018 13:23:58 +0200 Subject: [PATCH 131/701] Support profile expression in Logback's Closes gh-13496 --- .../main/asciidoc/spring-boot-features.adoc | 10 ++++--- .../logging/logback/SpringProfileAction.java | 5 ++-- .../SpringBootJoranConfiguratorTests.java | 26 ++++++++++++++++++- .../logging/logback/profile-expression.xml | 7 +++++ 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index e6be4dd59649..49454de7b6e2 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1820,8 +1820,12 @@ ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action f The `` tag lets you optionally include or exclude sections of configuration based on the active Spring profiles. Profile sections are supported anywhere within the `` element. Use the `name` attribute to specify which -profile accepts the configuration. Multiple profiles can be specified with a -comma-separated list. The following listing shows three sample profiles: +profile accepts the configuration. The ` tag can contains a simple profile +name (for example `staging`) or a profile expression. A profile expression allows for more +complicated profile logic to be expressed, for example +`production & (eu-central | eu-west)`. Check the +{spring-reference}core.html#beans-definition-profiles-java[reference guide] for more +details. The following listing shows three sample profiles: [source,xml,indent=0] ---- @@ -1829,7 +1833,7 @@ comma-separated list. The following listing shows three sample profiles: - + diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileAction.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileAction.java index abc6070b0ffc..d6b8883d24d3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileAction.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -29,6 +29,7 @@ import org.xml.sax.Attributes; import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -74,7 +75,7 @@ private boolean acceptsProfiles(InterpretationContext ic, Attributes attributes) OptionHelper.substVars(profileName, ic, this.context); } return this.environment != null - && this.environment.acceptsProfiles(profileNames); + && this.environment.acceptsProfiles(Profiles.of(profileNames)); } return false; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java index eba0279be160..48a0a5f1c9db 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -108,6 +108,30 @@ public void profileNotActive() throws Exception { this.out.expect(not(containsString("Hello"))); } + @Test + public void profileExpressionMatchFirst() throws Exception { + this.environment.setActiveProfiles("production"); + initialize("profile-expression.xml"); + this.logger.trace("Hello"); + this.out.expect(containsString("Hello")); + } + + @Test + public void profileExpressionMatchSecond() throws Exception { + this.environment.setActiveProfiles("production"); + initialize("profile-expression.xml"); + this.logger.trace("Hello"); + this.out.expect(containsString("Hello")); + } + + @Test + public void profileExpressionNoMatch() throws Exception { + this.environment.setActiveProfiles("development"); + initialize("profile-expression.xml"); + this.logger.trace("Hello"); + this.out.expect(not(containsString("Hello"))); + } + @Test public void profileNestedActiveActive() throws Exception { doTestNestedProfile(true, "outer", "inner"); diff --git a/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml new file mode 100644 index 000000000000..448bb017a5e4 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/resources/org/springframework/boot/logging/logback/profile-expression.xml @@ -0,0 +1,7 @@ + + + + + + + From fb834898abab3481e6976230e7f0f4d3f8a09be5 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 19 Jun 2018 04:27:38 +0900 Subject: [PATCH 132/701] Use final keywords for Map fields in JacksonProperties Closes gh-13517 --- .../autoconfigure/jackson/JacksonProperties.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java index 624f942dc79a..05a450bcce44 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonProperties.java @@ -65,36 +65,36 @@ public class JacksonProperties { * Jackson visibility thresholds that can be used to limit which methods (and fields) * are auto-detected. */ - private Map visibility = new EnumMap<>( + private final Map visibility = new EnumMap<>( PropertyAccessor.class); /** * Jackson on/off features that affect the way Java objects are serialized. */ - private Map serialization = new EnumMap<>( + private final Map serialization = new EnumMap<>( SerializationFeature.class); /** * Jackson on/off features that affect the way Java objects are deserialized. */ - private Map deserialization = new EnumMap<>( + private final Map deserialization = new EnumMap<>( DeserializationFeature.class); /** * Jackson general purpose on/off features. */ - private Map mapper = new EnumMap<>(MapperFeature.class); + private final Map mapper = new EnumMap<>(MapperFeature.class); /** * Jackson on/off features for parsers. */ - private Map parser = new EnumMap<>( + private final Map parser = new EnumMap<>( JsonParser.Feature.class); /** * Jackson on/off features for generators. */ - private Map generator = new EnumMap<>( + private final Map generator = new EnumMap<>( JsonGenerator.Feature.class); /** From 9308904af7708385a5cf835276cd63dd64df907d Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Tue, 19 Jun 2018 02:07:59 +0900 Subject: [PATCH 133/701] Add reference to dozer-spring-boot-starter See gh-13501 --- spring-boot-project/spring-boot-starters/README.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 2f6e2e7b35ab..ccd674036015 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -67,6 +67,9 @@ do as they were designed before this was clarified. | https://github.com/docker-java/docker-java/[Docker Java] and https://github.com/spotify/docker-client/[Docker Client] | https://github.com/jliu666/docker-api-spring-boot +| https://github.com/DozerMapper/dozer[Dozer] +| https://github.com/DozerMapper/dozer/blob/master/docs/asciidoc/documentation/springBootIntegration.adoc + | ErroREST exception handler | https://github.com/mkopylec/errorest-spring-boot-starter From f682c776913cc6eb888b85400132cbcba6c934da Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 19 Jun 2018 10:54:01 +0200 Subject: [PATCH 134/701] Polish "Add reference to dozer-spring-boot-starter" Closes gh-13501 --- spring-boot-project/spring-boot-starters/README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index ccd674036015..da1dfd813ec9 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -67,8 +67,8 @@ do as they were designed before this was clarified. | https://github.com/docker-java/docker-java/[Docker Java] and https://github.com/spotify/docker-client/[Docker Client] | https://github.com/jliu666/docker-api-spring-boot -| https://github.com/DozerMapper/dozer[Dozer] -| https://github.com/DozerMapper/dozer/blob/master/docs/asciidoc/documentation/springBootIntegration.adoc +| https://dozermapper.github.io/[Dozer] +| https://github.com/DozerMapper/dozer | ErroREST exception handler | https://github.com/mkopylec/errorest-spring-boot-starter From 28c1bc99861813b9a8694c3921da3569734e45c5 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 19 Jun 2018 15:02:45 +0200 Subject: [PATCH 135/701] Fix DefaultErrorViewResolver after HttpStatus changes Since SPR-16898, `HttpStatus.toString()` has changed and we should instead rely on `HttpStatus.value()` to get the HTTP status number. --- .../web/servlet/error/DefaultErrorViewResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorViewResolver.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorViewResolver.java index 829c13c63723..c005f2e471cf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorViewResolver.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorViewResolver.java @@ -102,7 +102,7 @@ public DefaultErrorViewResolver(ApplicationContext applicationContext, @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) { - ModelAndView modelAndView = resolve(String.valueOf(status), model); + ModelAndView modelAndView = resolve(String.valueOf(status.value()), model); if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } From 0ef54a79b15dc4d0463fba4ee4eeef2c948059af Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 6 Jun 2018 14:44:26 +0200 Subject: [PATCH 136/701] Add support for connection pooling with Artemis This commit expands ActiveMQ's connection pooling to artemis. The same pooling features are now shared by the two brokers and a PooledConnectionFactory can be auto-configured when the necessary jar is present. Closes gh-13523 --- ...ctiveMQConnectionFactoryConfiguration.java | 45 +---- .../jms/activemq/ActiveMQProperties.java | 159 +--------------- .../PooledConnectionFactoryFactory.java | 79 ++++++++ .../PooledConnectionFactoryProperties.java | 178 ++++++++++++++++++ ...ArtemisConnectionFactoryConfiguration.java | 26 ++- .../jms/artemis/ArtemisProperties.java | 11 +- .../jms/JmsAutoConfigurationTests.java | 2 +- .../ActiveMQAutoConfigurationTests.java | 2 +- .../ArtemisAutoConfigurationTests.java | 83 ++++++++ .../appendix-application-properties.adoc | 11 ++ .../main/asciidoc/spring-boot-features.adoc | 12 +- 11 files changed, 413 insertions(+), 195 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java index 34ee5468079d..e4a8a5a0467d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -21,7 +21,8 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.pool.PooledConnectionFactory; +import org.apache.activemq.jms.pool.PooledConnectionFactory; +import org.apache.commons.pool2.PooledObject; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -54,7 +55,7 @@ public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties propert } @Configuration - @ConditionalOnClass(PooledConnectionFactory.class) + @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) static class PooledConnectionFactoryConfiguration { @Bean(destroyMethod = "stop") @@ -62,38 +63,12 @@ static class PooledConnectionFactoryConfiguration { public PooledConnectionFactory pooledJmsConnectionFactory( ActiveMQProperties properties, ObjectProvider> factoryCustomizers) { - PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory( - new ActiveMQConnectionFactoryFactory(properties, - factoryCustomizers.getIfAvailable()).createConnectionFactory( - ActiveMQConnectionFactory.class)); - ActiveMQProperties.Pool pool = properties.getPool(); - pooledConnectionFactory.setBlockIfSessionPoolIsFull(pool.isBlockIfFull()); - if (pool.getBlockIfFullTimeout() != null) { - pooledConnectionFactory.setBlockIfSessionPoolIsFullTimeout( - pool.getBlockIfFullTimeout().toMillis()); - } - pooledConnectionFactory - .setCreateConnectionOnStartup(pool.isCreateConnectionOnStartup()); - if (pool.getExpiryTimeout() != null) { - pooledConnectionFactory - .setExpiryTimeout(pool.getExpiryTimeout().toMillis()); - } - if (pool.getIdleTimeout() != null) { - pooledConnectionFactory - .setIdleTimeout((int) pool.getIdleTimeout().toMillis()); - } - pooledConnectionFactory.setMaxConnections(pool.getMaxConnections()); - pooledConnectionFactory.setMaximumActiveSessionPerConnection( - pool.getMaximumActiveSessionPerConnection()); - pooledConnectionFactory - .setReconnectOnException(pool.isReconnectOnException()); - if (pool.getTimeBetweenExpirationCheck() != null) { - pooledConnectionFactory.setTimeBetweenExpirationCheckMillis( - pool.getTimeBetweenExpirationCheck().toMillis()); - } - pooledConnectionFactory - .setUseAnonymousProducers(pool.isUseAnonymousProducers()); - return pooledConnectionFactory; + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory( + properties, factoryCustomizers.getIfAvailable()) + .createConnectionFactory(ActiveMQConnectionFactory.class); + return new PooledConnectionFactoryFactory(properties.getPool()) + .createPooledConnectionFactory(connectionFactory); + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java index a951fe270828..8e9352dd834a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java @@ -21,6 +21,7 @@ import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; /** * Configuration properties for ActiveMQ. @@ -70,7 +71,8 @@ public class ActiveMQProperties { */ private Duration sendTimeout = Duration.ofMillis(0); - private final Pool pool = new Pool(); + @NestedConfigurationProperty + private final PooledConnectionFactoryProperties pool = new PooledConnectionFactoryProperties(); private final Packages packages = new Packages(); @@ -130,7 +132,7 @@ public void setSendTimeout(Duration sendTimeout) { this.sendTimeout = sendTimeout; } - public Pool getPool() { + public PooledConnectionFactoryProperties getPool() { return this.pool; } @@ -138,159 +140,6 @@ public Packages getPackages() { return this.packages; } - public static class Pool { - - /** - * Whether a PooledConnectionFactory should be created, instead of a regular - * ConnectionFactory. - */ - private boolean enabled; - - /** - * Whether to block when a connection is requested and the pool is full. Set it to - * false to throw a "JMSException" instead. - */ - private boolean blockIfFull = true; - - /** - * Blocking period before throwing an exception if the pool is still full. - */ - private Duration blockIfFullTimeout = Duration.ofMillis(-1); - - /** - * Whether to create a connection on startup. Can be used to warm up the pool on - * startup. - */ - private boolean createConnectionOnStartup = true; - - /** - * Connection expiration timeout. - */ - private Duration expiryTimeout = Duration.ofMillis(0); - - /** - * Connection idle timeout. - */ - private Duration idleTimeout = Duration.ofSeconds(30); - - /** - * Maximum number of pooled connections. - */ - private int maxConnections = 1; - - /** - * Maximum number of active sessions per connection. - */ - private int maximumActiveSessionPerConnection = 500; - - /** - * Reset the connection when a "JMSException" occurs. - */ - private boolean reconnectOnException = true; - - /** - * Time to sleep between runs of the idle connection eviction thread. When - * negative, no idle connection eviction thread runs. - */ - private Duration timeBetweenExpirationCheck = Duration.ofMillis(-1); - - /** - * Whether to use only one anonymous "MessageProducer" instance. Set it to false - * to create one "MessageProducer" every time one is required. - */ - private boolean useAnonymousProducers = true; - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isBlockIfFull() { - return this.blockIfFull; - } - - public void setBlockIfFull(boolean blockIfFull) { - this.blockIfFull = blockIfFull; - } - - public Duration getBlockIfFullTimeout() { - return this.blockIfFullTimeout; - } - - public void setBlockIfFullTimeout(Duration blockIfFullTimeout) { - this.blockIfFullTimeout = blockIfFullTimeout; - } - - public boolean isCreateConnectionOnStartup() { - return this.createConnectionOnStartup; - } - - public void setCreateConnectionOnStartup(boolean createConnectionOnStartup) { - this.createConnectionOnStartup = createConnectionOnStartup; - } - - public Duration getExpiryTimeout() { - return this.expiryTimeout; - } - - public void setExpiryTimeout(Duration expiryTimeout) { - this.expiryTimeout = expiryTimeout; - } - - public Duration getIdleTimeout() { - return this.idleTimeout; - } - - public void setIdleTimeout(Duration idleTimeout) { - this.idleTimeout = idleTimeout; - } - - public int getMaxConnections() { - return this.maxConnections; - } - - public void setMaxConnections(int maxConnections) { - this.maxConnections = maxConnections; - } - - public int getMaximumActiveSessionPerConnection() { - return this.maximumActiveSessionPerConnection; - } - - public void setMaximumActiveSessionPerConnection( - int maximumActiveSessionPerConnection) { - this.maximumActiveSessionPerConnection = maximumActiveSessionPerConnection; - } - - public boolean isReconnectOnException() { - return this.reconnectOnException; - } - - public void setReconnectOnException(boolean reconnectOnException) { - this.reconnectOnException = reconnectOnException; - } - - public Duration getTimeBetweenExpirationCheck() { - return this.timeBetweenExpirationCheck; - } - - public void setTimeBetweenExpirationCheck(Duration timeBetweenExpirationCheck) { - this.timeBetweenExpirationCheck = timeBetweenExpirationCheck; - } - - public boolean isUseAnonymousProducers() { - return this.useAnonymousProducers; - } - - public void setUseAnonymousProducers(boolean useAnonymousProducers) { - this.useAnonymousProducers = useAnonymousProducers; - } - - } - public static class Packages { /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java new file mode 100644 index 000000000000..33a9c04350c7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2018 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.autoconfigure.jms.activemq; + +import javax.jms.ConnectionFactory; + +import org.apache.activemq.jms.pool.PooledConnectionFactory; + +/** + * Factory to create a {@link PooledConnectionFactory} from properties defined in + * {@link PooledConnectionFactoryProperties}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class PooledConnectionFactoryFactory { + + private final PooledConnectionFactoryProperties properties; + + public PooledConnectionFactoryFactory(PooledConnectionFactoryProperties properties) { + this.properties = properties; + } + + /** + * Create a {@link PooledConnectionFactory} based on the specified + * {@link ConnectionFactory}. + * @param connectionFactory the connection factory to wrap + * @return a pooled connection factory + */ + public PooledConnectionFactory createPooledConnectionFactory( + ConnectionFactory connectionFactory) { + PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(); + pooledConnectionFactory.setConnectionFactory(connectionFactory); + + pooledConnectionFactory + .setBlockIfSessionPoolIsFull(this.properties.isBlockIfFull()); + if (this.properties.getBlockIfFullTimeout() != null) { + pooledConnectionFactory.setBlockIfSessionPoolIsFullTimeout( + this.properties.getBlockIfFullTimeout().toMillis()); + } + pooledConnectionFactory.setCreateConnectionOnStartup( + this.properties.isCreateConnectionOnStartup()); + if (this.properties.getExpiryTimeout() != null) { + pooledConnectionFactory + .setExpiryTimeout(this.properties.getExpiryTimeout().toMillis()); + } + if (this.properties.getIdleTimeout() != null) { + pooledConnectionFactory + .setIdleTimeout((int) this.properties.getIdleTimeout().toMillis()); + } + pooledConnectionFactory.setMaxConnections(this.properties.getMaxConnections()); + pooledConnectionFactory.setMaximumActiveSessionPerConnection( + this.properties.getMaximumActiveSessionPerConnection()); + pooledConnectionFactory + .setReconnectOnException(this.properties.isReconnectOnException()); + if (this.properties.getTimeBetweenExpirationCheck() != null) { + pooledConnectionFactory.setTimeBetweenExpirationCheckMillis( + this.properties.getTimeBetweenExpirationCheck().toMillis()); + } + pooledConnectionFactory + .setUseAnonymousProducers(this.properties.isUseAnonymousProducers()); + return pooledConnectionFactory; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java new file mode 100644 index 000000000000..75f05b481f58 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java @@ -0,0 +1,178 @@ +/* + * Copyright 2012-2018 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.autoconfigure.jms.activemq; + +import java.time.Duration; + +/** + * Configuration properties for connection factory pooling. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class PooledConnectionFactoryProperties { + + /** + * Whether a PooledConnectionFactory should be created, instead of a regular + * ConnectionFactory. + */ + private boolean enabled; + + /** + * Whether to block when a connection is requested and the pool is full. Set it to + * false to throw a "JMSException" instead. + */ + private boolean blockIfFull = true; + + /** + * Blocking period before throwing an exception if the pool is still full. + */ + private Duration blockIfFullTimeout = Duration.ofMillis(-1); + + /** + * Whether to create a connection on startup. Can be used to warm up the pool on + * startup. + */ + private boolean createConnectionOnStartup = true; + + /** + * Connection expiration timeout. + */ + private Duration expiryTimeout = Duration.ofMillis(0); + + /** + * Connection idle timeout. + */ + private Duration idleTimeout = Duration.ofSeconds(30); + + /** + * Maximum number of pooled connections. + */ + private int maxConnections = 1; + + /** + * Maximum number of active sessions per connection. + */ + private int maximumActiveSessionPerConnection = 500; + + /** + * Reset the connection when a "JMSException" occurs. + */ + private boolean reconnectOnException = true; + + /** + * Time to sleep between runs of the idle connection eviction thread. When negative, + * no idle connection eviction thread runs. + */ + private Duration timeBetweenExpirationCheck = Duration.ofMillis(-1); + + /** + * Whether to use only one anonymous "MessageProducer" instance. Set it to false to + * create one "MessageProducer" every time one is required. + */ + private boolean useAnonymousProducers = true; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isBlockIfFull() { + return this.blockIfFull; + } + + public void setBlockIfFull(boolean blockIfFull) { + this.blockIfFull = blockIfFull; + } + + public Duration getBlockIfFullTimeout() { + return this.blockIfFullTimeout; + } + + public void setBlockIfFullTimeout(Duration blockIfFullTimeout) { + this.blockIfFullTimeout = blockIfFullTimeout; + } + + public boolean isCreateConnectionOnStartup() { + return this.createConnectionOnStartup; + } + + public void setCreateConnectionOnStartup(boolean createConnectionOnStartup) { + this.createConnectionOnStartup = createConnectionOnStartup; + } + + public Duration getExpiryTimeout() { + return this.expiryTimeout; + } + + public void setExpiryTimeout(Duration expiryTimeout) { + this.expiryTimeout = expiryTimeout; + } + + public Duration getIdleTimeout() { + return this.idleTimeout; + } + + public void setIdleTimeout(Duration idleTimeout) { + this.idleTimeout = idleTimeout; + } + + public int getMaxConnections() { + return this.maxConnections; + } + + public void setMaxConnections(int maxConnections) { + this.maxConnections = maxConnections; + } + + public int getMaximumActiveSessionPerConnection() { + return this.maximumActiveSessionPerConnection; + } + + public void setMaximumActiveSessionPerConnection( + int maximumActiveSessionPerConnection) { + this.maximumActiveSessionPerConnection = maximumActiveSessionPerConnection; + } + + public boolean isReconnectOnException() { + return this.reconnectOnException; + } + + public void setReconnectOnException(boolean reconnectOnException) { + this.reconnectOnException = reconnectOnException; + } + + public Duration getTimeBetweenExpirationCheck() { + return this.timeBetweenExpirationCheck; + } + + public void setTimeBetweenExpirationCheck(Duration timeBetweenExpirationCheck) { + this.timeBetweenExpirationCheck = timeBetweenExpirationCheck; + } + + public boolean isUseAnonymousProducers() { + return this.useAnonymousProducers; + } + + public void setUseAnonymousProducers(boolean useAnonymousProducers) { + this.useAnonymousProducers = useAnonymousProducers; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java index f48b2cf6fe47..51b9947f37c0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,9 +19,14 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; +import org.apache.activemq.jms.pool.PooledConnectionFactory; +import org.apache.commons.pool2.PooledObject; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -30,16 +35,35 @@ * * @author Eddú Meléndez * @author Phillip Webb + * @author Stephane Nicoll */ @Configuration @ConditionalOnMissingBean(ConnectionFactory.class) class ArtemisConnectionFactoryConfiguration { @Bean + @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false", matchIfMissing = true) public ActiveMQConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties) { return new ArtemisConnectionFactoryFactory(beanFactory, properties) .createConnectionFactory(ActiveMQConnectionFactory.class); } + @Configuration + @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) + static class PooledConnectionFactoryConfiguration { + + @Bean(destroyMethod = "stop") + @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "true", matchIfMissing = false) + public PooledConnectionFactory pooledJmsConnectionFactory( + ListableBeanFactory beanFactory, ArtemisProperties properties) { + ActiveMQConnectionFactory connectionFactory = new ArtemisConnectionFactoryFactory( + beanFactory, properties) + .createConnectionFactory(ActiveMQConnectionFactory.class); + return new PooledConnectionFactoryFactory(properties.getPool()) + .createPooledConnectionFactory(connectionFactory); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java index e0f43aba2681..0a6fcf4a5315 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,7 +23,9 @@ import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants; +import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryProperties; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; /** * Configuration properties for Artemis. @@ -62,6 +64,9 @@ public class ArtemisProperties { private final Embedded embedded = new Embedded(); + @NestedConfigurationProperty + private final PooledConnectionFactoryProperties pool = new PooledConnectionFactoryProperties(); + public ArtemisMode getMode() { return this.mode; } @@ -106,6 +111,10 @@ public Embedded getEmbedded() { return this.embedded; } + public PooledConnectionFactoryProperties getPool() { + return this.pool; + } + /** * Configuration for an embedded Artemis server. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java index c65f6a2bbff6..849a9e7c649e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java @@ -20,7 +20,7 @@ import javax.jms.Session; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.pool.PooledConnectionFactory; +import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Test; import org.springframework.beans.BeansException; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java index 17ac22397201..a1337dc94d18 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java @@ -19,7 +19,7 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.pool.PooledConnectionFactory; +import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java index 82c166146c93..25b015aee442 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.UUID; +import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; @@ -36,6 +37,7 @@ import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl; import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl; import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS; +import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -291,6 +293,87 @@ public void connectToASpecificEmbeddedBroker() { }); } + @Test + public void defaultPooledConnectionFactoryIsApplied() { + this.contextRunner.withPropertyValues("spring.artemis.pool.enabled=true") + .run((context) -> { + assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + .hasSize(1); + PooledConnectionFactory connectionFactory = context + .getBean(PooledConnectionFactory.class); + PooledConnectionFactory defaultFactory = new PooledConnectionFactory(); + assertThat(connectionFactory.isBlockIfSessionPoolIsFull()) + .isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull()); + assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) + .isEqualTo( + defaultFactory.getBlockIfSessionPoolIsFullTimeout()); + assertThat(connectionFactory.isCreateConnectionOnStartup()) + .isEqualTo(defaultFactory.isCreateConnectionOnStartup()); + assertThat(connectionFactory.getExpiryTimeout()) + .isEqualTo(defaultFactory.getExpiryTimeout()); + assertThat(connectionFactory.getIdleTimeout()) + .isEqualTo(defaultFactory.getIdleTimeout()); + assertThat(connectionFactory.getMaxConnections()) + .isEqualTo(defaultFactory.getMaxConnections()); + assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) + .isEqualTo(defaultFactory + .getMaximumActiveSessionPerConnection()); + assertThat(connectionFactory.isReconnectOnException()) + .isEqualTo(defaultFactory.isReconnectOnException()); + assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) + .isEqualTo( + defaultFactory.getTimeBetweenExpirationCheckMillis()); + assertThat(connectionFactory.isUseAnonymousProducers()) + .isEqualTo(defaultFactory.isUseAnonymousProducers()); + }); + } + + @Test + public void customPooledConnectionFactoryIsApplied() { + this.contextRunner + .withPropertyValues("spring.artemis.pool.enabled=true", + "spring.artemis.pool.blockIfFull=false", + "spring.artemis.pool.blockIfFullTimeout=64", + "spring.artemis.pool.createConnectionOnStartup=false", + "spring.artemis.pool.expiryTimeout=4096", + "spring.artemis.pool.idleTimeout=512", + "spring.artemis.pool.maxConnections=256", + "spring.artemis.pool.maximumActiveSessionPerConnection=1024", + "spring.artemis.pool.reconnectOnException=false", + "spring.artemis.pool.timeBetweenExpirationCheck=2048", + "spring.artemis.pool.useAnonymousProducers=false") + .run((context) -> { + assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + .hasSize(1); + PooledConnectionFactory connectionFactory = context + .getBean(PooledConnectionFactory.class); + assertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse(); + assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) + .isEqualTo(64); + assertThat(connectionFactory.isCreateConnectionOnStartup()).isFalse(); + assertThat(connectionFactory.getExpiryTimeout()).isEqualTo(4096); + assertThat(connectionFactory.getIdleTimeout()).isEqualTo(512); + assertThat(connectionFactory.getMaxConnections()).isEqualTo(256); + assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) + .isEqualTo(1024); + assertThat(connectionFactory.isReconnectOnException()).isFalse(); + assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) + .isEqualTo(2048); + assertThat(connectionFactory.isUseAnonymousProducers()).isFalse(); + }); + } + + @Test + public void pooledConnectionFactoryConfiguration() { + this.contextRunner.withPropertyValues("spring.artemis.pool.enabled:true") + .run((context) -> { + ConnectionFactory factory = context.getBean(ConnectionFactory.class); + assertThat(factory).isInstanceOf(PooledConnectionFactory.class); + context.getSourceApplicationContext().close(); + assertThat(factory.createConnection()).isNull(); + }); + } + private TransportConfiguration assertInVmConnectionFactory( ActiveMQConnectionFactory connectionFactory) { TransportConfiguration transportConfig = getSingleTransportConfiguration( diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b44fee4a1293..8d27a4099642 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -969,6 +969,17 @@ content into your application. Rather, pick only the properties that you need. spring.artemis.host=localhost # Artemis broker host. spring.artemis.mode= # Artemis deployment mode, auto-detected by default. spring.artemis.password= # Login password of the broker. + spring.artemis.pool.block-if-full=true # Whether to block when a connection is requested and the pool is full. Set it to false to throw a "JMSException" instead. + spring.artemis.pool.block-if-full-timeout=-1ms # Blocking period before throwing an exception if the pool is still full. + spring.artemis.pool.create-connection-on-startup=true # Whether to create a connection on startup. Can be used to warm up the pool on startup. + spring.artemis.pool.enabled=false # Whether a PooledConnectionFactory should be created, instead of a regular ConnectionFactory. + spring.artemis.pool.expiry-timeout=0ms # Connection expiration timeout. + spring.artemis.pool.idle-timeout=30s # Connection idle timeout. + spring.artemis.pool.max-connections=1 # Maximum number of pooled connections. + spring.artemis.pool.maximum-active-session-per-connection=500 # Maximum number of active sessions per connection. + spring.artemis.pool.reconnect-on-exception=true # Reset the connection when a "JMSException" occurs. + spring.artemis.pool.time-between-expiration-check=-1ms # Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs. + spring.artemis.pool.use-anonymous-producers=true # Whether to use only one anonymous "MessageProducer" instance. Set it to false to create one "MessageProducer" every time one is required. spring.artemis.port=61616 # Artemis broker port. spring.artemis.user= # Login user of the broker. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 49454de7b6e2..57b690451a83 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5066,7 +5066,7 @@ ActiveMQ configuration is controlled by external configuration properties in ---- You can also pool JMS resources by adding a dependency to -`org.apache.activemq:activemq-pool` and configuring the `PooledConnectionFactory` +`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` accordingly, as shown in the following example: [source,properties,indent=0] @@ -5122,6 +5122,16 @@ list to create them with the default options, or you can define bean(s) of type `org.apache.activemq.artemis.jms.server.config.TopicConfiguration`, for advanced queue and topic configurations, respectively. +You can also pool JMS resources by adding a dependency to +`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` +accordingly, as shown in the following example: + +[source,properties,indent=0] +---- + spring.artemis.pool.enabled=true + spring.artemis.pool.max-connections=50 +---- + See {sc-spring-boot-autoconfigure}/jms/artemis/ArtemisProperties.{sc-ext}[`ArtemisProperties`] for more supported options. From 8365d535545b5683955a54eebaffbc3c7ffbcdda Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 7 Jun 2018 14:55:01 +0200 Subject: [PATCH 137/701] Add support for JMS session caching This commit adds support for CachingConnectionFactory for both Artemis and ActiveMQ. If connection pooling is not enabled explicitly, sessions, producers and consumers are cached. The factory can be further customized, including reverting to the raw ConnectionFactory, using the `spring.jms.*` namespace. Closes gh-12161 --- .../boot/autoconfigure/jms/JmsProperties.java | 64 +++++++++- .../activemq/ActiveMQAutoConfiguration.java | 5 +- ...ctiveMQConnectionFactoryConfiguration.java | 50 +++++++- .../jms/artemis/ArtemisAutoConfiguration.java | 5 +- ...ArtemisConnectionFactoryConfiguration.java | 46 ++++++- .../jms/JmsAutoConfigurationTests.java | 49 ++++---- .../ActiveMQAutoConfigurationTests.java | 53 +++++++- .../ArtemisAutoConfigurationTests.java | 119 ++++++++++++++---- .../appendix-application-properties.adoc | 4 + .../main/asciidoc/spring-boot-features.adoc | 22 +++- 10 files changed, 345 insertions(+), 72 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java index be584dc5750f..eff79905d53e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -41,6 +41,8 @@ public class JmsProperties { */ private String jndiName; + private final Cache cache = new Cache(); + private final Listener listener = new Listener(); private final Template template = new Template(); @@ -61,6 +63,10 @@ public void setJndiName(String jndiName) { this.jndiName = jndiName; } + public Cache getCache() { + return this.cache; + } + public Listener getListener() { return this.listener; } @@ -69,6 +75,62 @@ public Template getTemplate() { return this.template; } + public static class Cache { + + /** + * Whether to cache sessions. + */ + private boolean enabled = true; + + /** + * Whether to cache message consumers. + */ + private boolean consumers = false; + + /** + * Whether to cache message producers. + */ + private boolean producers = true; + + /** + * Size of the session cache (per JMS Session type). + */ + private int sessionCacheSize = 1; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isConsumers() { + return this.consumers; + } + + public void setConsumers(boolean consumers) { + this.consumers = consumers; + } + + public boolean isProducers() { + return this.producers; + } + + public void setProducers(boolean producers) { + this.producers = producers; + } + + public int getSessionCacheSize() { + return this.sessionCacheSize; + } + + public void setSessionCacheSize(int sessionCacheSize) { + this.sessionCacheSize = sessionCacheSize; + } + + } + public static class Listener { /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfiguration.java index b5462943cb04..ed1140c83c79 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; +import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -45,7 +46,7 @@ @AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class }) @ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class }) @ConditionalOnMissingBean(ConnectionFactory.class) -@EnableConfigurationProperties(ActiveMQProperties.class) +@EnableConfigurationProperties({ ActiveMQProperties.class, JmsProperties.class }) @Import({ ActiveMQXAConnectionFactoryConfiguration.class, ActiveMQConnectionFactoryConfiguration.class }) public class ActiveMQAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java index e4a8a5a0467d..df32566cf48c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java @@ -28,8 +28,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.jms.connection.CachingConnectionFactory; /** * Configuration for ActiveMQ {@link ConnectionFactory}. @@ -45,13 +47,49 @@ @ConditionalOnMissingBean(ConnectionFactory.class) class ActiveMQConnectionFactoryConfiguration { - @Bean + @Configuration @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true) - public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties, - ObjectProvider> factoryCustomizers) { - return new ActiveMQConnectionFactoryFactory(properties, - factoryCustomizers.getIfAvailable()) - .createConnectionFactory(ActiveMQConnectionFactory.class); + static class SimpleConnectionFactoryConfiguration { + + private final JmsProperties jmsProperties; + + private final ActiveMQProperties properties; + + private final List connectionFactoryCustomizers; + + SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties, + ActiveMQProperties properties, + ObjectProvider> connectionFactoryCustomizers) { + this.jmsProperties = jmsProperties; + this.properties = properties; + this.connectionFactoryCustomizers = connectionFactoryCustomizers + .getIfAvailable(); + } + + @Bean + @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true) + public CachingConnectionFactory cachingJmsConnectionFactory() { + JmsProperties.Cache cacheProperties = this.jmsProperties.getCache(); + CachingConnectionFactory connectionFactory = new CachingConnectionFactory( + createConnectionFactory()); + connectionFactory.setCacheConsumers(cacheProperties.isConsumers()); + connectionFactory.setCacheProducers(cacheProperties.isProducers()); + connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize()); + return connectionFactory; + } + + @Bean + @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false") + public ActiveMQConnectionFactory jmsConnectionFactory() { + return createConnectionFactory(); + } + + private ActiveMQConnectionFactory createConnectionFactory() { + return new ActiveMQConnectionFactoryFactory(this.properties, + this.connectionFactoryCustomizers) + .createConnectionFactory(ActiveMQConnectionFactory.class); + } + } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java index bff0d95c6274..3f312f8e555d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; +import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @@ -47,7 +48,7 @@ @AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class }) @ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class }) @ConditionalOnMissingBean(ConnectionFactory.class) -@EnableConfigurationProperties(ArtemisProperties.class) +@EnableConfigurationProperties({ ArtemisProperties.class, JmsProperties.class }) @Import({ ArtemisEmbeddedServerConfiguration.class, ArtemisXAConnectionFactoryConfiguration.class, ArtemisConnectionFactoryConfiguration.class }) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java index 51b9947f37c0..97bf6ea0079c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java @@ -26,9 +26,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.jms.connection.CachingConnectionFactory; /** * Configuration for Artemis {@link ConnectionFactory}. @@ -41,12 +43,46 @@ @ConditionalOnMissingBean(ConnectionFactory.class) class ArtemisConnectionFactoryConfiguration { - @Bean + @Configuration @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false", matchIfMissing = true) - public ActiveMQConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, - ArtemisProperties properties) { - return new ArtemisConnectionFactoryFactory(beanFactory, properties) - .createConnectionFactory(ActiveMQConnectionFactory.class); + static class SimpleConnectionFactoryConfiguration { + + private final JmsProperties jmsProperties; + + private final ArtemisProperties properties; + + private final ListableBeanFactory beanFactory; + + SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties, + ArtemisProperties properties, ListableBeanFactory beanFactory) { + this.jmsProperties = jmsProperties; + this.properties = properties; + this.beanFactory = beanFactory; + } + + @Bean + @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true) + public CachingConnectionFactory cachingJmsConnectionFactory() { + JmsProperties.Cache cacheProperties = this.jmsProperties.getCache(); + CachingConnectionFactory connectionFactory = new CachingConnectionFactory( + createConnectionFactory()); + connectionFactory.setCacheConsumers(cacheProperties.isConsumers()); + connectionFactory.setCacheProducers(cacheProperties.isProducers()); + connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize()); + return connectionFactory; + } + + @Bean + @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false") + public ActiveMQConnectionFactory jmsConnectionFactory() { + return createConnectionFactory(); + } + + private ActiveMQConnectionFactory createConnectionFactory() { + return new ArtemisConnectionFactoryFactory(this.beanFactory, this.properties) + .createConnectionFactory(ActiveMQConnectionFactory.class); + } + } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java index 849a9e7c649e..552afb6b9dcf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java @@ -40,6 +40,7 @@ import org.springframework.jms.config.JmsListenerContainerFactory; import org.springframework.jms.config.JmsListenerEndpoint; import org.springframework.jms.config.SimpleJmsListenerContainerFactory; +import org.springframework.jms.connection.CachingConnectionFactory; import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.listener.DefaultMessageListenerContainer; @@ -74,15 +75,17 @@ public void testDefaultJmsConfiguration() { } private void testDefaultJmsConfiguration(AssertableApplicationContext loaded) { - ActiveMQConnectionFactory factory = loaded - .getBean(ActiveMQConnectionFactory.class); + assertThat(loaded).hasSingleBean(ConnectionFactory.class); + assertThat(loaded).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory factory = loaded.getBean(CachingConnectionFactory.class); + assertThat(factory.getTargetConnectionFactory()) + .isInstanceOf(ActiveMQConnectionFactory.class); JmsTemplate jmsTemplate = loaded.getBean(JmsTemplate.class); JmsMessagingTemplate messagingTemplate = loaded .getBean(JmsMessagingTemplate.class); assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); assertThat(messagingTemplate.getJmsTemplate()).isEqualTo(jmsTemplate); - assertThat(((ActiveMQConnectionFactory) jmsTemplate.getConnectionFactory()) - .getBrokerURL()).isEqualTo(ACTIVEMQ_EMBEDDED_URL); + assertThat(getBrokerUrl(factory)).isEqualTo(ACTIVEMQ_EMBEDDED_URL); assertThat(loaded.containsBean("jmsListenerContainerFactory")).isTrue(); } @@ -313,9 +316,10 @@ public void testPubSubDomainActive() { public void testPubSubDomainOverride() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.jms.pubSubDomain:false").run((context) -> { + assertThat(context).hasSingleBean(JmsTemplate.class); + assertThat(context).hasSingleBean(ConnectionFactory.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); + ConnectionFactory factory = context.getBean(ConnectionFactory.class); assertThat(jmsTemplate).isNotNull(); assertThat(jmsTemplate.isPubSubDomain()).isFalse(); assertThat(factory).isNotNull() @@ -327,15 +331,13 @@ public void testPubSubDomainOverride() { public void testActiveMQOverriddenStandalone() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.activemq.inMemory:false").run((context) -> { + assertThat(context).hasSingleBean(JmsTemplate.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertThat(jmsTemplate).isNotNull(); - assertThat(factory).isNotNull() - .isEqualTo(jmsTemplate.getConnectionFactory()); - assertThat(((ActiveMQConnectionFactory) jmsTemplate - .getConnectionFactory()).getBrokerURL()) - .isEqualTo(ACTIVEMQ_NETWORK_URL); + ConnectionFactory factory = context.getBean(ConnectionFactory.class); + assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); + assertThat(getBrokerUrl((CachingConnectionFactory) factory)) + .isEqualTo(ACTIVEMQ_NETWORK_URL); }); } @@ -344,18 +346,23 @@ public void testActiveMQOverriddenRemoteHost() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.activemq.brokerUrl:tcp://remote-host:10000") .run((context) -> { + assertThat(context).hasSingleBean(JmsTemplate.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertThat(jmsTemplate).isNotNull(); - assertThat(factory).isNotNull(); + ConnectionFactory factory = context.getBean(ConnectionFactory.class); assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); - assertThat(((ActiveMQConnectionFactory) jmsTemplate - .getConnectionFactory()).getBrokerURL()) - .isEqualTo("tcp://remote-host:10000"); + assertThat(getBrokerUrl((CachingConnectionFactory) factory)) + .isEqualTo("tcp://remote-host:10000"); }); } + private String getBrokerUrl(CachingConnectionFactory connectionFactory) { + assertThat(connectionFactory.getTargetConnectionFactory()) + .isInstanceOf(ActiveMQConnectionFactory.class); + return ((ActiveMQConnectionFactory) connectionFactory + .getTargetConnectionFactory()).getBrokerURL(); + } + @Test public void testActiveMQOverriddenPool() { this.contextRunner.withUserConfiguration(TestConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java index a1337dc94d18..c65009f40824 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java @@ -27,6 +27,8 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.jms.connection.CachingConnectionFactory; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -50,10 +52,13 @@ public class ActiveMQAutoConfigurationTests { public void brokerIsEmbeddedByDefault() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .run((context) -> { - assertThat(context).getBean(ConnectionFactory.class) + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory cachingConnectionFactory = context + .getBean(CachingConnectionFactory.class); + assertThat(cachingConnectionFactory.getTargetConnectionFactory()) .isInstanceOf(ActiveMQConnectionFactory.class); - assertThat(context.getBean(ActiveMQConnectionFactory.class) - .getBrokerURL()) + assertThat(((ActiveMQConnectionFactory) cachingConnectionFactory + .getTargetConnectionFactory()).getBrokerURL()) .isEqualTo("vm://localhost?broker.persistent=false"); }); } @@ -68,10 +73,46 @@ public void configurationBacksOffWhenCustomConnectionFactoryExists() { } @Test - public void defaultConnectionFactoryIsApplied() { + public void connectionFactoryIsCachedByDefault() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) - .withPropertyValues("spring.activemq.pool.enabled=false") .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory connectionFactory = context + .getBean(CachingConnectionFactory.class); + assertThat(connectionFactory.getTargetConnectionFactory()) + .isInstanceOf(ActiveMQConnectionFactory.class); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheConsumers")).isEqualTo(false); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheProducers")).isEqualTo(true); + assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1); + }); + } + + @Test + public void connectionFactoryCachingCanBeCustomized() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.jms.cache.consumers=true", + "spring.jms.cache.producers=false", + "spring.jms.cache.session-cache-size=10") + .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory connectionFactory = context + .getBean(CachingConnectionFactory.class); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheConsumers")).isEqualTo(true); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheProducers")).isEqualTo(false); + assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10); + }); + } + + @Test + public void connectionFactoryCachingCanBeDisabled() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.jms.cache.enabled=false").run((context) -> { assertThat(context.getBeansOfType(ActiveMQConnectionFactory.class)) .hasSize(1); ActiveMQConnectionFactory connectionFactory = context @@ -99,7 +140,7 @@ public void defaultConnectionFactoryIsApplied() { @Test public void customConnectionFactoryIsApplied() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) - .withPropertyValues("spring.activemq.pool.enabled=false", + .withPropertyValues("spring.jms.cache.enabled=false", "spring.activemq.brokerUrl=vm://localhost?useJmx=false&broker.persistent=false", "spring.activemq.user=foo", "spring.activemq.password=bar", "spring.activemq.closeTimeout=500", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java index 25b015aee442..df581ab612a2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java @@ -48,10 +48,12 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.jms.connection.CachingConnectionFactory; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.SessionCallback; import org.springframework.jms.support.destination.DestinationResolver; import org.springframework.jms.support.destination.DynamicDestinationResolver; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -70,17 +72,69 @@ public class ArtemisAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class, JmsAutoConfiguration.class)); + @Test + public void connectionFactoryIsCachedByDefault() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory connectionFactory = context + .getBean(CachingConnectionFactory.class); + assertThat(connectionFactory.getTargetConnectionFactory()) + .isInstanceOf(ActiveMQConnectionFactory.class); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheConsumers")).isEqualTo(false); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheProducers")).isEqualTo(true); + assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1); + }); + } + + @Test + public void connectionFactoryCachingCanBeCustomized() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.jms.cache.consumers=true", + "spring.jms.cache.producers=false", + "spring.jms.cache.session-cache-size=10") + .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class); + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory connectionFactory = context + .getBean(CachingConnectionFactory.class); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheConsumers")).isEqualTo(true); + assertThat(ReflectionTestUtils.getField(connectionFactory, + "cacheProducers")).isEqualTo(false); + assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10); + }); + } + + @Test + public void connectionFactoryCachingCanBeDisabled() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.jms.cache.enabled=false").run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class); + assertThat(context).doesNotHaveBean(CachingConnectionFactory.class); + assertThat(context.getBean(ConnectionFactory.class)) + .isInstanceOf(ActiveMQConnectionFactory.class); + }); + } + @Test public void nativeConnectionFactory() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .withPropertyValues("spring.artemis.mode:native").run((context) -> { JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); - assertNettyConnectionFactory(factory, "localhost", 61616); - assertThat(factory.getUser()).isNull(); - assertThat(factory.getPassword()).isNull(); + ConnectionFactory connectionFactory = context + .getBean(ConnectionFactory.class); + assertThat(connectionFactory) + .isEqualTo(jmsTemplate.getConnectionFactory()); + ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory( + connectionFactory); + assertNettyConnectionFactory(activeMQConnectionFactory, "localhost", + 61616); + assertThat(activeMQConnectionFactory.getUser()).isNull(); + assertThat(activeMQConnectionFactory.getPassword()).isNull(); }); } @@ -90,9 +144,10 @@ public void nativeConnectionFactoryCustomHost() { .withPropertyValues("spring.artemis.mode:native", "spring.artemis.host:192.168.1.144", "spring.artemis.port:9876") .run((context) -> { - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertNettyConnectionFactory(factory, "192.168.1.144", 9876); + assertNettyConnectionFactory( + getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class)), + "192.168.1.144", 9876); }); } @@ -103,12 +158,17 @@ public void nativeConnectionFactoryCredentials() { "spring.artemis.user:user", "spring.artemis.password:secret") .run((context) -> { JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); - assertNettyConnectionFactory(factory, "localhost", 61616); - assertThat(factory.getUser()).isEqualTo("user"); - assertThat(factory.getPassword()).isEqualTo("secret"); + ConnectionFactory connectionFactory = context + .getBean(ConnectionFactory.class); + assertThat(connectionFactory) + .isEqualTo(jmsTemplate.getConnectionFactory()); + ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory( + connectionFactory); + assertNettyConnectionFactory(activeMQConnectionFactory, "localhost", + 61616); + assertThat(activeMQConnectionFactory.getUser()).isEqualTo("user"); + assertThat(activeMQConnectionFactory.getPassword()) + .isEqualTo("secret"); }); } @@ -125,9 +185,8 @@ public void embeddedConnectionFactory() { org.apache.activemq.artemis.core.config.Configuration.class); assertThat(configuration.isPersistenceEnabled()).isFalse(); assertThat(configuration.isSecurityEnabled()).isFalse(); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertInVmConnectionFactory(factory); + assertInVmConnectionFactory(getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class))); }); } @@ -142,9 +201,8 @@ public void embeddedConnectionFactoryByDefault() { org.apache.activemq.artemis.core.config.Configuration.class); assertThat(configuration.isPersistenceEnabled()).isFalse(); assertThat(configuration.isSecurityEnabled()).isFalse(); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertInVmConnectionFactory(factory); + assertInVmConnectionFactory(getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class))); }); } @@ -155,9 +213,10 @@ public void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() { .withPropertyValues("spring.artemis.embedded.enabled:false") .run((context) -> { assertThat(context).doesNotHaveBean(EmbeddedJMS.class); - ActiveMQConnectionFactory factory = context - .getBean(ActiveMQConnectionFactory.class); - assertNettyConnectionFactory(factory, "localhost", 61616); + assertNettyConnectionFactory( + getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class)), + "localhost", 61616); }); } @@ -169,9 +228,8 @@ public void embeddedConnectionFactoryEvenIfEmbeddedServiceDisabled() { "spring.artemis.embedded.enabled:false") .run((context) -> { assertThat(context.getBeansOfType(EmbeddedJMS.class)).isEmpty(); - ActiveMQConnectionFactory connectionFactory = context - .getBean(ActiveMQConnectionFactory.class); - assertInVmConnectionFactory(connectionFactory); + assertInVmConnectionFactory(getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class))); }); } @@ -374,6 +432,13 @@ public void pooledConnectionFactoryConfiguration() { }); } + private ActiveMQConnectionFactory getActiveMQConnectionFactory( + ConnectionFactory connectionFactory) { + assertThat(connectionFactory).isInstanceOf(CachingConnectionFactory.class); + return (ActiveMQConnectionFactory) ((CachingConnectionFactory) connectionFactory) + .getTargetConnectionFactory(); + } + private TransportConfiguration assertInVmConnectionFactory( ActiveMQConnectionFactory connectionFactory) { TransportConfiguration transportConfig = getSingleTransportConfiguration( diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 8d27a4099642..b51a13af0bcf 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -995,6 +995,10 @@ content into your application. Rather, pick only the properties that you need. spring.integration.jdbc.schema=classpath:org/springframework/integration/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema. # JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties]) + spring.jms.cache.consumers=false # Whether to cache message consumers. + spring.jms.cache.enabled=true # Whether to cache sessions. + spring.jms.cache.producers=true # Whether to cache message producers. + spring.jms.cache.session-cache-size=1 # Size of the session cache (per JMS Session type). spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations. spring.jms.listener.acknowledge-mode= # Acknowledge mode of the container. By default, the listener is transacted with automatic acknowledgment. spring.jms.listener.auto-startup=true # Start the container automatically on startup. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 57b690451a83..f67b0b7fef6c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5065,7 +5065,16 @@ ActiveMQ configuration is controlled by external configuration properties in spring.activemq.password=secret ---- -You can also pool JMS resources by adding a dependency to +By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with +sensible settings that you can control by external configuration properties in +`+spring.jms.*+`: + +[source,properties,indent=0] +---- + spring.jms.cache.session-cache-size=5 +---- + +If you'd rather use native pooling, you can do so by adding a dependency to `org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` accordingly, as shown in the following example: @@ -5122,7 +5131,16 @@ list to create them with the default options, or you can define bean(s) of type `org.apache.activemq.artemis.jms.server.config.TopicConfiguration`, for advanced queue and topic configurations, respectively. -You can also pool JMS resources by adding a dependency to +By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with +sensible settings that you can control by external configuration properties in +`+spring.jms.*+`: + +[source,properties,indent=0] +---- + spring.jms.cache.session-cache-size=5 +---- + +If you'd rather use native pooling, you can do so by adding a dependency to `org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` accordingly, as shown in the following example: From cc894ce4f21c0ffe4306793819ee74cc9862f462 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 19 Jun 2018 16:05:40 +0200 Subject: [PATCH 138/701] Fix Micrometer tag providers after HttpStatus changes Since SPR-16898, `HttpStatus.toString()` has changed and we should instead rely on `HttpStatus.value()` to get the HTTP status number. --- .../metrics/web/reactive/client/WebClientExchangeTags.java | 2 +- .../boot/actuate/metrics/web/reactive/server/WebFluxTags.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index c70aa216500e..5ffc05009c27 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -83,7 +83,7 @@ private static String extractPath(String url) { * @return the status tag */ public static Tag status(ClientResponse response) { - return Tag.of("status", response.statusCode().toString()); + return Tag.of("status", String.valueOf(response.statusCode().value())); } /** diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java index 5d1fdcd0695e..17b610c269c8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java @@ -69,7 +69,7 @@ public static Tag status(ServerWebExchange exchange) { if (status == null) { status = HttpStatus.OK; } - return Tag.of("status", status.toString()); + return Tag.of("status", String.valueOf(status.value())); } /** From 9d3ba14686deaf66291468457a02b4cc541b23d9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 19 Jun 2018 19:58:48 +0200 Subject: [PATCH 139/701] Fix conditions for CachingConnectionFactory support Closes gh-12161 --- .../spring-boot-actuator-autoconfigure/pom.xml | 5 +++++ .../jms/activemq/ActiveMQConnectionFactoryConfiguration.java | 1 + .../jms/artemis/ArtemisConnectionFactoryConfiguration.java | 1 + 3 files changed, 7 insertions(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index 256ace35bf1d..bd2f32275f8e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -278,6 +278,11 @@ spring-jdbc true + + org.springframework + spring-jms + true + org.springframework spring-messaging diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java index df32566cf48c..1901d140c03e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java @@ -48,6 +48,7 @@ class ActiveMQConnectionFactoryConfiguration { @Configuration + @ConditionalOnClass(CachingConnectionFactory.class) @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true) static class SimpleConnectionFactoryConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java index 97bf6ea0079c..01390df47d0f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java @@ -44,6 +44,7 @@ class ArtemisConnectionFactoryConfiguration { @Configuration + @ConditionalOnClass(CachingConnectionFactory.class) @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false", matchIfMissing = true) static class SimpleConnectionFactoryConfiguration { From 65cc7c72f46e739ccf2d971af2018ff6097a5837 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 19 Jun 2018 17:47:26 +0200 Subject: [PATCH 140/701] Harmonize JNDI lookups to enable resourceRef This commit makes sure that JMS and Mail JNDI lookups behave the same way as DataSource JNDI lookups by enabling the "resourceRef" flag. This will make sure to add "java:comp/env" to the lookup if the JNDI name doesn't already contain it. If that name does not exist, a second attempt to the original name will be issued automatically. Closes gh-12803 --- .../JndiConnectionFactoryAutoConfiguration.java | 7 +++++-- .../mail/MailSenderJndiConfiguration.java | 3 ++- ...ndiConnectionFactoryAutoConfigurationTests.java | 11 ++++++++++- .../mail/MailSenderAutoConfigurationTests.java | 14 ++++++++++++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfiguration.java index bfbacbf481c3..08fcc3f3f41c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfiguration.java @@ -57,14 +57,17 @@ public class JndiConnectionFactoryAutoConfiguration { private final JmsProperties properties; + private final JndiLocatorDelegate jndiLocatorDelegate; + public JndiConnectionFactoryAutoConfiguration(JmsProperties properties) { this.properties = properties; + this.jndiLocatorDelegate = JndiLocatorDelegate.createDefaultResourceRefLocator(); } @Bean public ConnectionFactory connectionFactory() throws NamingException { if (StringUtils.hasLength(this.properties.getJndiName())) { - return new JndiLocatorDelegate().lookup(this.properties.getJndiName(), + return this.jndiLocatorDelegate.lookup(this.properties.getJndiName(), ConnectionFactory.class); } return findJndiConnectionFactory(); @@ -73,7 +76,7 @@ public ConnectionFactory connectionFactory() throws NamingException { private ConnectionFactory findJndiConnectionFactory() { for (String name : JNDI_LOCATIONS) { try { - return new JndiLocatorDelegate().lookup(name, ConnectionFactory.class); + return this.jndiLocatorDelegate.lookup(name, ConnectionFactory.class); } catch (NamingException ex) { // Swallow and continue diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderJndiConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderJndiConfiguration.java index 0c9c8cacb2c8..052f222936c5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderJndiConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderJndiConfiguration.java @@ -60,7 +60,8 @@ public JavaMailSenderImpl mailSender(Session session) { public Session session() { String jndiName = this.properties.getJndiName(); try { - return new JndiLocatorDelegate().lookup(jndiName, Session.class); + return JndiLocatorDelegate.createDefaultResourceRefLocator().lookup(jndiName, + Session.class); } catch (NamingException ex) { throw new IllegalStateException( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfigurationTests.java index 800746ee02aa..89c6e775a02c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JndiConnectionFactoryAutoConfigurationTests.java @@ -93,7 +93,16 @@ public void detectWithXAConnectionFactory() { @Test public void jndiNamePropertySet() { - ConnectionFactory connectionFactory = configureConnectionFactory("myCF"); + ConnectionFactory connectionFactory = configureConnectionFactory( + "java:comp/env/myCF"); + this.contextRunner.withPropertyValues("spring.jms.jndi-name=java:comp/env/myCF") + .run(assertConnectionFactory(connectionFactory)); + } + + @Test + public void jndiNamePropertySetWithResourceRef() { + ConnectionFactory connectionFactory = configureConnectionFactory( + "java:comp/env/myCF"); this.contextRunner.withPropertyValues("spring.jms.jndi-name=myCF") .run(assertConnectionFactory(connectionFactory)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java index 1d6cd71929ff..5c5881aa41ea 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java @@ -150,8 +150,18 @@ public void mailSenderBackOff() { @Test public void jndiSessionAvailable() { - Session session = configureJndiSession("foo"); - this.contextRunner.withPropertyValues("spring.mail.jndi-name:foo") + Session session = configureJndiSession("java:comp/env/foo"); + testJndiSessionLookup(session, "java:comp/env/foo"); + } + + @Test + public void jndiSessionAvailableWithResourceRef() { + Session session = configureJndiSession("java:comp/env/foo"); + testJndiSessionLookup(session, "foo"); + } + + private void testJndiSessionLookup(Session session, String jndiName) { + this.contextRunner.withPropertyValues("spring.mail.jndi-name:" + jndiName) .run((context) -> { assertThat(context).hasSingleBean(Session.class); Session sessionBean = context.getBean(Session.class); From 8b35d06cf6112bc51135c0d3496e7f712de021f6 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 20 Jun 2018 09:28:00 +0200 Subject: [PATCH 141/701] Share RetryTemplate infrastructure for Rabbit listener and template Closes gh-13529 --- ...bitListenerContainerFactoryConfigurer.java | 5 +- .../amqp/RabbitAutoConfiguration.java | 22 +------- .../amqp/RetryTemplateFactory.java | 50 +++++++++++++++++++ 3 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java index 8475293207f0..989a43bbe53f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java @@ -107,9 +107,8 @@ protected void configure(T factory, ConnectionFactory connectionFactory, RetryInterceptorBuilder builder = (retryConfig.isStateless() ? RetryInterceptorBuilder.stateless() : RetryInterceptorBuilder.stateful()); - builder.maxAttempts(retryConfig.getMaxAttempts()); - builder.backOffOptions(retryConfig.getInitialInterval().toMillis(), - retryConfig.getMultiplier(), retryConfig.getMaxInterval().toMillis()); + builder.retryOperations( + new RetryTemplateFactory().createRetryTemplate(retryConfig)); MessageRecoverer recoverer = (this.messageRecoverer != null ? this.messageRecoverer : new RejectAndDontRequeueRecoverer()); builder.recoverer(recoverer); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index d08d1b2c76e7..2895a5f8a4a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -40,9 +40,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.retry.backoff.ExponentialBackOffPolicy; -import org.springframework.retry.policy.SimpleRetryPolicy; -import org.springframework.retry.support.RetryTemplate; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}. @@ -178,7 +175,8 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { template.setMandatory(determineMandatoryFlag()); RabbitProperties.Template properties = this.properties.getTemplate(); if (properties.getRetry().isEnabled()) { - template.setRetryTemplate(createRetryTemplate(properties.getRetry())); + template.setRetryTemplate(new RetryTemplateFactory() + .createRetryTemplate(properties.getRetry())); } map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis) .to(template::setReceiveTimeout); @@ -194,22 +192,6 @@ private boolean determineMandatoryFlag() { return (mandatory != null ? mandatory : this.properties.isPublisherReturns()); } - private RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) { - PropertyMapper map = PropertyMapper.get(); - RetryTemplate template = new RetryTemplate(); - SimpleRetryPolicy policy = new SimpleRetryPolicy(); - map.from(properties::getMaxAttempts).to(policy::setMaxAttempts); - template.setRetryPolicy(policy); - ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); - map.from(properties::getInitialInterval).whenNonNull().as(Duration::toMillis) - .to(backOffPolicy::setInitialInterval); - map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier); - map.from(properties::getMaxInterval).whenNonNull().as(Duration::toMillis) - .to(backOffPolicy::setMaxInterval); - template.setBackOffPolicy(backOffPolicy); - return template; - } - @Bean @ConditionalOnSingleCandidate(ConnectionFactory.class) @ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java new file mode 100644 index 000000000000..a98adca394e0 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2018 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.autoconfigure.amqp; + +import java.time.Duration; + +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.retry.backoff.ExponentialBackOffPolicy; +import org.springframework.retry.policy.SimpleRetryPolicy; +import org.springframework.retry.support.RetryTemplate; + +/** + * Factory to create {@link RetryTemplate} instance from properties defined in + * {@link RabbitProperties}. + * + * @author Stephane Nicoll + */ +class RetryTemplateFactory { + + public RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) { + PropertyMapper map = PropertyMapper.get(); + RetryTemplate template = new RetryTemplate(); + SimpleRetryPolicy policy = new SimpleRetryPolicy(); + map.from(properties::getMaxAttempts).to(policy::setMaxAttempts); + template.setRetryPolicy(policy); + ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); + map.from(properties::getInitialInterval).whenNonNull().as(Duration::toMillis) + .to(backOffPolicy::setInitialInterval); + map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier); + map.from(properties::getMaxInterval).whenNonNull().as(Duration::toMillis) + .to(backOffPolicy::setMaxInterval); + template.setBackOffPolicy(backOffPolicy); + return template; + } + +} From bb60edaca62a9a6e96f258cd3c87e72ea99501a7 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 21 Jun 2018 05:32:09 +0900 Subject: [PATCH 142/701] Polish Closes gh-13534 --- .../endpoint/condition/ConditionalOnEnabledEndpoint.java | 2 +- .../reactive/WebClientMetricsAutoConfigurationTests.java | 4 ++-- .../autoconfigure/jackson/JacksonAutoConfiguration.java | 4 ++-- .../boot/autoconfigure/orm/jpa/HibernateProperties.java | 2 +- .../src/main/asciidoc/production-ready-features.adoc | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java index 3d6e8b954329..a61d12e505c8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnEnabledEndpoint.java @@ -68,7 +68,7 @@ * *
  * @EndpointWebExtension(endpoint = MyEndpoint.class)
- * class MyEndpointWebExtension {
+ * public class MyEndpointWebExtension {
  *
  * }
*

diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java index 16b036329eac..d32efe9c64b7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java @@ -83,7 +83,7 @@ public void shouldNotOverrideCustomTagsProvider() { this.contextRunner.withUserConfiguration(CustomTagsProviderConfig.class) .run((context) -> assertThat(context) .getBeans(WebClientExchangeTagsProvider.class).hasSize(1) - .containsKey("customTagProvider")); + .containsKey("customTagsProvider")); } @Test @@ -113,7 +113,7 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { protected static class CustomTagsProviderConfig { @Bean - public WebClientExchangeTagsProvider customTagProvider() { + public WebClientExchangeTagsProvider customTagsProvider() { return mock(WebClientExchangeTagsProvider.class); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index 9e72b7c07c89..cc83ef5cab2e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -270,8 +270,8 @@ private void configureFeatures(Jackson2ObjectMapperBuilder builder, } private void configureVisibility(Jackson2ObjectMapperBuilder builder, - Map accessors) { - accessors.forEach(builder::visibility); + Map visibilities) { + visibilities.forEach(builder::visibility); } private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index eb56d17fec8e..13e1112a97c3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -80,7 +80,7 @@ public Naming getNaming() { * Determine the configuration properties for the initialization of the main Hibernate * EntityManagerFactory based on standard JPA properties and * {@link HibernateSettings}. - * @param jpaProperties standard jpa properties + * @param jpaProperties standard JPA properties * @param settings the settings to apply when determining the configuration properties * @return the Hibernate properties to use */ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index fecf705dcbf9..7790ae1ca1cf 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1867,8 +1867,8 @@ include::{code-examples}/actuate/metrics/MetricsFilterBeanExample.java[tag=confi [[production-ready-metrics-common-tags]] ==== Common tags -Common tag are generally used for dimensional drill-down on the operating environment like -host, instance, region, stack, etc. Commons tags applied to all meters and can be +Common tags are generally used for dimensional drill-down on the operating environment like +host, instance, region, stack, etc. Commons tags are applied to all meters and can be configured as shown in the following example: [source,properties,indent=0] @@ -1877,7 +1877,7 @@ configured as shown in the following example: management.metrics.tags.stack=prod ---- -The example above adds a `region` and `stack` tags to all meters with a value of +The example above adds `region` and `stack` tags to all meters with a value of `us-east-1` and `prod` respectively. NOTE: The order of common tags is important if you are using Graphite. As the order of From 56a7aa552f04b9b9276255c278346ce5b8686567 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 21 Jun 2018 10:40:33 +0200 Subject: [PATCH 143/701] Polish --- .../boot/autoconfigure/web/ResourceProperties.java | 4 ++-- .../asciidoc/appendix-application-properties.adoc | 11 +++++------ .../boot/jta/atomikos/AtomikosProperties.java | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java index 491b1ffdc9e0..17e83d472cc3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ResourceProperties.java @@ -112,8 +112,8 @@ public static class Chain { private boolean htmlApplicationCache = false; /** - * Whether to enable resolution of already compressed resources. Checks for a - * resource name with the '.gz' or '.br' file extensions. + * Whether to enable resolution of already compressed resources (gzip, brotli). + * Checks for a resource name with the '.gz' or '.br' file extensions. */ private boolean compressed = false; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b51a13af0bcf..c38d4b996916 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -80,7 +80,7 @@ content into your application. Rather, pick only the properties that you need. spring.cache.jcache.provider= # Fully qualified name of the CachingProvider implementation to use to retrieve the JSR-107 compliant cache manager. Needed only if more than one JSR-107 implementation is available on the classpath. spring.cache.redis.cache-null-values=true # Allow caching null values. spring.cache.redis.key-prefix= # Key prefix. - spring.cache.redis.time-to-live=0ms # Entry expiration. By default the entries never expire. + spring.cache.redis.time-to-live= # Entry expiration. By default the entries never expire. spring.cache.redis.use-key-prefix=true # Whether to use the key prefix when writing to Redis. spring.cache.type= # Cache type. By default, auto-detected according to the environment. @@ -499,7 +499,6 @@ content into your application. Rather, pick only the properties that you need. spring.webservices.wsdl-locations= # Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans. - [[common-application-properties-security]] # ---------------------------------------- # SECURITY PROPERTIES # ---------------------------------------- @@ -543,7 +542,7 @@ content into your application. Rather, pick only the properties that you need. spring.flyway.placeholder-suffix= # spring.flyway.placeholders.*= # spring.flyway.repeatable-sql-migration-prefix= # - spring.flyway.schemas= # schemas to update + spring.flyway.schemas= # Schemas to update. spring.flyway.skip-default-callbacks= # spring.flyway.skip-default-resolvers= # spring.flyway.sql-migration-prefix=V # @@ -721,9 +720,9 @@ content into your application. Rather, pick only the properties that you need. spring.elasticsearch.jest.username= # Login username. # Elasticsearch REST clients ({sc-spring-boot-autoconfigure}/elasticsearch/rest/RestClientProperties.{sc-ext}[RestClientProperties]) - spring.elasticsearch.rest.password= # Credentials username. + spring.elasticsearch.rest.password= # Credentials password. spring.elasticsearch.rest.uris=http://localhost:9200 # Comma-separated list of the Elasticsearch instances to use. - spring.elasticsearch.rest.username= # Credentials password. + spring.elasticsearch.rest.username= # Credentials username. # H2 Web Console ({sc-spring-boot-autoconfigure}/h2/H2ConsoleProperties.{sc-ext}[H2ConsoleProperties]) spring.h2.console.enabled=false # Whether to enable the console. @@ -1346,7 +1345,7 @@ content into your application. Rather, pick only the properties that you need. management.metrics.binders.logback.enabled=true # Whether to enable Logback metrics. management.metrics.binders.processor.enabled=true # Whether to enable processor metrics. management.metrics.binders.uptime.enabled=true # Whether to enable uptime metrics. - management.metrics.distribution.percentiles-histogram.*= # Whether meter IDs starting-with the specified name should be publish percentile histograms. + management.metrics.distribution.percentiles-histogram.*= # Whether meter IDs starting with the specified name should publish percentile histograms. management.metrics.distribution.percentiles.*= # Specific computed non-aggregable percentiles to ship to the backend for meter IDs starting-with the specified name. management.metrics.distribution.sla.*= # Specific SLA boundaries for meter IDs starting-with the specified name. The longest match wins, the key `all` can also be used to configure all meters. management.metrics.enable.*= # Whether meter IDs starting-with the specified name should be enabled. The longest match wins, the key `all` can also be used to configure all meters. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java index 3ab135647972..65f100e830a8 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java @@ -100,7 +100,7 @@ public class AtomikosProperties { /** * Interval between checkpoints, expressed as the number of log writes between two - * checkpoint. A checkpoint reduces the log file size at the expense of adding some + * checkpoints. A checkpoint reduces the log file size at the expense of adding some * overhead in the runtime. */ private long checkpointInterval = 500; From a097f923c1a096090535ef21e23a27fba5edfc07 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 22 Jun 2018 12:25:35 +0100 Subject: [PATCH 144/701] Provide sensible defaults for launch script properties when using Gradle Closes gh-4458 --- .../src/main/asciidoc/deployment.adoc | 79 +++++++++++----- .../boot/gradle/tasks/bundling/BootJar.java | 2 +- .../boot/gradle/tasks/bundling/BootWar.java | 2 +- .../bundling/LaunchScriptConfiguration.java | 36 +++++++ .../bundling/AbstractBootArchiveTests.java | 35 +++++-- .../LaunchScriptConfigurationTests.java | 93 +++++++++++++++++++ 6 files changed, 211 insertions(+), 36 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfigurationTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/deployment.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/deployment.adoc index 055505a945ca..6bbae5b915b2 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/deployment.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/deployment.adoc @@ -678,69 +678,98 @@ Spring Boot Maven or Gradle plugins. The following property substitutions are supported with the default script: -[cols="1,6"] +[cols="1,3,3,3"] |=== -|Name |Description +|Name |Description |Gradle default |Maven default |`mode` -|The script mode. Defaults to `auto`. +|The script mode. +|`auto` +|`auto` |`initInfoProvides` -|The `Provides` section of "`INIT INFO`". Defaults to `spring-boot-application` for Gradle - and to `${project.artifactId}` for Maven. +|The `Provides` section of "`INIT INFO`" +|`${task.baseName}` +|`${project.artifactId}` |`initInfoRequiredStart` -|The `Required-Start` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`. +|`Required-Start` section of "`INIT INFO`". +|`$remote_fs $syslog $network` +|`$remote_fs $syslog $network` |`initInfoRequiredStop` -|The `Required-Stop` section of "`INIT INFO`". Defaults to `$remote_fs $syslog $network`. - +|`Required-Stop` section of "`INIT INFO`". +|`$remote_fs $syslog $network` +|`$remote_fs $syslog $network` |`initInfoDefaultStart` -|The `Default-Start` section of "`INIT INFO`". Defaults to `2 3 4 5`. +|`Default-Start` section of "`INIT INFO`". +|`2 3 4 5` +|`2 3 4 5` |`initInfoDefaultStop` -|The `Default-Stop` section of "`INIT INFO`". Defaults to `0 1 6`. +|`Default-Stop` section of "`INIT INFO`". +|`0 1 6` +|`0 1 6` |`initInfoShortDescription` -|The `Short-Description` section of "`INIT INFO`". Defaults to `Spring Boot Application` -for Gradle and to `${project.name}` for Maven. +|`Short-Description` section of "`INIT INFO`". +|Single-line version of `${project.description}` (falling back to `${task.baseName}`) +|`${project.name}` |`initInfoDescription` -|The `Description` section of "`INIT INFO`". Defaults to `Spring Boot Application` for - Gradle and to `${project.description}` (falling back to `${project.name}`) for Maven. +|`Description` section of "`INIT INFO`". +|`${project.description}` (falling back to `${task.baseName}`) +|`${project.description}` (falling back to `${project.name}`) |`initInfoChkconfig` -|The `chkconfig` section of "`INIT INFO`". Defaults to `2345 99 01`. +|`chkconfig` section of "`INIT INFO`" +|`2345 99 01` +|`2345 99 01` |`confFolder` -|The default value for `CONF_FOLDER`. Defaults to the folder containing the jar. +|The default value for `CONF_FOLDER` +|Folder containing the jar +|Folder containing the jar |`inlinedConfScript` |Reference to a file script that should be inlined in the default launch script. This can be used to set environmental variables such as `JAVA_OPTS` before any external - config files are loaded. + config files are loaded +| +| |`logFolder` -|The default value for `LOG_FOLDER`. Only valid for an `init.d` service. +|Default value for `LOG_FOLDER`. Only valid for an `init.d` service +| +| |`logFilename` -|The default value for `LOG_FILENAME`. Only valid for an `init.d` service. +|Default value for `LOG_FILENAME`. Only valid for an `init.d` service +| +| |`pidFolder` -|The default value for `PID_FOLDER`. Only valid for an `init.d` service. +|Default value for `PID_FOLDER`. Only valid for an `init.d` service +| +| |`pidFilename` -|The default value for the name of the PID file in `PID_FOLDER`. Only valid for an - `init.d` service. +|Default value for the name of the PID file in `PID_FOLDER`. Only valid for an + `init.d` service +| +| |`useStartStopDaemon` |Whether the `start-stop-daemon` command, when it's available, should be used to control - the process. Defaults to `true`. + the process +|`true` +|`true` |`stopWaitTime` -|The default value for `STOP_WAIT_TIME`. Only valid for an `init.d` service. - Defaults to 60 seconds. +|Default value for `STOP_WAIT_TIME` in seconds. Only valid for an `init.d` service +|60 +|60 |=== diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java index e63e83dd25b0..d69e3f846ced 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -184,7 +184,7 @@ protected ZipCompression resolveZipCompression(FileCopyDetails details) { private LaunchScriptConfiguration enableLaunchScriptIfNecessary() { LaunchScriptConfiguration launchScript = this.support.getLaunchScript(); if (launchScript == null) { - launchScript = new LaunchScriptConfiguration(); + launchScript = new LaunchScriptConfiguration(this); this.support.setLaunchScript(launchScript); } return launchScript; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java index e6be12492f47..83c1dd8a2b1f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java @@ -162,7 +162,7 @@ protected ZipCompression resolveZipCompression(FileCopyDetails details) { private LaunchScriptConfiguration enableLaunchScriptIfNecessary() { LaunchScriptConfiguration launchScript = this.support.getLaunchScript(); if (launchScript == null) { - launchScript = new LaunchScriptConfiguration(); + launchScript = new LaunchScriptConfiguration(this); this.support.setLaunchScript(launchScript); } return launchScript; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java index 4152e2a8c148..6320939b6279 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java @@ -22,6 +22,9 @@ import java.util.HashMap; import java.util.Map; +import org.gradle.api.Project; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; + import org.springframework.boot.loader.tools.FileUtils; /** @@ -37,6 +40,19 @@ public class LaunchScriptConfiguration implements Serializable { private File script; + public LaunchScriptConfiguration() { + + } + + LaunchScriptConfiguration(AbstractArchiveTask archiveTask) { + Project project = archiveTask.getProject(); + putIfMissing(this.properties, "initInfoProvides", archiveTask.getBaseName()); + putIfMissing(this.properties, "initInfoShortDescription", + removeLineBreaks(project.getDescription()), archiveTask.getBaseName()); + putIfMissing(this.properties, "initInfoDescription", + augmentLineBreaks(project.getDescription()), archiveTask.getBaseName()); + } + /** * Returns the properties that are applied to the launch script when it's being * including in the executable archive. @@ -121,4 +137,24 @@ private boolean equalContents(File one, File two) { } } + private String removeLineBreaks(String string) { + return (string != null ? string.replaceAll("\\s+", " ") : null); + } + + private String augmentLineBreaks(String string) { + return (string != null ? string.replaceAll("\n", "\n# ") : null); + } + + private void putIfMissing(Map properties, String key, + String... valueCandidates) { + if (!properties.containsKey(key)) { + for (String candidate : valueCandidates) { + if (candidate != null && !candidate.isEmpty()) { + properties.put(key, candidate); + return; + } + } + } + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java index 978ce3607821..f3e6c7a6d8c0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java @@ -24,7 +24,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -64,6 +66,8 @@ public abstract class AbstractBootArchiveTests { private final String classesPath; + private Project project; + private T task; protected AbstractBootArchiveTests(Class taskClass, String launcherClass, @@ -77,10 +81,12 @@ protected AbstractBootArchiveTests(Class taskClass, String launcherClass, @Before public void createTask() { try { - Project project = ProjectBuilder.builder() - .withProjectDir(this.temp.newFolder()).build(); + this.project = ProjectBuilder.builder().withProjectDir(this.temp.newFolder()) + .build(); + this.project + .setDescription("Test project for " + this.taskClass.getSimpleName()); this.task = configure( - project.getTasks().create("testArchive", this.taskClass)); + this.project.getTasks().create("testArchive", this.taskClass)); } catch (IOException ex) { throw new RuntimeException(ex); @@ -186,8 +192,12 @@ public void launchScriptCanBePrepended() throws IOException { this.task.setMainClassName("com.example.Main"); this.task.launchScript(); this.task.execute(); + Map properties = new HashMap<>(); + properties.put("initInfoProvides", this.task.getBaseName()); + properties.put("initInfoShortDescription", this.project.getDescription()); + properties.put("initInfoDescription", this.project.getDescription()); assertThat(Files.readAllBytes(this.task.getArchivePath().toPath())) - .startsWith(new DefaultLaunchScript(null, null).toByteArray()); + .startsWith(new DefaultLaunchScript(null, properties).toByteArray()); try { Set permissions = Files .getPosixFilePermissions(this.task.getArchivePath().toPath()); @@ -211,13 +221,20 @@ public void customLaunchScriptCanBePrepended() throws IOException { } @Test - public void launchScriptPropertiesAreReplaced() throws IOException { + public void launchScriptInitInfoPropertiesCanBeCustomized() throws IOException { this.task.setMainClassName("com.example.Main"); - this.task.launchScript((configuration) -> configuration.getProperties() - .put("initInfoProvides", "test property value")); + this.task.launchScript((configuration) -> { + configuration.getProperties().put("initInfoProvides", "provides"); + configuration.getProperties().put("initInfoShortDescription", + "short description"); + configuration.getProperties().put("initInfoDescription", "description"); + }); this.task.execute(); - assertThat(Files.readAllBytes(this.task.getArchivePath().toPath())) - .containsSequence("test property value".getBytes()); + byte[] bytes = Files.readAllBytes(this.task.getArchivePath().toPath()); + assertThat(bytes).containsSequence("Provides: provides".getBytes()); + assertThat(bytes) + .containsSequence("Short-Description: short description".getBytes()); + assertThat(bytes).containsSequence("Description: description".getBytes()); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfigurationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfigurationTests.java new file mode 100644 index 000000000000..43fcbcd97d8d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfigurationTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-2018 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.gradle.tasks.bundling; + +import org.gradle.api.Project; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link LaunchScriptConfiguration}. + * + * @author Andy Wilkinson + */ +public class LaunchScriptConfigurationTests { + + private final AbstractArchiveTask task = mock(AbstractArchiveTask.class); + + private final Project project = mock(Project.class); + + @Before + public void setUp() { + given(this.task.getProject()).willReturn(this.project); + } + + @Test + public void initInfoProvidesUsesArchiveBaseNameByDefault() { + given(this.task.getBaseName()).willReturn("base-name"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoProvides", "base-name"); + } + + @Test + public void initInfoShortDescriptionUsesDescriptionByDefault() { + given(this.project.getDescription()).willReturn("Project description"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoShortDescription", "Project description"); + } + + @Test + public void initInfoShortDescriptionUsesArchiveBaseNameWhenDescriptionIsNull() { + given(this.task.getBaseName()).willReturn("base-name"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoShortDescription", "base-name"); + } + + @Test + public void initInfoShortDescriptionUsesSingleLineVersionOfMultiLineProjectDescription() { + given(this.project.getDescription()).willReturn("Project\ndescription"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoShortDescription", "Project description"); + } + + @Test + public void initInfoDescriptionUsesArchiveBaseNameWhenDescriptionIsNull() { + given(this.task.getBaseName()).willReturn("base-name"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoDescription", "base-name"); + } + + @Test + public void initInfoDescriptionUsesProjectDescriptionByDefault() { + given(this.project.getDescription()).willReturn("Project description"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoDescription", "Project description"); + } + + @Test + public void initInfoDescriptionUsesCorrectlyFormattedMultiLineProjectDescription() { + given(this.project.getDescription()).willReturn("The\nproject\ndescription"); + assertThat(new LaunchScriptConfiguration(this.task).getProperties()) + .containsEntry("initInfoDescription", "The\n# project\n# description"); + } + +} From 9281e2a410bb493d59448f9c3249af0c3a34ed46 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 25 Jun 2018 17:35:30 +0100 Subject: [PATCH 145/701] Avoid creating JsonParser for VCAP_* parsing when running outside CF Closes gh-13437 --- ...oudFoundryVcapEnvironmentPostProcessor.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java index 5a7afea4aa68..4425eb29ba91 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java @@ -101,8 +101,6 @@ public class CloudFoundryVcapEnvironmentPostProcessor // Before ConfigFileApplicationListener so values there can use these ones private int order = ConfigFileApplicationListener.DEFAULT_ORDER - 1; - private final JsonParser parser = JsonParserFactory.getJsonParser(); - public void setOrder(int order) { this.order = order; } @@ -117,9 +115,11 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) { Properties properties = new Properties(); - addWithPrefix(properties, getPropertiesFromApplication(environment), + JsonParser jsonParser = JsonParserFactory.getJsonParser(); + addWithPrefix(properties, + getPropertiesFromApplication(environment, jsonParser), "vcap.application."); - addWithPrefix(properties, getPropertiesFromServices(environment), + addWithPrefix(properties, getPropertiesFromServices(environment, jsonParser), "vcap.services."); MutablePropertySources propertySources = environment.getPropertySources(); if (propertySources.contains( @@ -142,11 +142,12 @@ private void addWithPrefix(Properties properties, Properties other, String prefi } } - private Properties getPropertiesFromApplication(Environment environment) { + private Properties getPropertiesFromApplication(Environment environment, + JsonParser parser) { Properties properties = new Properties(); try { String property = environment.getProperty(VCAP_APPLICATION, "{}"); - Map map = this.parser.parseMap(property); + Map map = parser.parseMap(property); extractPropertiesFromApplication(properties, map); } catch (Exception ex) { @@ -155,11 +156,12 @@ private Properties getPropertiesFromApplication(Environment environment) { return properties; } - private Properties getPropertiesFromServices(Environment environment) { + private Properties getPropertiesFromServices(Environment environment, + JsonParser parser) { Properties properties = new Properties(); try { String property = environment.getProperty(VCAP_SERVICES, "{}"); - Map map = this.parser.parseMap(property); + Map map = parser.parseMap(property); extractPropertiesFromServices(properties, map); } catch (Exception ex) { From ca0de4385c01cbbd120e96ec9f83427fb48c9a15 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 26 Jun 2018 16:51:47 +0100 Subject: [PATCH 146/701] Upgrade to Hibernate 5.3 and JPA 2.2 Closes gh-11725 --- .../spring-boot-dependencies/pom.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e5c583127d1d..2d5a4f8a83ef 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -68,8 +68,7 @@ 1.3 3.10.1 1.2.3 - 5.2.17.Final - 1.0.2.Final + 5.3.1.Final 6.0.10.Final 2.7.9 2.4.1 @@ -90,6 +89,7 @@ 1.0 1.6.1 1.0.3 + 2.2 1.2 2.0.1.Final 1.1.6 @@ -1027,6 +1027,11 @@ javax.mail-api ${javax-mail.version} + + javax.persistence + javax.persistence-api + ${javax-persistence.version} + javax.money money-api @@ -1898,11 +1903,6 @@ hibernate-testing ${hibernate.version} - - org.hibernate.javax.persistence - hibernate-jpa-2.1-api - ${hibernate-jpa-2.1-api.version} - org.hibernate.validator hibernate-validator From f8186ce0ee16b6b02d4aefde3865d786a1559d88 Mon Sep 17 00:00:00 2001 From: Phil Webb Date: Tue, 26 Jun 2018 16:50:17 -0700 Subject: [PATCH 147/701] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c58da9ec1f6c..f1163e8854cc 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,7 +3,7 @@ Thanks for raising a Spring Boot issue. Please take the time to review the follo categories as some of them do not apply here. ❓Question -Please ask questions about how to use something, or to understand why something isn't +STOP!! Please ask questions about how to use something, or to understand why something isn't working as you expect it to, on Stack Overflow using the spring-boot tag. 🐞 Bug report From b4cd4f4c435c19bedc34e3e327801cdffe3406bd Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Jun 2018 10:51:58 +0100 Subject: [PATCH 148/701] Stop mocking class that is final in latest Framework 5.1 snapshots --- .../test/web/client/RootUriRequestExpectationManagerTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/RootUriRequestExpectationManagerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/RootUriRequestExpectationManagerTests.java index d4bc3151429a..e850d8312f0e 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/RootUriRequestExpectationManagerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/RootUriRequestExpectationManagerTests.java @@ -86,7 +86,7 @@ public void createWhenExpectationManagerIsNullShouldThrowException() { @Test public void expectRequestShouldDelegateToExpectationManager() { - ExpectedCount count = mock(ExpectedCount.class); + ExpectedCount count = ExpectedCount.once(); RequestMatcher requestMatcher = mock(RequestMatcher.class); this.manager.expectRequest(count, requestMatcher); verify(this.delegate).expectRequest(count, requestMatcher); From 45fdf2ffa4b4fd9e30300975d2015357e243892e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 29 May 2018 16:52:44 +0100 Subject: [PATCH 149/701] Support Tomcat 9 and Undertow 2 Closes gh-11749 Closes gh-12243 --- .../spring-boot-dependencies/pom.xml | 6 +++--- .../src/main/asciidoc/getting-started.adoc | 8 ++++---- .../src/main/asciidoc/howto.adoc | 20 ++++++++++--------- .../main/asciidoc/spring-boot-features.adoc | 6 +++--- .../spring-boot-starter-jetty/pom.xml | 1 + .../spring-boot-starter-undertow/pom.xml | 2 +- .../springframework/boot/maven/Verify.java | 6 +++--- .../TomcatServletWebServerFactoryTests.java | 4 +--- .../spring-boot-sample-jetty-jsp/pom.xml | 1 + .../spring-boot-sample-jetty-ssl/pom.xml | 1 + .../spring-boot-sample-jetty/pom.xml | 1 + 11 files changed, 30 insertions(+), 26 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2d5a4f8a83ef..6bda2aa9d519 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -147,7 +147,7 @@ 3.9.1 2.29.3 4.1.2 - 3.1.0 + 4.0.1 1.7.25 1.19 7.2.1 @@ -175,9 +175,9 @@ 2.3.0 2.0.1 3.0.1.RELEASE - 8.5.31 + 9.0.10 4.0.6 - 1.4.25.Final + 2.0.9.Final 3325375 0.35 1.6.3 diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc index 62bffbcab9c6..6f5b5e0f00c4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc @@ -51,14 +51,14 @@ Spring Boot supports the following embedded servlet containers: |=== |Name |Servlet Version -|Tomcat 8.5 -|3.1 +|Tomcat 9.0 +|4.0 |Jetty 9.4 |3.1 -|Undertow 1.4 -|3.1 +|Undertow 2.0 +|4.0 |=== You can also deploy Spring Boot applications to any Servlet 3.1+ compatible container. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 0d83beb63631..4c057478235b 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -523,6 +523,9 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp [source,xml,indent=0,subs="verbatim,quotes,attributes"] ---- + + 3.1.0 + org.springframework.boot spring-boot-starter-web @@ -541,6 +544,9 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp ---- +NOTE: The version of the Servlet API has been overridden as, unlike Tomcat 9 and Undertow +2.0, Jetty 9.4 does not support Servlet 4.0. + The following Gradle example shows how to exclude Netty and include Undertow for Spring WebFlux: @@ -727,16 +733,16 @@ To enable that support, your application needs to have two additional dependenci [[howto-configure-http2-tomcat]] ==== HTTP/2 with Tomcat -Spring Boot ships by default with Tomcat 8.5.x. With that version, HTTP/2 is only -supported if the `libtcnative` library and its dependencies are installed on the host -operating system. +Spring Boot ships by default with Tomcat 9.0.x which supports HTTP/2 out of the box when +using JDK 9 or later. Alternatively, HTTP/2 can be used on JDK 8 if the `libtcnative` +library and its dependencies are installed on the host operating system. The library folder must be made available, if not already, to the JVM library path. You can do so with a JVM argument such as `-Djava.library.path=/usr/local/opt/tomcat-native/lib`. More on this in the -https://tomcat.apache.org/tomcat-8.5-doc/apr.html[official Tomcat documentation]. +https://tomcat.apache.org/tomcat-9.0-doc/apr.html[official Tomcat documentation]. -Starting Tomcat 8.5.x without that native support logs the following error: +Starting Tomcat 9.0.x on JDK 8 without that native support logs the following error: [indent=0,subs="attributes"] ---- @@ -745,10 +751,6 @@ Starting Tomcat 8.5.x without that native support logs the following error: This error is not fatal, and the application still starts with HTTP/1.1 SSL support. -Running your application with Tomcat 9.0.x and JDK9 does not require any native library to -be installed. To use Tomcat 9, you can override the `tomcat.version` build property with -the version of your choice. - [[howto-configure-webserver]] diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index b1262bf30424..638354c1a8a9 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -7409,9 +7409,9 @@ include::{test-examples}/web/client/SampleWebClientTests.java[tag=test] [[boot-features-websockets]] == WebSockets -Spring Boot provides WebSockets auto-configuration for embedded Tomcat 8.5, Jetty -9, and Undertow. If you deploy a war file to a standalone container, Spring Boot assumes -that the container is responsible for the configuration of its WebSocket support. +Spring Boot provides WebSockets auto-configuration for embedded Tomcat, Jetty, and +Undertow. If you deploy a war file to a standalone container, Spring Boot assumes that the +container is responsible for the configuration of its WebSocket support. Spring Framework provides {spring-reference}web.html#websocket[rich WebSocket support] that can be easily accessed through the `spring-boot-starter-websocket` module. diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/pom.xml index 537da2c67844..0d8fc32869ff 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-jetty/pom.xml @@ -13,6 +13,7 @@ alternative to spring-boot-starter-tomcat ${basedir}/../../.. + 3.1.0 diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-undertow/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-undertow/pom.xml index c29c6bbc2ce1..7c1162b5cf62 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-undertow/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-undertow/pom.xml @@ -25,7 +25,7 @@ org.jboss.spec.javax.servlet - jboss-servlet-api_3.1_spec + jboss-servlet-api_4.0_spec diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java index 982feecff61a..3121e1bf7dd4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java @@ -230,7 +230,7 @@ protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { super.verifyZipEntries(verifier); verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/spring-context"); verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/spring-core"); - verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/javax.servlet-api-3"); + verifier.assertHasEntryNameStartingWith("BOOT-INF/lib/javax.servlet-api-4"); assertThat(verifier .hasEntry("org/springframework/boot/loader/JarLauncher.class")) .as("Unpacked launcher classes").isTrue(); @@ -263,7 +263,7 @@ protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { verifier.assertHasEntryNameStartingWith("WEB-INF/lib/spring-context"); verifier.assertHasEntryNameStartingWith("WEB-INF/lib/spring-core"); verifier.assertHasEntryNameStartingWith( - "WEB-INF/lib-provided/javax.servlet-api-3"); + "WEB-INF/lib-provided/javax.servlet-api-4"); assertThat(verifier .hasEntry("org/" + "springframework/boot/loader/JarLauncher.class")) .as("Unpacked launcher classes").isTrue(); @@ -314,7 +314,7 @@ protected void verifyZipEntries(ArchiveVerifier verifier) throws Exception { super.verifyZipEntries(verifier); verifier.assertHasEntryNameStartingWith("lib/spring-context"); verifier.assertHasEntryNameStartingWith("lib/spring-core"); - verifier.assertHasNoEntryNameStartingWith("lib/javax.servlet-api-3"); + verifier.assertHasNoEntryNameStartingWith("lib/javax.servlet-api"); assertThat(verifier .hasEntry("org/" + "springframework/boot/loader/JarLauncher.class")) .as("Unpacked launcher classes").isFalse(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index 6ab1dfd77329..c2b894d2d94b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -63,7 +63,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -181,8 +180,7 @@ public void tomcatAdditionalConnectors() { TomcatServletWebServerFactory factory = getFactory(); Connector[] listeners = new Connector[4]; for (int i = 0; i < listeners.length; i++) { - Connector connector = mock(Connector.class); - given(connector.getState()).willReturn(LifecycleState.STOPPED); + Connector connector = new Connector(); listeners[i] = connector; } factory.addAdditionalTomcatConnectors(listeners); diff --git a/spring-boot-samples/spring-boot-sample-jetty-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-jetty-jsp/pom.xml index e208d3a8862a..a2ddaa620d6e 100644 --- a/spring-boot-samples/spring-boot-sample-jetty-jsp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jetty-jsp/pom.xml @@ -15,6 +15,7 @@ ${basedir}/../.. / + 3.1.0 diff --git a/spring-boot-samples/spring-boot-sample-jetty-ssl/pom.xml b/spring-boot-samples/spring-boot-sample-jetty-ssl/pom.xml index 05468a45b355..169415278938 100644 --- a/spring-boot-samples/spring-boot-sample-jetty-ssl/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jetty-ssl/pom.xml @@ -13,6 +13,7 @@ Spring Boot Jetty SSL Sample ${basedir}/../.. + 3.1.0 diff --git a/spring-boot-samples/spring-boot-sample-jetty/pom.xml b/spring-boot-samples/spring-boot-sample-jetty/pom.xml index b5729f797af5..395594a74714 100644 --- a/spring-boot-samples/spring-boot-sample-jetty/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jetty/pom.xml @@ -13,6 +13,7 @@ Spring Boot Jetty Sample ${basedir}/../.. + 3.1.0 From d641249ca8de59e60ce954f695d9bff8155eccb9 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sat, 30 Jun 2018 18:55:20 +0200 Subject: [PATCH 150/701] Fix deprecation warning in SpringPhysicalNamingStrategyTests Closes gh-13623 --- .../SpringPhysicalNamingStrategyTests.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/orm/jpa/hibernate/SpringPhysicalNamingStrategyTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/orm/jpa/hibernate/SpringPhysicalNamingStrategyTests.java index 38fe9c27a3af..de33a148732e 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/orm/jpa/hibernate/SpringPhysicalNamingStrategyTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/orm/jpa/hibernate/SpringPhysicalNamingStrategyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,14 +18,12 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.H2Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.mapping.PersistentClass; -import org.hibernate.service.ServiceRegistry; import org.junit.Before; import org.junit.Test; @@ -43,20 +41,16 @@ public class SpringPhysicalNamingStrategyTests { private MetadataSources metadataSources; - private StandardServiceRegistry serviceRegistry; - @Before public void setup() { - this.metadataSources = new MetadataSources(); + this.metadataSources = new MetadataSources(createServiceRegistry()); this.metadataSources.addAnnotatedClass(TelephoneNumber.class); - this.serviceRegistry = getServiceRegistry(this.metadataSources); - this.metadata = this.metadataSources.getMetadataBuilder(this.serviceRegistry) + this.metadata = this.metadataSources.getMetadataBuilder() .applyPhysicalNamingStrategy(new SpringPhysicalNamingStrategy()).build(); } - private StandardServiceRegistry getServiceRegistry(MetadataSources metadataSources) { - ServiceRegistry registry = metadataSources.getServiceRegistry(); - return new StandardServiceRegistryBuilder((BootstrapServiceRegistry) registry) + private StandardServiceRegistry createServiceRegistry() { + return new StandardServiceRegistryBuilder() .applySetting(AvailableSettings.DIALECT, H2Dialect.class).build(); } @@ -69,7 +63,7 @@ public void tableNameShouldBeLowercaseUnderscore() { @Test public void tableNameShouldNotBeLowerCaseIfCaseSensitive() { - this.metadata = this.metadataSources.getMetadataBuilder(this.serviceRegistry) + this.metadata = this.metadataSources.getMetadataBuilder() .applyPhysicalNamingStrategy(new TestSpringPhysicalNamingStrategy()) .build(); PersistentClass binding = this.metadata From 205fa2507b019f5e1348f6bc554fdd18691152ba Mon Sep 17 00:00:00 2001 From: Karl Heinz Marbaise Date: Sun, 1 Jul 2018 16:41:37 +0200 Subject: [PATCH 151/701] Remove maven-eclipse-plugin as it has been retired Closes gh-13631 --- spring-boot-project/spring-boot-dependencies/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6bda2aa9d519..68de4b8ef1be 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -193,7 +193,6 @@ 3.7.0 3.0.2 2.8.2 - 2.10 3.0.0-M1 2.22.0 2.5.2 @@ -2912,11 +2911,6 @@ maven-dependency-plugin ${maven-dependency-plugin.version} - - org.apache.maven.plugins - maven-eclipse-plugin - ${maven-eclipse-plugin.version} - org.apache.maven.plugins maven-enforcer-plugin From 0d3b49cd9577b3711c65dcf00b34dd878686a93c Mon Sep 17 00:00:00 2001 From: Karl Heinz Marbaise Date: Sun, 1 Jul 2018 16:31:07 +0200 Subject: [PATCH 152/701] Upgrade to Maven War Plugin 3.2.2 Closes gh-13629 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 68de4b8ef1be..dc1f6dbc9eca 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -205,7 +205,7 @@ 3.6 3.0.1 2.22.0 - 3.1.0 + 3.2.2 2.3 1.0.1 1.0.0 From 11c635671f97c2586ea8780ad5073880251479a3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:32:57 +0100 Subject: [PATCH 153/701] Upgrade to Rxjava2 2.1.16 Closes gh-13642 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index a788fa38e299..beb691ea4a82 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -143,7 +143,7 @@ 1.0.2 1.3.8 1.2.1 - 2.1.14 + 2.1.16 3.9.1 2.29.3 4.1.2 From 1301e0885b97fef5d4059fae740185275083ef86 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:32:57 +0100 Subject: [PATCH 154/701] Upgrade to Johnzon Jsonb 1.1.8 Closes gh-13643 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index beb691ea4a82..45a34ececb56 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -107,7 +107,7 @@ 4.5.1 2.9.9 1.5.0 - 1.1.7 + 1.1.8 3.10.7 1.5.0 2.4.0 From 0e601c58cc86c4be2fce40ba6394a693a2eb1b96 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:32:59 +0100 Subject: [PATCH 155/701] Upgrade to Jooq 3.10.8 Closes gh-13645 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 45a34ececb56..31c7115e50c7 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -108,7 +108,7 @@ 2.9.9 1.5.0 1.1.8 - 3.10.7 + 3.10.8 1.5.0 2.4.0 1.2 From 8014b21ad96cf109735e092bb1d4e1c251634064 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:33:00 +0100 Subject: [PATCH 156/701] Upgrade to Maven Enforcer Plugin 3.0.0-M2 Closes gh-13646 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 31c7115e50c7..c3ef3738fd66 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -193,7 +193,7 @@ 3.7.0 3.0.2 2.8.2 - 3.0.0-M1 + 3.0.0-M2 2.22.0 2.5.2 3.1.0 From deee5e63a6a8911f6c8ede86a749f3a7b20d9133 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:33:01 +0100 Subject: [PATCH 157/701] Upgrade to Maven Javadoc Plugin 3.0.1 Closes gh-13647 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c3ef3738fd66..d2d84dd883e0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -199,7 +199,7 @@ 3.1.0 2.2 3.0.2 - 3.0.0 + 3.0.1 3.0.1 2.4.3 3.6 From e94aecc5b61e1fefc52b0c1838fb196ebf7f43f5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:33:02 +0100 Subject: [PATCH 158/701] Upgrade to Maven Resources Plugin 3.0.2 Closes gh-13648 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d2d84dd883e0..e93ced5b7132 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -200,7 +200,7 @@ 2.2 3.0.2 3.0.1 - 3.0.1 + 3.0.2 2.4.3 3.6 3.0.1 From 1615b7d128ed96fb78ca4d9886c1a102cc6efa68 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:33:03 +0100 Subject: [PATCH 159/701] Upgrade to Xml Maven Plugin 1.0.2 Closes gh-13649 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e93ced5b7132..aca1573355f9 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -207,7 +207,7 @@ 2.22.0 3.2.2 2.3 - 1.0.1 + 1.0.2 1.0.0 From f7aee36fd454b66c721d0f09b70967e52dc48e09 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:33:04 +0100 Subject: [PATCH 160/701] Upgrade to Flatten Maven Plugin 1.0.1 Closes gh-13650 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index aca1573355f9..fc6f47f27aab 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -208,7 +208,7 @@ 3.2.2 2.3 1.0.2 - 1.0.0 + 1.0.1 From 0827d9791a2463a768e4c69ac6722dcec2126682 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:45:57 +0100 Subject: [PATCH 161/701] Upgrade to Cassandra Driver 3.5.1 Closes gh-13651 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fc6f47f27aab..560a495850b5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -43,7 +43,7 @@ 2.1.4 1.7.11 2.6.2 - 3.5.0 + 3.5.1 1.3.4 1.11 2.2.0 From dbf239be81fddf58684ce4b82baa6d31293b933a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:45:58 +0100 Subject: [PATCH 162/701] Upgrade to Hazelcast 3.10.2 Closes gh-13652 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 560a495850b5..c10c82fe33a6 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -66,7 +66,7 @@ 2.8.5 1.4.197 1.3 - 3.10.1 + 3.10.2 1.2.3 5.3.1.Final 6.0.10.Final From 7e020b3170b84ff8f472ea3a431e2bf4c2c7bedb Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:45:58 +0100 Subject: [PATCH 163/701] Upgrade to Mssql Jdbc 6.4.0.jre8 Closes gh-13653 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c10c82fe33a6..18a5aa30f03c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -127,7 +127,7 @@ 2.18.3 1.9.0-beta1 3.8.0-beta2 - 6.2.2.jre8 + 6.4.0.jre8 5.1.46 5.8.2.Final 1.9.22 From a30f0d9148bdc4be3fee98de9b98593101493a9a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:45:59 +0100 Subject: [PATCH 164/701] Upgrade to Querydsl 4.2.1 Closes gh-13654 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 18a5aa30f03c..30166495ef17 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -136,7 +136,7 @@ 1.1.0 42.2.2 2.3.0 - 4.1.4 + 4.2.1 5.1.2 Californium-BUILD-SNAPSHOT 3.0.7 From 031ad17ac17f244b29a49bf4fec32f32c26d9f80 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:00 +0100 Subject: [PATCH 165/701] Upgrade to Rabbit Amqp Client 5.3.0 Closes gh-13655 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 30166495ef17..55972da52558 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -137,7 +137,7 @@ 42.2.2 2.3.0 4.2.1 - 5.1.2 + 5.3.0 Californium-BUILD-SNAPSHOT 3.0.7 1.0.2 From 49d9f59f1bce8044f055258f6d440aa12282aac3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:01 +0100 Subject: [PATCH 166/701] Upgrade to Sendgrid 4.2.1 Closes gh-13656 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 55972da52558..5d551bff5209 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -146,7 +146,7 @@ 2.1.16 3.9.1 2.29.3 - 4.1.2 + 4.2.1 4.0.1 1.7.25 1.19 From 706945d2ce84e3e7700864be6c6344b63f0dfdbe Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:01 +0100 Subject: [PATCH 167/701] Upgrade to Embedded Mongo 2.1.1 Closes gh-13657 --- .../EmbeddedMongoAutoConfiguration.java | 73 ++----------------- .../spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 6 insertions(+), 69 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 270208161122..4cc10f460f17 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -19,10 +19,8 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; import com.mongodb.MongoClient; import de.flapdoodle.embed.mongo.Command; @@ -37,8 +35,10 @@ import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion; +import de.flapdoodle.embed.mongo.distribution.Versions; import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.io.ProcessOutput; +import de.flapdoodle.embed.process.distribution.GenericVersion; import de.flapdoodle.embed.process.io.Processors; import de.flapdoodle.embed.process.io.Slf4jLevel; import de.flapdoodle.embed.process.io.progress.Slf4jProgressListener; @@ -65,7 +65,6 @@ import org.springframework.core.env.PropertySource; import org.springframework.data.mongodb.core.MongoClientFactoryBean; import org.springframework.data.mongodb.core.ReactiveMongoClientFactoryBean; -import org.springframework.util.Assert; /** * {@link EnableAutoConfiguration Auto-configuration} for Embedded Mongo. @@ -126,9 +125,9 @@ private MongodStarter getMongodStarter(IRuntimeConfig runtimeConfig) { @Bean @ConditionalOnMissingBean public IMongodConfig embeddedMongoConfiguration() throws IOException { - IFeatureAwareVersion featureAwareVersion = new ToStringFriendlyFeatureAwareVersion( - this.embeddedProperties.getVersion(), - this.embeddedProperties.getFeatures()); + IFeatureAwareVersion featureAwareVersion = Versions.withFeatures( + new GenericVersion(this.embeddedProperties.getVersion()), + this.embeddedProperties.getFeatures().toArray(new Feature[0])); MongodConfigBuilder builder = new MongodConfigBuilder() .version(featureAwareVersion); if (this.embeddedProperties.getStorage() != null) { @@ -242,66 +241,4 @@ public EmbeddedReactiveMongoDependencyConfiguration() { } - /** - * A workaround for the lack of a {@code toString} implementation on - * {@code GenericFeatureAwareVersion}. - */ - private static final class ToStringFriendlyFeatureAwareVersion - implements IFeatureAwareVersion { - - private final String version; - - private final Set features; - - private ToStringFriendlyFeatureAwareVersion(String version, - Set features) { - Assert.notNull(version, "version must not be null"); - this.version = version; - this.features = (features != null ? features : Collections.emptySet()); - } - - @Override - public String asInDownloadPath() { - return this.version; - } - - @Override - public boolean enabled(Feature feature) { - return this.features.contains(feature); - } - - @Override - public String toString() { - return this.version; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + this.features.hashCode(); - result = prime * result + this.version.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() == obj.getClass()) { - ToStringFriendlyFeatureAwareVersion other = (ToStringFriendlyFeatureAwareVersion) obj; - boolean equals = true; - equals = equals && this.features.equals(other.features); - equals = equals && this.version.equals(other.version); - return equals; - } - return super.equals(obj); - } - - } - } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5d551bff5209..f3f9cfaa9f79 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -57,7 +57,7 @@ 3.2.6 2.10.5 3.5.2 - 2.0.3 + 2.1.1 5.0.7 2.3.28 6.2.4 From c94d8b19785dbb36815dc6c59b083d0b8efb9ed3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:02 +0100 Subject: [PATCH 168/701] Upgrade to Rest Assured 3.1.0 Closes gh-13658 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f3f9cfaa9f79..021df67cdf64 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -139,7 +139,7 @@ 4.2.1 5.3.0 Californium-BUILD-SNAPSHOT - 3.0.7 + 3.1.0 1.0.2 1.3.8 1.2.1 From 7fb62af8bd7a5f48b7bd87975fcf44af72598809 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:03 +0100 Subject: [PATCH 169/701] Upgrade to Javax Transaction 1.3 Closes gh-13659 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 021df67cdf64..c4e140050555 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -90,7 +90,7 @@ 1.6.1 1.0.3 2.2 - 1.2 + 1.3 2.0.1.Final 1.1.6 3.0.4 From c21a6c59a94a38364253c60e82139d135521e164 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:03 +0100 Subject: [PATCH 170/701] Upgrade to Joda Time 2.10 Closes gh-13660 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c4e140050555..76a2fe7a7a48 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -105,7 +105,7 @@ 8.5.24.2 1.14 4.5.1 - 2.9.9 + 2.10 1.5.0 1.1.8 3.10.8 From 5a85b7dbb7356303aece72b50a2a1d8ea92ef980 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:04 +0100 Subject: [PATCH 171/701] Upgrade to Byte Buddy 1.8.12 Closes gh-13661 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 76a2fe7a7a48..0e81213979c4 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -41,7 +41,7 @@ 3.9.1 4.0.6 2.1.4 - 1.7.11 + 1.8.12 2.6.2 3.5.1 1.3.4 From fbcc92dc7da6d71a419e3909116044dbdc038703 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:05 +0100 Subject: [PATCH 172/701] Upgrade to Htmlunit 2.31 Closes gh-13662 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0e81213979c4..5d19a972b837 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -72,7 +72,7 @@ 6.0.10.Final 2.7.9 2.4.1 - 2.29 + 2.31 4.1.3 4.5.5 4.4.10 From 304598e4bc0a0efc41796df4a24f9c3b98a83f11 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:06 +0100 Subject: [PATCH 173/701] Upgrade to Artemis 2.6.2 Closes gh-13663 --- .../jms/artemis/ArtemisEmbeddedConfigurationFactory.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java index ea12be48b28c..d232fb31e0e9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedConfigurationFactory.java @@ -83,7 +83,7 @@ private CoreAddressConfiguration createAddressConfiguration(String name) { return new CoreAddressConfiguration().setName(name) .addRoutingType(RoutingType.ANYCAST) .addQueueConfiguration(new CoreQueueConfiguration().setName(name) - .setRoutingType(RoutingType.ANYCAST)); + .setRoutingType(RoutingType.ANYCAST).setAddress(name)); } private String getDataDir() { diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5d19a972b837..b9327271d6db 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -36,7 +36,7 @@ 5.15.4 2.7.7 1.9.64 - 2.4.0 + 2.6.2 1.9.0 3.9.1 4.0.6 @@ -1339,7 +1339,12 @@ org.apache.activemq artemis-server - ${artemis.version} + ${artemis.version} + + commons-logging + commons-logging + + org.apache.activemq From 53cb3d86410ea44c5393104ba61a7a945c63a041 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:07 +0100 Subject: [PATCH 174/701] Upgrade to Commons Dbcp2 2.4.0 Closes gh-13664 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b9327271d6db..c6e4f4faa417 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -46,7 +46,7 @@ 3.5.1 1.3.4 1.11 - 2.2.0 + 2.4.0 3.7 1.6 2.5.0 From d80181c550ec4423e66b27ecd25440e1ca1052d0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:08 +0100 Subject: [PATCH 175/701] Upgrade to Derby 10.14.2.0 Closes gh-13665 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c6e4f4faa417..804f9ca06d7c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -52,7 +52,7 @@ 2.5.0 2.5.9 2.1.0 - 10.14.1.0 + 10.14.2.0 1.6.1 3.2.6 2.10.5 From 13d53c0a33a02352c46fafbe5e6dcb62b7461f51 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:08 +0100 Subject: [PATCH 176/701] Upgrade to Log4j2 2.11.0 Closes gh-13666 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 804f9ca06d7c..cf6924e2c902 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -119,7 +119,7 @@ 1.2.41 5.1.0.M1 3.6.1 - 2.10.0 + 2.11.0 1.2.3 1.16.22 2.2.5 From 1d4ec56b080ebbccfeb08c4b94e00ee22c766f0c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:09 +0100 Subject: [PATCH 177/701] Upgrade to Solr 7.4.0 Closes gh-13667 --- .../boot/autoconfigure/solr/SolrAutoConfiguration.java | 7 +++++-- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java index 7a669b5455c9..c661ae820256 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java @@ -16,6 +16,9 @@ package org.springframework.boot.autoconfigure.solr; +import java.util.Arrays; +import java.util.Optional; + import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; @@ -56,8 +59,8 @@ public SolrClient solrClient() { private SolrClient createSolrClient() { if (StringUtils.hasText(this.properties.getZkHost())) { - return new CloudSolrClient.Builder().withZkHost(this.properties.getZkHost()) - .build(); + return new CloudSolrClient.Builder(Arrays.asList(this.properties.getZkHost()), + Optional.empty()).build(); } return new HttpSolrClient.Builder(this.properties.getHost()).build(); } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index cf6924e2c902..ddfdc14ffcc0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -150,7 +150,7 @@ 4.0.1 1.7.25 1.19 - 7.2.1 + 7.4.0 5.1.0.BUILD-SNAPSHOT 2.0.4.RELEASE 4.0.1.RELEASE From cbcde741b192154cec491444a51e43a62f6d0b08 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:10 +0100 Subject: [PATCH 178/701] Upgrade to Aspectj 1.9.1 Closes gh-13668 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index ddfdc14ffcc0..8fb604a3e7a8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -37,7 +37,7 @@ 2.7.7 1.9.64 2.6.2 - 1.9.0 + 1.9.1 3.9.1 4.0.6 2.1.4 From 2f303f3e5bf292e2f5af0bef13a17b58405720ed Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:11 +0100 Subject: [PATCH 179/701] Upgrade to Assertj 3.10.0 Closes gh-13669 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8fb604a3e7a8..b0cbb23ed5bd 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -38,7 +38,7 @@ 1.9.64 2.6.2 1.9.1 - 3.9.1 + 3.10.0 4.0.6 2.1.4 1.8.12 From e4869a71bedd1b311f4d4ec1ad702b2e765815d7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:12 +0100 Subject: [PATCH 180/701] Upgrade to Groovy 2.5.0 Closes gh-13670 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b0cbb23ed5bd..cdb4e509e7a2 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -62,7 +62,7 @@ 2.3.28 6.2.4 3.0.0 - 2.4.15 + 2.5.0 2.8.5 1.4.197 1.3 From 234804745033017a223db240ae4fd0dc95f70b39 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:12 +0100 Subject: [PATCH 181/701] Upgrade to Elasticsearch 6.3.0 Closes gh-13671 --- spring-boot-project/spring-boot-autoconfigure/pom.xml | 5 +++++ spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index b731062d0c26..ad95125becfb 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -750,6 +750,11 @@ johnzon-jsonb test + + org.apache.logging.log4j + log4j-core + test + org.apache.tomcat.embed tomcat-embed-jasper diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index cdb4e509e7a2..3152c662c99c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -60,7 +60,7 @@ 2.1.1 5.0.7 2.3.28 - 6.2.4 + 6.3.0 3.0.0 2.5.0 2.8.5 From b6b37c91bb4e20f84f6ee347c98e0e1a6c0d98b7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:13 +0100 Subject: [PATCH 182/701] Upgrade to Flyway 5.1.3 Closes gh-13672 --- .../test/resources/db/migration/V1__init.sql | 1 + .../test/resources/db/migration/V1__init.sql | 1 + .../flyway/FlywayAutoConfiguration.java | 23 ++++- .../flyway/FlywayAutoConfigurationTests.java | 85 ++++++++++++++++--- .../test/resources/db/migration/V1__init.sql | 1 + .../test/resources/db/vendors/h2/V1__init.sql | 1 + .../spring-boot-dependencies/pom.xml | 2 +- .../src/main/asciidoc/howto.adoc | 7 +- 8 files changed, 104 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/db/migration/V1__init.sql b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/db/migration/V1__init.sql index e69de29bb2d1..867c7c24f526 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/db/migration/V1__init.sql +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/resources/db/migration/V1__init.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS TEST; diff --git a/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V1__init.sql b/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V1__init.sql index e69de29bb2d1..867c7c24f526 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V1__init.sql +++ b/spring-boot-project/spring-boot-actuator/src/test/resources/db/migration/V1__init.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS TEST; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index a93adbc15a6c..d593ccc4df6d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -29,6 +29,7 @@ import org.flywaydb.core.Flyway; import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.callback.Callback; import org.flywaydb.core.api.callback.FlywayCallback; import org.springframework.beans.factory.ObjectProvider; @@ -71,6 +72,7 @@ * @author Dominic Gunn * @since 1.1.0 */ +@SuppressWarnings("deprecation") @Configuration @ConditionalOnClass(Flyway.class) @ConditionalOnBean(DataSource.class) @@ -109,13 +111,16 @@ public static class FlywayConfiguration { private final FlywayMigrationStrategy migrationStrategy; - private List flywayCallbacks; + private final List callbacks; + + private final List flywayCallbacks; public FlywayConfiguration(FlywayProperties properties, DataSourceProperties dataSourceProperties, ResourceLoader resourceLoader, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, ObjectProvider migrationStrategy, + ObjectProvider> callbacks, ObjectProvider> flywayCallbacks) { this.properties = properties; this.dataSourceProperties = dataSourceProperties; @@ -123,6 +128,7 @@ public FlywayConfiguration(FlywayProperties properties, this.dataSource = dataSource.getIfUnique(); this.flywayDataSource = flywayDataSource.getIfAvailable(); this.migrationStrategy = migrationStrategy.getIfAvailable(); + this.callbacks = callbacks.getIfAvailable(Collections::emptyList); this.flywayCallbacks = flywayCallbacks.getIfAvailable(Collections::emptyList); } @@ -146,7 +152,20 @@ else if (this.flywayDataSource != null) { else { flyway.setDataSource(this.dataSource); } - flyway.setCallbacks(this.flywayCallbacks.toArray(new FlywayCallback[0])); + if (this.flywayCallbacks.isEmpty()) { + flyway.setCallbacks(this.callbacks.toArray(new Callback[0])); + } + else { + if (this.callbacks.isEmpty()) { + flyway.setCallbacks( + this.flywayCallbacks.toArray(new FlywayCallback[0])); + } + else { + throw new IllegalStateException( + "Found a mixture of Callback and FlywayCallback beans." + + " One type must be used exclusively."); + } + } String[] locations = new LocationResolver(flyway.getDataSource()) .resolveLocations(this.properties.getLocations()); checkLocationExists(locations); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java index 90f2e8b864ca..507381985336 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfigurationTests.java @@ -24,7 +24,11 @@ import javax.sql.DataSource; import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.Location; import org.flywaydb.core.api.MigrationVersion; +import org.flywaydb.core.api.callback.Callback; +import org.flywaydb.core.api.callback.Context; +import org.flywaydb.core.api.callback.Event; import org.flywaydb.core.api.callback.FlywayCallback; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.junit.Test; @@ -48,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; @@ -62,6 +67,7 @@ * @author Stephane Nicoll * @author Dominic Gunn */ +@SuppressWarnings("deprecation") public class FlywayAutoConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() @@ -137,7 +143,7 @@ public void defaultFlyway() { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getLocations()) - .containsExactly("classpath:db/migration"); + .containsExactly(new Location("classpath:db/migration")); }); } @@ -150,7 +156,8 @@ public void overrideLocations() { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getLocations()).containsExactly( - "classpath:db/changelog", "classpath:db/migration"); + new Location("classpath:db/changelog"), + new Location("classpath:db/migration")); }); } @@ -163,7 +170,8 @@ public void overrideLocationsList() { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getLocations()).containsExactly( - "classpath:db/changelog", "classpath:db/migration"); + new Location("classpath:db/changelog"), + new Location("classpath:db/migration")); }); } @@ -278,7 +286,8 @@ public void useVendorDirectory() { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getLocations()).containsExactlyInAnyOrder( - "classpath:db/vendors/h2", "classpath:db/changelog"); + new Location("classpath:db/vendors/h2"), + new Location("classpath:db/changelog")); }); } @@ -291,7 +300,7 @@ public void useOneLocationWithVendorDirectory() { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); assertThat(flyway.getLocations()) - .containsExactly("classpath:db/vendors/h2"); + .containsExactly(new Location("classpath:db/vendors/h2")); }); } @@ -301,14 +310,31 @@ public void callbacksAreConfiguredAndOrdered() { CallbackConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(Flyway.class); Flyway flyway = context.getBean(Flyway.class); - FlywayCallback callbackOne = context.getBean("callbackOne", - FlywayCallback.class); - FlywayCallback callbackTwo = context.getBean("callbackTwo", - FlywayCallback.class); + Callback callbackOne = context.getBean("callbackOne", Callback.class); + Callback callbackTwo = context.getBean("callbackTwo", Callback.class); assertThat(flyway.getCallbacks()).hasSize(2); assertThat(flyway.getCallbacks()).containsExactly(callbackTwo, callbackOne); InOrder orderedCallbacks = inOrder(callbackOne, callbackTwo); + orderedCallbacks.verify(callbackTwo).handle(any(Event.class), + any(Context.class)); + orderedCallbacks.verify(callbackOne).handle(any(Event.class), + any(Context.class)); + }); + } + + @Test + public void legacyCallbacksAreConfiguredAndOrdered() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, + LegacyCallbackConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Flyway.class); + Flyway flyway = context.getBean(Flyway.class); + FlywayCallback callbackOne = context.getBean("legacyCallbackOne", + FlywayCallback.class); + FlywayCallback callbackTwo = context.getBean("legacyCallbackTwo", + FlywayCallback.class); + assertThat(flyway.getCallbacks()).hasSize(2); + InOrder orderedCallbacks = inOrder(callbackOne, callbackTwo); orderedCallbacks.verify(callbackTwo) .beforeMigrate(any(Connection.class)); orderedCallbacks.verify(callbackOne) @@ -316,6 +342,19 @@ public void callbacksAreConfiguredAndOrdered() { }); } + @Test + public void callbacksAndLegacyCallbacksCannotBeMixed() { + this.contextRunner + .withUserConfiguration(EmbeddedDataSourceConfiguration.class, + LegacyCallbackConfiguration.class, CallbackConfiguration.class) + .run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()).hasMessageContaining( + "Found a mixture of Callback and FlywayCallback beans." + + " One type must be used exclusively."); + }); + } + @Configuration protected static class FlywayDataSourceConfiguration { @@ -395,13 +434,37 @@ static class CallbackConfiguration { @Bean @Order(1) - public FlywayCallback callbackOne() { + public Callback callbackOne() { + return mockCallback(); + } + + @Bean + @Order(0) + public Callback callbackTwo() { + return mockCallback(); + } + + private Callback mockCallback() { + Callback callback = mock(Callback.class); + given(callback.supports(any(Event.class), any(Context.class))) + .willReturn(true); + return callback; + } + + } + + @Configuration + static class LegacyCallbackConfiguration { + + @Bean + @Order(1) + public FlywayCallback legacyCallbackOne() { return mock(FlywayCallback.class); } @Bean @Order(0) - public FlywayCallback callbackTwo() { + public FlywayCallback legacyCallbackTwo() { return mock(FlywayCallback.class); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/migration/V1__init.sql b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/migration/V1__init.sql index e69de29bb2d1..867c7c24f526 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/migration/V1__init.sql +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/migration/V1__init.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS TEST; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/vendors/h2/V1__init.sql b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/vendors/h2/V1__init.sql index e69de29bb2d1..867c7c24f526 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/vendors/h2/V1__init.sql +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/db/vendors/h2/V1__init.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS TEST; diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 3152c662c99c..22831bc372d8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -58,7 +58,7 @@ 2.10.5 3.5.2 2.1.1 - 5.0.7 + 5.1.3 2.3.28 6.3.0 3.0.0 diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 4c057478235b..c398792454df 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -2225,9 +2225,10 @@ more control, provide a `@Bean` that implements Flyway supports SQL and Java https://flywaydb.org/documentation/callbacks.html[callbacks]. To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` folder. To use Java-based callbacks, create one or more beans that implement -`FlywayCallback` or, preferably, extend `BaseFlywayCallback`. Any such beans are -automatically registered with `Flyway`. They can be ordered by using `@Order` or by -implementing `Ordered`. +`Callback`. Any such beans are automatically registered with `Flyway`. They can be +ordered by using `@Order` or by implementing `Ordered`. Beans that implement the +deprecated `FlywayCallback` interface can also be detected, however they cannot be used +alongside `Callback` beans. By default, Flyway autowires the (`@Primary`) `DataSource` in your context and uses that for migrations. If you like to use a different `DataSource`, you can create From 9b72a4c1f0d073941eca6640dbfd4e2d7376ccb9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:14 +0100 Subject: [PATCH 183/701] Upgrade to Influxdb Java 2.11 Closes gh-13673 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 22831bc372d8..82b00825259f 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -77,7 +77,7 @@ 4.5.5 4.4.10 9.1.7.Final - 2.9 + 2.11 2.9.6 3.0.8 1.3.2 From fba7ff293cbe4045956db01ae366468ad0094322 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:15 +0100 Subject: [PATCH 184/701] Upgrade to Jolokia 1.6.0 Closes gh-13674 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 82b00825259f..237ccb3231f0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -106,7 +106,7 @@ 1.14 4.5.1 2.10 - 1.5.0 + 1.6.0 1.1.8 3.10.8 1.5.0 From 134edf9f2aba351db5c86e522121ce54784f7d19 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:15 +0100 Subject: [PATCH 185/701] Upgrade to Jooq 3.11.2 Closes gh-13675 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../java/sample/jooq/util/TangleFreeGeneratorStrategy.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 237ccb3231f0..85db62f2cb67 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -108,7 +108,7 @@ 2.10 1.6.0 1.1.8 - 3.10.8 + 3.11.2 1.5.0 2.4.0 1.2 diff --git a/spring-boot-samples/spring-boot-sample-jooq/src/main/java/sample/jooq/util/TangleFreeGeneratorStrategy.java b/spring-boot-samples/spring-boot-sample-jooq/src/main/java/sample/jooq/util/TangleFreeGeneratorStrategy.java index 0dcbb0315150..9bf66785dae9 100644 --- a/spring-boot-samples/spring-boot-sample-jooq/src/main/java/sample/jooq/util/TangleFreeGeneratorStrategy.java +++ b/spring-boot-samples/spring-boot-sample-jooq/src/main/java/sample/jooq/util/TangleFreeGeneratorStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2018 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,8 +16,8 @@ package sample.jooq.util; -import org.jooq.util.DefaultGeneratorStrategy; -import org.jooq.util.Definition; +import org.jooq.codegen.DefaultGeneratorStrategy; +import org.jooq.meta.Definition; /** * Custom {@link DefaultGeneratorStrategy} that doesn't produce tangled packages. Too From d1f441a038acc0a59860cfef654c0fb3522c29cf Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:16 +0100 Subject: [PATCH 186/701] Upgrade to Mockito 2.19.0 Closes gh-13676 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 85db62f2cb67..73896b9721b8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -124,7 +124,7 @@ 1.16.22 2.2.5 1.0.5 - 2.18.3 + 2.19.0 1.9.0-beta1 3.8.0-beta2 6.4.0.jre8 From 757c6a9619bb01b78568a488ca215457a9f63894 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:17 +0100 Subject: [PATCH 187/701] Upgrade to Mongodb 3.8.0 Closes gh-13677 --- .../boot/autoconfigure/mongo/MongoClientFactoryTests.java | 5 +++-- .../boot/autoconfigure/mongo/MongoPropertiesTests.java | 5 +++-- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoClientFactoryTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoClientFactoryTests.java index 1c55322eb170..151e183da856 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoClientFactoryTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoClientFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -133,7 +133,8 @@ private MongoClient createMongoClient(MongoProperties properties, } private List extractServerAddresses(MongoClient client) { - Cluster cluster = (Cluster) ReflectionTestUtils.getField(client, "cluster"); + Cluster cluster = (Cluster) ReflectionTestUtils + .getField(ReflectionTestUtils.getField(client, "delegate"), "cluster"); ClusterSettings clusterSettings = (ClusterSettings) ReflectionTestUtils .getField(cluster, "settings"); return clusterSettings.getHosts(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoPropertiesTests.java index 77a9259b0b0a..a0e94172d83f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -159,7 +159,8 @@ public void noCustomAddressAndNoUriUsesDefaultUri() { } private List extractServerAddresses(MongoClient client) { - Cluster cluster = (Cluster) ReflectionTestUtils.getField(client, "cluster"); + Cluster cluster = (Cluster) ReflectionTestUtils + .getField(ReflectionTestUtils.getField(client, "delegate"), "cluster"); ClusterSettings clusterSettings = (ClusterSettings) ReflectionTestUtils .getField(cluster, "settings"); return clusterSettings.getHosts(); diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 73896b9721b8..52740305d8b5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -126,7 +126,7 @@ 1.0.5 2.19.0 1.9.0-beta1 - 3.8.0-beta2 + 3.8.0 6.4.0.jre8 5.1.46 5.8.2.Final From 373fde9b5d3a0f5ff1aa201523f30eeb55932b5a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:18 +0100 Subject: [PATCH 188/701] Upgrade to Mongo Driver Reactivestreams 1.9.0 Closes gh-13678 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 52740305d8b5..668cd6d4ad73 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -125,7 +125,7 @@ 2.2.5 1.0.5 2.19.0 - 1.9.0-beta1 + 1.9.0 3.8.0 6.4.0.jre8 5.1.46 From fe2749ee7e17edfd61ea6536837cfc2a09aff6ed Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:18 +0100 Subject: [PATCH 189/701] Upgrade to Lombok 1.18.0 Closes gh-13679 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 668cd6d4ad73..c5cd0f8deb68 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -121,7 +121,7 @@ 3.6.1 2.11.0 1.2.3 - 1.16.22 + 1.18.0 2.2.5 1.0.5 2.19.0 From 366899f10cb4883efe76368cb55caaf5b3626eb9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:19 +0100 Subject: [PATCH 190/701] Upgrade to Selenium Htmlunit 2.31.0 Closes gh-13680 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c5cd0f8deb68..1ce63e4ba9f9 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -145,7 +145,7 @@ 1.2.1 2.1.16 3.9.1 - 2.29.3 + 2.31.0 4.2.1 4.0.1 1.7.25 From a79644f25235743c8db962498f50731e46108a70 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:20 +0100 Subject: [PATCH 191/701] Upgrade to Selenium 3.13.0 Closes gh-13681 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1ce63e4ba9f9..5981f618e797 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -144,7 +144,7 @@ 1.3.8 1.2.1 2.1.16 - 3.9.1 + 3.13.0 2.31.0 4.2.1 4.0.1 From 63cddd1b6d878513189f618e3ce944eb1fd5af70 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:21 +0100 Subject: [PATCH 192/701] Upgrade to Sqlite Jdbc 3.23.1 Closes gh-13682 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5981f618e797..5e7a9eb8716b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -166,7 +166,7 @@ 5.1.0.M1 Apple-SR3 3.0.1.RELEASE - 3.21.0.1 + 3.23.1 3.1.0 ${javax-mail.version} 1.4.0 From 099dd0bd931bc760e27a9eeadc2f109af9e785fe Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:21 +0100 Subject: [PATCH 193/701] Upgrade to Xmlunit2 2.6.0 Closes gh-13683 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5e7a9eb8716b..0ce705220e28 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -182,7 +182,7 @@ 0.35 1.6.3 1.4.01 - 2.5.1 + 2.6.0 3.0.0 1.6.0 From 6fa24edf3a7da02e9825b1fc0e4e4620b1091ec1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:22 +0100 Subject: [PATCH 194/701] Upgrade to Snakeyaml 1.21 Closes gh-13684 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0ce705220e28..09439a18fa53 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -149,7 +149,7 @@ 4.2.1 4.0.1 1.7.25 - 1.19 + 1.21 7.4.0 5.1.0.BUILD-SNAPSHOT 2.0.4.RELEASE From dbef33dd2aea646e26ef59490fe5068c3efc1e1e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:23 +0100 Subject: [PATCH 195/701] Upgrade to Maven Clean Plugin 3.1.0 Closes gh-13685 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 09439a18fa53..acbf1e73e932 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -189,7 +189,7 @@ 2.2.4 1.8 3.1.0 - 3.0.0 + 3.1.0 3.7.0 3.0.2 2.8.2 From 4cd0b194abc234bd75f49e98dd80728dc46ec534 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 13:46:24 +0100 Subject: [PATCH 196/701] Upgrade to Maven Dependency Plugin 3.1.1 Closes gh-13686 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index acbf1e73e932..4162e15ad941 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -191,7 +191,7 @@ 3.1.0 3.1.0 3.7.0 - 3.0.2 + 3.1.1 2.8.2 3.0.0-M2 2.22.0 From 18904ec29138080dcfc707b6150dc0069b7a0ac4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:31 +0100 Subject: [PATCH 197/701] Upgrade to Mysql 8.0.11 Closes gh-13688 --- .../boot/autoconfigure/jdbc/DataSourcePropertiesTests.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../java/org/springframework/boot/jdbc/DatabaseDriver.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java index d49dc76dd374..3617fec16b29 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourcePropertiesTests.java @@ -43,7 +43,7 @@ public void determineDriver() { properties.setUrl("jdbc:mysql://mydb"); assertThat(properties.getDriverClassName()).isNull(); assertThat(properties.determineDriverClassName()) - .isEqualTo("com.mysql.jdbc.Driver"); + .isEqualTo("com.mysql.cj.jdbc.Driver"); } @Test diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4162e15ad941..25fea342df99 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -128,7 +128,7 @@ 1.9.0 3.8.0 6.4.0.jre8 - 5.1.46 + 8.0.11 5.8.2.Final 1.9.22 3.1.0 diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java index 1c868f4919ca..669983370e21 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java @@ -67,8 +67,8 @@ public enum DatabaseDriver { /** * MySQL. */ - MYSQL("MySQL", "com.mysql.jdbc.Driver", - "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource", "/* ping */ SELECT 1"), + MYSQL("MySQL", "com.mysql.cj.jdbc.Driver", "com.mysql.cj.jdbc.MysqlXADataSource", + "/* ping */ SELECT 1"), /** * Maria DB. From 2c745aab14ec5f4f51996283dafecdeb7eba12b1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:32 +0100 Subject: [PATCH 198/701] Upgrade to Maven Help Plugin 3.1.0 Closes gh-13689 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 25fea342df99..bd8a0ad87a21 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -197,7 +197,7 @@ 2.22.0 2.5.2 3.1.0 - 2.2 + 3.1.0 3.0.2 3.0.1 3.0.2 From a7351ec734256b0d72133cb7bba320880a8c2294 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:32 +0100 Subject: [PATCH 199/701] Upgrade to Maven Jar Plugin 3.1.0 Closes gh-13690 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index bd8a0ad87a21..2167080bada1 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -198,7 +198,7 @@ 2.5.2 3.1.0 3.1.0 - 3.0.2 + 3.1.0 3.0.1 3.0.2 2.4.3 From e219c8793b5fc19450b824a4c79efa8ed3e56949 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:33 +0100 Subject: [PATCH 200/701] Upgrade to Maven Resources Plugin 3.1.0 Closes gh-13691 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2167080bada1..fe8a74930789 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -200,7 +200,7 @@ 3.1.0 3.1.0 3.0.1 - 3.0.2 + 3.1.0 2.4.3 3.6 3.0.1 From 649511d3c8bebf43b7be04e9177bbcc9eafc61f3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:34 +0100 Subject: [PATCH 201/701] Upgrade to Maven Shade Plugin 3.1.1 Closes gh-13692 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fe8a74930789..7309620dec41 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -201,7 +201,7 @@ 3.1.0 3.0.1 3.1.0 - 2.4.3 + 3.1.1 3.6 3.0.1 2.22.0 From 27d727b52e0343cfda3bff48375434d09363a02f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:35 +0100 Subject: [PATCH 202/701] Upgrade to Maven Site Plugin 3.7.1 Closes gh-13693 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 7309620dec41..53e443256dae 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -202,7 +202,7 @@ 3.0.1 3.1.0 3.1.1 - 3.6 + 3.7.1 3.0.1 2.22.0 3.2.2 From 5e6220f04032b74a8478add51987c434f84b6bac Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 16:59:35 +0100 Subject: [PATCH 203/701] Upgrade to Versions Maven Plugin 2.5 Closes gh-13694 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 53e443256dae..712ed0d13cc5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -206,7 +206,7 @@ 3.0.1 2.22.0 3.2.2 - 2.3 + 2.5 1.0.2 1.0.1 From fd624c20cfe0f08be921c508b64e9712001f6d36 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 17:00:10 +0100 Subject: [PATCH 204/701] Upgrade to Hikaricp 3.2.0 Closes gh-13695 --- ...ataSourcePoolMetricsAutoConfiguration.java | 37 ++++++-- .../HikariDataSourceMetricsPostProcessor.java | 84 ------------------- .../spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 32 insertions(+), 91 deletions(-) delete mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/HikariDataSourceMetricsPostProcessor.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java index 0361adcb83b5..7219958cd150 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/DataSourcePoolMetricsAutoConfiguration.java @@ -23,7 +23,10 @@ import javax.sql.DataSource; import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory; import io.micrometer.core.instrument.MeterRegistry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; @@ -35,8 +38,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; @@ -101,10 +102,34 @@ private String getDataSourceName(String beanName) { @ConditionalOnClass(HikariDataSource.class) static class HikariDataSourceMetricsConfiguration { - @Bean - public static HikariDataSourceMetricsPostProcessor hikariDataSourceMetricsPostProcessor( - ApplicationContext applicationContext) { - return new HikariDataSourceMetricsPostProcessor(applicationContext); + private static final Log logger = LogFactory + .getLog(HikariDataSourceMetricsConfiguration.class); + + private final MeterRegistry registry; + + HikariDataSourceMetricsConfiguration(MeterRegistry registry) { + this.registry = registry; + } + + @Autowired + public void bindMetricsRegistryToHikariDataSources( + Collection dataSources) { + dataSources.stream().filter(HikariDataSource.class::isInstance) + .map(HikariDataSource.class::cast) + .forEach(this::bindMetricsRegistryToHikariDataSource); + } + + private void bindMetricsRegistryToHikariDataSource(HikariDataSource hikari) { + if (hikari.getMetricRegistry() == null + && hikari.getMetricsTrackerFactory() == null) { + try { + hikari.setMetricsTrackerFactory( + new MicrometerMetricsTrackerFactory(this.registry)); + } + catch (Exception ex) { + logger.warn("Failed to bind Hikari metrics: " + ex.getMessage()); + } + } } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/HikariDataSourceMetricsPostProcessor.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/HikariDataSourceMetricsPostProcessor.java deleted file mode 100644 index 07a6439c2f6f..000000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/jdbc/HikariDataSourceMetricsPostProcessor.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.metrics.jdbc; - -import com.zaxxer.hikari.HikariDataSource; -import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory; -import io.micrometer.core.instrument.MeterRegistry; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.context.ApplicationContext; -import org.springframework.core.Ordered; - -/** - * {@link BeanPostProcessor} that configures Hikari metrics. Such arrangement is necessary - * because a {@link HikariDataSource} instance cannot be modified once its configuration - * has completed. - * - * @author Stephane Nicoll - */ -class HikariDataSourceMetricsPostProcessor implements BeanPostProcessor, Ordered { - - private static final Log logger = LogFactory - .getLog(HikariDataSourceMetricsPostProcessor.class); - - private final ApplicationContext context; - - private volatile MeterRegistry meterRegistry; - - HikariDataSourceMetricsPostProcessor(ApplicationContext context) { - this.context = context; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) { - if (bean instanceof HikariDataSource) { - bindMetricsRegistryToHikariDataSource(getMeterRegistry(), - (HikariDataSource) bean); - } - return bean; - } - - private void bindMetricsRegistryToHikariDataSource(MeterRegistry registry, - HikariDataSource dataSource) { - if (dataSource.getMetricRegistry() == null - && dataSource.getMetricsTrackerFactory() == null) { - try { - dataSource.setMetricsTrackerFactory( - new MicrometerMetricsTrackerFactory(registry)); - } - catch (Exception ex) { - logger.warn("Failed to bind Hikari metrics: " + ex.getMessage()); - } - } - } - - private MeterRegistry getMeterRegistry() { - if (this.meterRegistry == null) { - this.meterRegistry = this.context.getBean(MeterRegistry.class); - } - return this.meterRegistry; - } - - @Override - public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; - } - -} diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 712ed0d13cc5..b58e93b82a3b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -70,7 +70,7 @@ 1.2.3 5.3.1.Final 6.0.10.Final - 2.7.9 + 3.2.0 2.4.1 2.31 4.1.3 From 4799a539fe7f6b2b4bcb62028dd50aadcc464228 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 3 Jul 2018 22:12:47 +0100 Subject: [PATCH 205/701] Stop using groovy-all as it does not exist in Groovy 2.5 --- spring-boot-project/spring-boot-docs/pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index c88b648a221d..2d9920727496 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -1148,7 +1148,12 @@ org.codehaus.groovy - groovy-all + groovy + ${groovy.version} + + + org.codehaus.groovy + groovy-ant ${groovy.version} From ed39d0106d1f9a0101b61620daf95f2e39a704c1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 4 Jul 2018 10:32:38 +0100 Subject: [PATCH 206/701] Remove dependency management for groovy-all as it doesn't exist in 2.5 See gh-13670 --- spring-boot-project/spring-boot-dependencies/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b58e93b82a3b..6d809833110a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1641,11 +1641,6 @@ groovy ${groovy.version} - - org.codehaus.groovy - groovy-all - ${groovy.version} - org.codehaus.groovy groovy-ant From 79155a53131a98f4db8cb119e1fc167bd63ec73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarren=CC=83o?= Date: Mon, 25 Jun 2018 17:10:12 +0200 Subject: [PATCH 207/701] Upgrade to Infinispan 9.3.0.Final See gh-13570 --- spring-boot-project/spring-boot-dependencies/pom.xml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6d809833110a..6ed62c3d4f68 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -76,7 +76,7 @@ 4.1.3 4.5.5 4.4.10 - 9.1.7.Final + 9.3.0.Final 2.11 2.9.6 3.0.8 @@ -1867,11 +1867,6 @@ hibernate-hikaricp ${hibernate.version} - - org.hibernate - hibernate-infinispan - ${hibernate.version} - org.hibernate hibernate-java8 @@ -2009,7 +2004,7 @@ org.infinispan - infinispan-hibernate-cache + infinispan-hibernate-cache-v53 ${infinispan.version} From bc65c4cb2c733ec88837eacbc618d6c11e5642c9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 4 Jul 2018 14:00:22 +0100 Subject: [PATCH 208/701] Update Infinispan dependency management for changes between 9.1 and 9.3 Closes gh-13570 --- .../spring-boot-dependencies/pom.xml | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6ed62c3d4f68..7028213a9949 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1957,11 +1957,6 @@ infinispan-cdi-remote ${infinispan.version} - - org.infinispan - infinispan-cli - ${infinispan.version} - org.infinispan infinispan-client-hotrod @@ -1979,27 +1974,22 @@ org.infinispan - infinispan-commons - ${infinispan.version} - - - org.infinispan - infinispan-core + infinispan-clustered-lock ${infinispan.version} org.infinispan - infinispan-directory-provider + infinispan-commons ${infinispan.version} org.infinispan - infinispan-embedded + infinispan-core ${infinispan.version} org.infinispan - infinispan-embedded-query + infinispan-directory-provider ${infinispan.version} @@ -2057,11 +2047,6 @@ infinispan-query-dsl ${infinispan.version} - - org.infinispan - infinispan-remote - ${infinispan.version} - org.infinispan infinispan-remote-query-client From bdd95f09a49bf02f4fef3d83815303e7d924f898 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 5 Jul 2018 15:58:34 +0200 Subject: [PATCH 209/701] Polish WebClient metrics support This commit improves the for Actuator Metrics in WebClient. Unlike the server couterpart of WebFlux, using a `retry` operator on a `WebClient` pipeline does resubscribes to the whole chain. The previous implementation recorded start time at the time of pipeline build phase, but outside of it. This doesn't work since retrying the same pipeline doesn't update the recorded start time and the duration of sequential calls are cumulative. This is now fixed using the Reactor `Context`, since we're now recording the start time at subscription time and record metrics on `onNext` and `onError` signals. Closes gh-12228 --- .../MetricsWebClientFilterFunction.java | 27 ++++++++++++------- .../MetricsWebClientFilterFunctionTests.java | 21 +++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java index 89468ff2467f..c884e3e04bc7 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunction.java @@ -37,6 +37,9 @@ */ public class MetricsWebClientFilterFunction implements ExchangeFilterFunction { + private static final String METRICS_WEBCLIENT_START_TIME = MetricsWebClientFilterFunction.class + .getName() + ".START_TIME"; + private final MeterRegistry meterRegistry; private final WebClientExchangeTagsProvider tagProvider; @@ -53,16 +56,20 @@ public MetricsWebClientFilterFunction(MeterRegistry meterRegistry, @Override public Mono filter(ClientRequest clientRequest, ExchangeFunction exchangeFunction) { - long startTime = System.nanoTime(); - return exchangeFunction.exchange(clientRequest) - .doOnSuccessOrError((clientResponse, throwable) -> { - Iterable tags = this.tagProvider.tags(clientRequest, - clientResponse, throwable); - Timer.builder(this.metricName).tags(tags) - .description("Timer of WebClient operation") - .register(this.meterRegistry) - .record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS); - }); + return exchangeFunction.exchange(clientRequest).doOnEach((signal) -> { + if (!signal.isOnComplete()) { + Long startTime = signal.getContext().get(METRICS_WEBCLIENT_START_TIME); + ClientResponse clientResponse = signal.get(); + Throwable throwable = signal.getThrowable(); + Iterable tags = this.tagProvider.tags(clientRequest, clientResponse, + throwable); + Timer.builder(this.metricName).tags(tags) + .description("Timer of WebClient operation") + .register(this.meterRegistry) + .record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS); + } + }).subscriberContext((context) -> context.put(METRICS_WEBCLIENT_START_TIME, + System.nanoTime())); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java index 533df63d244a..0e1eea7187d2 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java @@ -18,6 +18,8 @@ import java.io.IOException; import java.net.URI; +import java.time.Duration; +import java.util.concurrent.TimeUnit; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MockClock; @@ -117,4 +119,23 @@ public void filterWhenExceptionThrownShouldRecordTimer() { .timer().count()).isEqualTo(1); } + @Test + public void filterWhenExceptionAndRetryShouldNotCumulateRecordTime() { + ClientRequest request = ClientRequest.create(HttpMethod.GET, + URI.create("http://example.com/projects/spring-boot")).build(); + ExchangeFunction exchange = (r) -> Mono.error(new IllegalArgumentException()) + .delaySubscription(Duration.ofMillis(300)).cast(ClientResponse.class); + this.filterFunction.filter(request, exchange).retry(1) + .onErrorResume(IllegalArgumentException.class, (t) -> Mono.empty()) + .block(); + assertThat(this.registry + .get("http.client.requests").tags("method", "GET", "uri", + "/projects/spring-boot", "status", "CLIENT_ERROR") + .timer().count()).isEqualTo(2); + assertThat(this.registry.get("http.client.requests") + .tags("method", "GET", "uri", "/projects/spring-boot", "status", + "CLIENT_ERROR") + .timer().max(TimeUnit.MILLISECONDS)).isLessThan(600); + } + } From 68a3c234bed2f8b01de8ec100cf1c01645a0365b Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 6 Jul 2018 14:45:47 +0200 Subject: [PATCH 210/701] Adapt to API changes in Reactor Netty The following issue changed the SSL configuration API for both client and server: https://github.com/reactor/reactor-netty/issues/370 --- .../ReactiveCloudFoundrySecurityService.java | 8 ++-- .../embedded/netty/SslServerCustomizer.java | 40 +++++++++---------- ...AbstractReactiveWebServerFactoryTests.java | 17 ++++---- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java index 49d2b38d8fac..40b1398ae9a8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java @@ -66,13 +66,13 @@ class ReactiveCloudFoundrySecurityService { } protected ReactorClientHttpConnector buildTrustAllSslConnector() { - HttpClient client = HttpClient.create().secure((sslContextSpec) -> sslContextSpec - .forClient().sslContext(this::configureSsl)); + HttpClient client = HttpClient.create().secure( + (sslContextSpec) -> sslContextSpec.sslContext(createSslContext())); return new ReactorClientHttpConnector(client); } - private SslContextBuilder configureSsl(SslContextBuilder builder) { - return builder.sslProvider(SslProvider.JDK) + private SslContextBuilder createSslContext() { + return SslContextBuilder.forClient().sslProvider(SslProvider.JDK) .trustManager(InsecureTrustManagerFactory.INSTANCE); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index 93672318293a..0c421402c495 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -19,7 +19,6 @@ import java.net.URL; import java.security.KeyStore; import java.util.Arrays; -import java.util.function.Consumer; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; @@ -52,32 +51,31 @@ public SslServerCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) { @Override public HttpServer apply(HttpServer server) { try { - return server.secure((contextSpec) -> contextSpec.forServer() - .sslContext(getContextBuilderConsumer())); + return server + .secure((contextSpec) -> contextSpec.sslContext(getContextBuilder())); } catch (Exception ex) { throw new IllegalStateException(ex); } } - protected Consumer getContextBuilderConsumer() { - return (builder) -> { - builder.keyManager(getKeyManagerFactory(this.ssl, this.sslStoreProvider)) - .trustManager( - getTrustManagerFactory(this.ssl, this.sslStoreProvider)); - if (this.ssl.getEnabledProtocols() != null) { - builder.protocols(this.ssl.getEnabledProtocols()); - } - if (this.ssl.getCiphers() != null) { - builder.ciphers(Arrays.asList(this.ssl.getCiphers())); - } - if (this.ssl.getClientAuth() == Ssl.ClientAuth.NEED) { - builder.clientAuth(ClientAuth.REQUIRE); - } - else if (this.ssl.getClientAuth() == Ssl.ClientAuth.WANT) { - builder.clientAuth(ClientAuth.OPTIONAL); - } - }; + protected SslContextBuilder getContextBuilder() { + SslContextBuilder builder = SslContextBuilder + .forServer(getKeyManagerFactory(this.ssl, this.sslStoreProvider)) + .trustManager(getTrustManagerFactory(this.ssl, this.sslStoreProvider)); + if (this.ssl.getEnabledProtocols() != null) { + builder.protocols(this.ssl.getEnabledProtocols()); + } + if (this.ssl.getCiphers() != null) { + builder.ciphers(Arrays.asList(this.ssl.getCiphers())); + } + if (this.ssl.getClientAuth() == Ssl.ClientAuth.NEED) { + builder.clientAuth(ClientAuth.REQUIRE); + } + else if (this.ssl.getClientAuth() == Ssl.ClientAuth.WANT) { + builder.clientAuth(ClientAuth.OPTIONAL); + } + return builder; } protected KeyManagerFactory getKeyManagerFactory(Ssl ssl, diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 40d6f1e8e18d..536c7ae033d8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -31,6 +31,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import org.junit.After; @@ -135,10 +136,11 @@ protected final void testBasicSslWithKeyStore(String keyStore, String keyPasswor } protected ReactorClientHttpConnector buildTrustAllSslConnector() { + SslContextBuilder builder = SslContextBuilder.forClient() + .sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE); HttpClient client = HttpClient.create().wiretap() - .secure((sslContextSpec) -> sslContextSpec.forClient() - .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE))); + .secure((sslContextSpec) -> sslContextSpec.sslContext(builder)); return new ReactorClientHttpConnector(client); } @@ -171,11 +173,12 @@ protected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector() KeyManagerFactory clientKeyManagerFactory = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); clientKeyManagerFactory.init(clientKeyStore, "password".toCharArray()); + SslContextBuilder builder = SslContextBuilder.forClient() + .sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .keyManager(clientKeyManagerFactory); HttpClient client = HttpClient.create().wiretap() - .secure((sslContextSpec) -> sslContextSpec.forClient() - .sslContext((builder) -> builder.sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .keyManager(clientKeyManagerFactory))); + .secure((sslContextSpec) -> sslContextSpec.sslContext(builder)); return new ReactorClientHttpConnector(client); } From 94517b981144c5f76e0d267acb57af423909ce97 Mon Sep 17 00:00:00 2001 From: Klaus Lehner Date: Thu, 21 Jun 2018 14:59:12 +0200 Subject: [PATCH 211/701] Add reference to structurizr starter See gh-13540 --- spring-boot-project/spring-boot-starters/README.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 0c47f48d83dc..7957a91d6c96 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -175,6 +175,9 @@ do as they were designed before this was clarified. | https://github.com/StripesFramework/stripes[Stripes] | https://github.com/juanpablo-santos/stripes-spring-boot +| https://github.com/structurizr/java[Structurizr] +| https://github.com/Catalysts/structurizr-extensions/tree/master/structurizr-spring-boot + | http://teiid.org/[Teiid] | https://github.com/teiid/teiid-spring-boot From 3e24df1794d4e909291c65d6d4410005aa0de4ec Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 9 Jul 2018 08:38:58 +0200 Subject: [PATCH 212/701] Polish "Add reference to structurizr starter" Closes gh-13540 --- spring-boot-project/spring-boot-starters/README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 7957a91d6c96..9fa2b033460a 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -176,7 +176,7 @@ do as they were designed before this was clarified. | https://github.com/juanpablo-santos/stripes-spring-boot | https://github.com/structurizr/java[Structurizr] -| https://github.com/Catalysts/structurizr-extensions/tree/master/structurizr-spring-boot +| https://github.com/Catalysts/structurizr-extensions | http://teiid.org/[Teiid] | https://github.com/teiid/teiid-spring-boot From ba46e77169ac1a5fa92dee8345ba002bbf5918ba Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sun, 24 Jun 2018 17:45:37 +0200 Subject: [PATCH 213/701] Optimize checks for java classes in Binder Closes gh-13567 --- .../springframework/boot/context/properties/bind/Binder.java | 4 +--- .../boot/context/properties/bind/MapBinder.java | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java index f0d34b345e70..12295d5cfaf4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java @@ -45,7 +45,6 @@ import org.springframework.core.env.Environment; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * A container object which Binds objects from one or more @@ -354,8 +353,7 @@ private boolean isUnbindableBean(ConfigurationPropertyName name, Bindable tar if (resolved.isPrimitive() || NON_BEAN_CLASSES.contains(resolved)) { return true; } - String packageName = ClassUtils.getPackageName(resolved); - return packageName.startsWith("java."); + return resolved.getName().startsWith("java."); } private boolean containsNoDescendantOf(Stream sources, diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java index 8aaa5c0c7920..07717364fc51 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java @@ -30,7 +30,6 @@ import org.springframework.boot.context.properties.source.IterableConfigurationPropertySource; import org.springframework.core.CollectionFactory; import org.springframework.core.ResolvableType; -import org.springframework.util.ClassUtils; /** * {@link AggregateBinder} for Maps. @@ -199,8 +198,7 @@ private boolean isValueTreatedAsNestedMap() { private boolean isScalarValue(ConfigurationPropertySource source, ConfigurationPropertyName name) { Class resolved = this.valueType.resolve(Object.class); - String packageName = ClassUtils.getPackageName(resolved); - if (!packageName.startsWith("java.lang") && !resolved.isEnum()) { + if (!resolved.getName().startsWith("java.lang") && !resolved.isEnum()) { return false; } ConfigurationProperty property = source.getConfigurationProperty(name); From 5fcba490d289b2b80114ed9425da615a6dca3646 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Tue, 26 Jun 2018 18:36:53 +0200 Subject: [PATCH 214/701] Polish conditional expressions Closes gh-13583 --- .../boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java | 4 ++-- .../webservices/WebServicesAutoConfiguration.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java index 96f78c72a364..064a11067ba3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -52,7 +52,7 @@ public H2ConsoleAutoConfiguration(H2ConsoleProperties properties) { @Bean public ServletRegistrationBean h2Console() { String path = this.properties.getPath(); - String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*"); + String urlMapping = path + (path.endsWith("/") ? "*" : "/*"); ServletRegistrationBean registration = new ServletRegistrationBean<>( new WebServlet(), urlMapping); H2ConsoleProperties.Settings settings = this.properties.getSettings(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java index eb5d5cc906c4..634d366c8f17 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java @@ -77,7 +77,7 @@ public ServletRegistrationBean messageDispatcherServle MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); String path = this.properties.getPath(); - String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*"); + String urlMapping = path + (path.endsWith("/") ? "*" : "/*"); ServletRegistrationBean registration = new ServletRegistrationBean<>( servlet, urlMapping); WebServicesProperties.Servlet servletProperties = this.properties.getServlet(); From d1acf9a24d2a3d1cdf5c7433501ca192efc68ee8 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sun, 8 Jul 2018 18:28:39 +0200 Subject: [PATCH 215/701] Fix API adaptation changes for Reactor Netty --- .../boot/web/embedded/netty/SslServerCustomizer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index 0c421402c495..032547626bd3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -26,6 +26,7 @@ import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; import reactor.netty.http.server.HttpServer; +import reactor.netty.tcp.SslProvider.DefaultConfigurationType; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.SslStoreProvider; @@ -52,7 +53,8 @@ public SslServerCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) { public HttpServer apply(HttpServer server) { try { return server - .secure((contextSpec) -> contextSpec.sslContext(getContextBuilder())); + .secure((contextSpec) -> contextSpec.sslContext(getContextBuilder()) + .defaultConfiguration(DefaultConfigurationType.NONE)); } catch (Exception ex) { throw new IllegalStateException(ex); From 710cdbab9216256df8d40725a2612306663aebaa Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 9 Jul 2018 12:17:15 +0100 Subject: [PATCH 216/701] Prohibit bean overriding by default and analyze override failures Closes gh-13609 --- .../appendix-application-properties.adoc | 1 + .../boot/SpringApplication.java | 26 +++++- ...BeanDefinitionOverrideFailureAnalyzer.java | 55 +++++++++++ ...itional-spring-configuration-metadata.json | 7 ++ .../main/resources/META-INF/spring.factories | 1 + .../boot/OverrideSourcesTests.java | 1 + .../boot/SpringApplicationTests.java | 31 +++++++ ...efinitionOverrideFailureAnalyzerTests.java | 92 +++++++++++++++++++ 8 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 4eab17e22889..a1b8e209bf33 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -113,6 +113,7 @@ content into your application. Rather, pick only the properties that you need. spring.mail.username= # Login user of the SMTP server. # APPLICATION SETTINGS ({sc-spring-boot}/SpringApplication.{sc-ext}[SpringApplication]) + spring.main.allow-bean-definition-overriding=false # Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed. spring.main.banner-mode=console # Mode used to display the banner when the application runs. spring.main.sources= # Sources (class names, package names, or XML resource locations) to include in the ApplicationContext. spring.main.web-application-type= # Flag to explicitly request a specific type of web application. If not set, auto-detected based on the classpath. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 404b2207a55a..90dbc2ecac82 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -35,9 +35,11 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.CachedIntrospectionResults; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.boot.Banner.Mode; import org.springframework.boot.context.properties.bind.Bindable; @@ -235,6 +237,8 @@ public class SpringApplication { private Set additionalProfiles = new HashSet<>(); + private boolean allowBeanDefinitionOverriding; + /** * Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class-level} @@ -381,12 +385,15 @@ private void prepareContext(ConfigurableApplicationContext context, } // Add boot specific singleton beans - context.getBeanFactory().registerSingleton("springApplicationArguments", - applicationArguments); + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { - context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); + beanFactory.registerSingleton("springBootBanner", printedBanner); + } + if (beanFactory instanceof DefaultListableBeanFactory) { + ((DefaultListableBeanFactory) beanFactory) + .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } - // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); @@ -955,6 +962,17 @@ public void setWebApplicationType(WebApplicationType webApplicationType) { this.webApplicationType = webApplicationType; } + /** + * Sets if bean definition overriding, by registering a definition with the same name + * as an existing definition, should be allowed. Defaults to {@code false}. + * @param allowBeanDefinitionOverriding if overriding is allowed + * @since 2.1 + * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean) + */ + public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { + this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; + } + /** * Sets if the application is headless and should not instantiate AWT. Defaults to * {@code true} to prevent java icons appearing. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java new file mode 100644 index 000000000000..2bd543c932b2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.diagnostics.analyzer; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +/** + * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a + * {@link BeanDefinitionOverrideException}. + * + * @author Andy Wilkinson + */ +class BeanDefinitionOverrideFailureAnalyzer + extends AbstractFailureAnalyzer { + + private static final String ACTION = "Consider renaming one of the beans or enabling " + + "overriding by setting spring.main.allow-bean-definition-overriding=true"; + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, + BeanDefinitionOverrideException cause) { + return new FailureAnalysis(getDescription(cause), ACTION, cause); + } + + private String getDescription(BeanDefinitionOverrideException ex) { + StringWriter description = new StringWriter(); + PrintWriter printer = new PrintWriter(description); + printer.printf( + "The bean '%s', defined in %s, could not be registered. A bean with that " + + "name has already been defined in %s and overriding is disabled.", + ex.getBeanName(), ex.getBeanDefinition().getResourceDescription(), + ex.getExistingDefinition().getResourceDescription()); + return description.toString(); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f25fb511deb1..c8ef53d679ff 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -172,6 +172,13 @@ "com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner" ] }, + { + "name": "spring.main.allow-bean-definition-overriding", + "type": "java.lang.Boolean", + "sourceType": "org.springframework.boot.SpringApplication", + "description": "Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed", + "defaultValue": false + }, { "name": "spring.main.banner-mode", "type": "org.springframework.boot.Banner$Mode", diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index ff98c96f037d..2250eba38a9b 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -39,6 +39,7 @@ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProce # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ +org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java index 0e7dd9c30cf5..52913484a6ef 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java @@ -56,6 +56,7 @@ public void primaryBeanInjectedProvingSourcesNotOverridden() { this.context = SpringApplication.run( new Class[] { MainConfiguration.class, TestConfiguration.class }, new String[] { "--spring.main.web-application-type=none", + "--spring.main.allow-bean-definition-overriding=true", "--spring.main.sources=org.springframework.boot.OverrideSourcesTests.MainConfiguration" }); assertThat(this.context.getBean(Service.class).bean.name).isEqualTo("bar"); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index e31a5b6a670a..0d575bc76531 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -45,6 +45,7 @@ import org.springframework.beans.CachedIntrospectionResults; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator; @@ -1118,6 +1119,21 @@ public void run() { assertThat(occurrences).as("Expected single stacktrace").isEqualTo(1); } + @Test + public void beanDefinitionOverridingIsDisabledByDefault() { + this.thrown.expect(BeanDefinitionOverrideException.class); + new SpringApplication(ExampleConfig.class, OverrideConfig.class).run(); + } + + @Test + public void beanDefinitionOverridingCanBeEnabled() { + assertThat( + new SpringApplication(ExampleConfig.class, OverrideConfig.class) + .run("--spring.main.allow-bean-definition-overriding=true", + "--spring.main.web-application-type=none") + .getBean("someBean")).isEqualTo("override"); + } + private Condition matchingPropertySource( final Class propertySourceClass, final String name) { return new Condition("has property source") { @@ -1228,6 +1244,21 @@ public Banner.Mode getBannerMode() { @Configuration static class ExampleConfig { + @Bean + public String someBean() { + return "test"; + } + + } + + @Configuration + static class OverrideConfig { + + @Bean + public String someBean() { + return "override"; + } + } @Configuration diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java new file mode 100644 index 000000000000..861e52159df8 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2018 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.diagnostics.analyzer; + +import org.junit.Test; + +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BeanDefinitionOverrideFailureAnalyzer}. + * + * @author Andy Wilkinson + */ +public class BeanDefinitionOverrideFailureAnalyzerTests { + + @Test + public void bindExceptionWithFieldErrorsDueToValidationFailure() { + FailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class); + String description = analysis.getDescription(); + assertThat(description).contains("The bean 'testBean', defined in " + + SecondConfiguration.class.getName() + ", could not be registered."); + assertThat(description).contains(FirstConfiguration.class.getName()); + } + + private FailureAnalysis performAnalysis(Class configuration) { + BeanDefinitionOverrideException failure = createFailure(configuration); + assertThat(failure).isNotNull(); + return new BeanDefinitionOverrideFailureAnalyzer().analyze(failure); + } + + private BeanDefinitionOverrideException createFailure(Class configuration) { + try { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.setAllowBeanDefinitionOverriding(false); + context.register(configuration); + context.refresh(); + context.close(); + return null; + } + catch (BeanDefinitionOverrideException ex) { + return ex; + } + } + + @Configuration + @Import({ FirstConfiguration.class, SecondConfiguration.class }) + static class BeanOverrideConfiguration { + + } + + @Configuration + static class FirstConfiguration { + + @Bean + public String testBean() { + return "test"; + } + + } + + @Configuration + static class SecondConfiguration { + + @Bean + public String testBean() { + return "test"; + } + + } + +} From 063e8e4dc6d42fd574e54ea42f116a77764f9607 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 9 Jul 2018 17:58:49 +0100 Subject: [PATCH 217/701] Revert "Prohibit bean overriding by default and analyze override failures" This reverts commit 710cdbab9216256df8d40725a2612306663aebaa. --- .../appendix-application-properties.adoc | 1 - .../boot/SpringApplication.java | 26 +----- ...BeanDefinitionOverrideFailureAnalyzer.java | 55 ----------- ...itional-spring-configuration-metadata.json | 7 -- .../main/resources/META-INF/spring.factories | 1 - .../boot/OverrideSourcesTests.java | 1 - .../boot/SpringApplicationTests.java | 31 ------- ...efinitionOverrideFailureAnalyzerTests.java | 92 ------------------- 8 files changed, 4 insertions(+), 210 deletions(-) delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index a1b8e209bf33..4eab17e22889 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -113,7 +113,6 @@ content into your application. Rather, pick only the properties that you need. spring.mail.username= # Login user of the SMTP server. # APPLICATION SETTINGS ({sc-spring-boot}/SpringApplication.{sc-ext}[SpringApplication]) - spring.main.allow-bean-definition-overriding=false # Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed. spring.main.banner-mode=console # Mode used to display the banner when the application runs. spring.main.sources= # Sources (class names, package names, or XML resource locations) to include in the ApplicationContext. spring.main.web-application-type= # Flag to explicitly request a specific type of web application. If not set, auto-detected based on the classpath. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 90dbc2ecac82..404b2207a55a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -35,11 +35,9 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.CachedIntrospectionResults; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.boot.Banner.Mode; import org.springframework.boot.context.properties.bind.Bindable; @@ -237,8 +235,6 @@ public class SpringApplication { private Set additionalProfiles = new HashSet<>(); - private boolean allowBeanDefinitionOverriding; - /** * Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class-level} @@ -385,15 +381,12 @@ private void prepareContext(ConfigurableApplicationContext context, } // Add boot specific singleton beans - ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); - beanFactory.registerSingleton("springApplicationArguments", applicationArguments); + context.getBeanFactory().registerSingleton("springApplicationArguments", + applicationArguments); if (printedBanner != null) { - beanFactory.registerSingleton("springBootBanner", printedBanner); - } - if (beanFactory instanceof DefaultListableBeanFactory) { - ((DefaultListableBeanFactory) beanFactory) - .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); + context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } + // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); @@ -962,17 +955,6 @@ public void setWebApplicationType(WebApplicationType webApplicationType) { this.webApplicationType = webApplicationType; } - /** - * Sets if bean definition overriding, by registering a definition with the same name - * as an existing definition, should be allowed. Defaults to {@code false}. - * @param allowBeanDefinitionOverriding if overriding is allowed - * @since 2.1 - * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean) - */ - public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { - this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; - } - /** * Sets if the application is headless and should not instantiate AWT. Defaults to * {@code true} to prevent java icons appearing. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java deleted file mode 100644 index 2bd543c932b2..000000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012-2018 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.diagnostics.analyzer; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.springframework.beans.factory.support.BeanDefinitionOverrideException; -import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; -import org.springframework.boot.diagnostics.FailureAnalysis; - -/** - * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a - * {@link BeanDefinitionOverrideException}. - * - * @author Andy Wilkinson - */ -class BeanDefinitionOverrideFailureAnalyzer - extends AbstractFailureAnalyzer { - - private static final String ACTION = "Consider renaming one of the beans or enabling " - + "overriding by setting spring.main.allow-bean-definition-overriding=true"; - - @Override - protected FailureAnalysis analyze(Throwable rootFailure, - BeanDefinitionOverrideException cause) { - return new FailureAnalysis(getDescription(cause), ACTION, cause); - } - - private String getDescription(BeanDefinitionOverrideException ex) { - StringWriter description = new StringWriter(); - PrintWriter printer = new PrintWriter(description); - printer.printf( - "The bean '%s', defined in %s, could not be registered. A bean with that " - + "name has already been defined in %s and overriding is disabled.", - ex.getBeanName(), ex.getBeanDefinition().getResourceDescription(), - ex.getExistingDefinition().getResourceDescription()); - return description.toString(); - } - -} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c8ef53d679ff..f25fb511deb1 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -172,13 +172,6 @@ "com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner" ] }, - { - "name": "spring.main.allow-bean-definition-overriding", - "type": "java.lang.Boolean", - "sourceType": "org.springframework.boot.SpringApplication", - "description": "Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed", - "defaultValue": false - }, { "name": "spring.main.banner-mode", "type": "org.springframework.boot.Banner$Mode", diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 2250eba38a9b..ff98c96f037d 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -39,7 +39,6 @@ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProce # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ -org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java index 52913484a6ef..0e7dd9c30cf5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java @@ -56,7 +56,6 @@ public void primaryBeanInjectedProvingSourcesNotOverridden() { this.context = SpringApplication.run( new Class[] { MainConfiguration.class, TestConfiguration.class }, new String[] { "--spring.main.web-application-type=none", - "--spring.main.allow-bean-definition-overriding=true", "--spring.main.sources=org.springframework.boot.OverrideSourcesTests.MainConfiguration" }); assertThat(this.context.getBean(Service.class).bean.name).isEqualTo("bar"); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 0d575bc76531..e31a5b6a670a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -45,7 +45,6 @@ import org.springframework.beans.CachedIntrospectionResults; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionOverrideException; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator; @@ -1119,21 +1118,6 @@ public void run() { assertThat(occurrences).as("Expected single stacktrace").isEqualTo(1); } - @Test - public void beanDefinitionOverridingIsDisabledByDefault() { - this.thrown.expect(BeanDefinitionOverrideException.class); - new SpringApplication(ExampleConfig.class, OverrideConfig.class).run(); - } - - @Test - public void beanDefinitionOverridingCanBeEnabled() { - assertThat( - new SpringApplication(ExampleConfig.class, OverrideConfig.class) - .run("--spring.main.allow-bean-definition-overriding=true", - "--spring.main.web-application-type=none") - .getBean("someBean")).isEqualTo("override"); - } - private Condition matchingPropertySource( final Class propertySourceClass, final String name) { return new Condition("has property source") { @@ -1244,21 +1228,6 @@ public Banner.Mode getBannerMode() { @Configuration static class ExampleConfig { - @Bean - public String someBean() { - return "test"; - } - - } - - @Configuration - static class OverrideConfig { - - @Bean - public String someBean() { - return "override"; - } - } @Configuration diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java deleted file mode 100644 index 861e52159df8..000000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2012-2018 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.diagnostics.analyzer; - -import org.junit.Test; - -import org.springframework.beans.factory.support.BeanDefinitionOverrideException; -import org.springframework.boot.diagnostics.FailureAnalysis; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link BeanDefinitionOverrideFailureAnalyzer}. - * - * @author Andy Wilkinson - */ -public class BeanDefinitionOverrideFailureAnalyzerTests { - - @Test - public void bindExceptionWithFieldErrorsDueToValidationFailure() { - FailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class); - String description = analysis.getDescription(); - assertThat(description).contains("The bean 'testBean', defined in " - + SecondConfiguration.class.getName() + ", could not be registered."); - assertThat(description).contains(FirstConfiguration.class.getName()); - } - - private FailureAnalysis performAnalysis(Class configuration) { - BeanDefinitionOverrideException failure = createFailure(configuration); - assertThat(failure).isNotNull(); - return new BeanDefinitionOverrideFailureAnalyzer().analyze(failure); - } - - private BeanDefinitionOverrideException createFailure(Class configuration) { - try { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.setAllowBeanDefinitionOverriding(false); - context.register(configuration); - context.refresh(); - context.close(); - return null; - } - catch (BeanDefinitionOverrideException ex) { - return ex; - } - } - - @Configuration - @Import({ FirstConfiguration.class, SecondConfiguration.class }) - static class BeanOverrideConfiguration { - - } - - @Configuration - static class FirstConfiguration { - - @Bean - public String testBean() { - return "test"; - } - - } - - @Configuration - static class SecondConfiguration { - - @Bean - public String testBean() { - return "test"; - } - - } - -} From b87b23a44f6ec267ff2ddf942f56cb47a4d913b0 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sun, 8 Jul 2018 03:10:00 +0900 Subject: [PATCH 218/701] Fix parameter order for RequestMatcherAssert.doesNotMatch() Closes gh-13707 --- .../servlet/EndpointRequestTests.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java index e16c01e53fdb..20df4c8c571b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java @@ -78,14 +78,15 @@ public void toAnyEndpointShouldNotMatchOtherPath() { @Test public void toAnyEndpointWhenServletPathNotEmptyShouldMatch() { RequestMatcher matcher = EndpointRequest.toAnyEndpoint(); - assertMatcher(matcher, "/actuator", "/spring", "/admin").matches("/actuator/foo", - "/spring", "/admin"); - assertMatcher(matcher, "/actuator", "/spring", "/admin").matches("/actuator/bar", - "/spring", "/admin"); - assertMatcher(matcher, "/actuator", "/spring").matches("/actuator", "/spring"); - assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/actuator/baz", - "/spring"); - assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/actuator/foo", ""); + assertMatcher(matcher, "/actuator", "/spring", "/admin") + .matches(Arrays.asList("/spring", "/admin"), "/actuator/foo"); + assertMatcher(matcher, "/actuator", "/spring", "/admin") + .matches(Arrays.asList("/spring", "/admin"), "/actuator/bar"); + assertMatcher(matcher, "/actuator", "/spring").matches(Arrays.asList("/spring"), + "/actuator"); + assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/spring", + "/actuator/baz"); + assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("", "/actuator/foo"); } @Test @@ -279,8 +280,8 @@ public void matches(String servletPath) { matches(mockRequest(servletPath)); } - public void matches(String pathInfo, String... servletPaths) { - Arrays.stream(servletPaths).forEach((p) -> matches(mockRequest(p, pathInfo))); + public void matches(List servletPaths, String pathInfo) { + servletPaths.forEach((p) -> matches(mockRequest(p, pathInfo))); } private void matches(HttpServletRequest request) { From cdd9c92ba22c6107286f68313067fe689e1a4338 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 11:42:37 +0100 Subject: [PATCH 219/701] Start building against snapshots for Spring Data Lovelace RC1 See gh-13740 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 54805f668e11..b2219a607784 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -155,7 +155,7 @@ 2.0.4.RELEASE 4.0.1.RELEASE 2.0.2.RELEASE - Lovelace-M3 + Lovelace-BUILD-SNAPSHOT 0.24.0.RELEASE 5.0.6.RELEASE 2.2.0.BUILD-SNAPSHOT From c1a81cfca09f49c74a83b0934c4129089948664a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 11:41:07 +0100 Subject: [PATCH 220/701] Prohibit bean overriding by default and analyze override failures Closes gh-13609 --- .../AbstractEndpointDocumentationTests.java | 4 +- .../FlywayEndpointDocumentationTests.java | 6 +- .../BasicErrorControllerIntegrationTests.java | 6 +- .../BasicErrorControllerMockMvcTests.java | 4 +- .../appendix-application-properties.adoc | 1 + .../boot/SpringApplication.java | 26 +++++- ...BeanDefinitionOverrideFailureAnalyzer.java | 55 +++++++++++ ...itional-spring-configuration-metadata.json | 7 ++ .../main/resources/META-INF/spring.factories | 1 + .../boot/OverrideSourcesTests.java | 1 + .../boot/SpringApplicationTests.java | 31 +++++++ ...efinitionOverrideFailureAnalyzerTests.java | 92 +++++++++++++++++++ 12 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java index a10ba43787ce..ff2ddf1bc15a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/AbstractEndpointDocumentationTests.java @@ -31,6 +31,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; @@ -39,7 +40,6 @@ import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationPreprocessor; import org.springframework.restdocs.payload.FieldDescriptor; @@ -128,7 +128,7 @@ private List select(List candidates, Predicate filter) { } @Configuration - @Import({ JacksonAutoConfiguration.class, + @ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java index c146c28a7d84..5e0972092a46 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/FlywayEndpointDocumentationTests.java @@ -26,8 +26,8 @@ import org.junit.Test; import org.springframework.boot.actuate.flyway.FlywayEndpoint; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -98,8 +98,8 @@ private List migrationFieldDescriptors() { } @Configuration - @Import({ BaseDocumentationConfiguration.class, EmbeddedDataSourceConfiguration.class, - FlywayAutoConfiguration.class }) + @Import(BaseDocumentationConfiguration.class) + @ImportAutoConfiguration(FlywayAutoConfiguration.class) static class TestConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java index 9c25c10b6a1e..22b6188ba237 100755 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java @@ -36,6 +36,7 @@ import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; @@ -46,7 +47,6 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; @@ -236,7 +236,7 @@ private void load(String... arguments) { @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented - @Import({ ServletWebServerFactoryAutoConfiguration.class, + @ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) @@ -246,7 +246,7 @@ private void load(String... arguments) { @Configuration @MinimalWebConfiguration - @Import(FreeMarkerAutoConfiguration.class) + @ImportAutoConfiguration(FreeMarkerAutoConfiguration.class) public static class TestConfiguration { // For manual testing diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerMockMvcTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerMockMvcTests.java index 5dacfd3b9532..4eabf5dda066 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerMockMvcTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerMockMvcTests.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; @@ -42,7 +43,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; @@ -129,7 +129,7 @@ public void testDirectAccessForBrowserClient() throws Exception { @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented - @Import({ ServletWebServerFactoryAutoConfiguration.class, + @ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 4eab17e22889..a1b8e209bf33 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -113,6 +113,7 @@ content into your application. Rather, pick only the properties that you need. spring.mail.username= # Login user of the SMTP server. # APPLICATION SETTINGS ({sc-spring-boot}/SpringApplication.{sc-ext}[SpringApplication]) + spring.main.allow-bean-definition-overriding=false # Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed. spring.main.banner-mode=console # Mode used to display the banner when the application runs. spring.main.sources= # Sources (class names, package names, or XML resource locations) to include in the ApplicationContext. spring.main.web-application-type= # Flag to explicitly request a specific type of web application. If not set, auto-detected based on the classpath. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 404b2207a55a..90dbc2ecac82 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -35,9 +35,11 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.CachedIntrospectionResults; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.boot.Banner.Mode; import org.springframework.boot.context.properties.bind.Bindable; @@ -235,6 +237,8 @@ public class SpringApplication { private Set additionalProfiles = new HashSet<>(); + private boolean allowBeanDefinitionOverriding; + /** * Create a new {@link SpringApplication} instance. The application context will load * beans from the specified primary sources (see {@link SpringApplication class-level} @@ -381,12 +385,15 @@ private void prepareContext(ConfigurableApplicationContext context, } // Add boot specific singleton beans - context.getBeanFactory().registerSingleton("springApplicationArguments", - applicationArguments); + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { - context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); + beanFactory.registerSingleton("springBootBanner", printedBanner); + } + if (beanFactory instanceof DefaultListableBeanFactory) { + ((DefaultListableBeanFactory) beanFactory) + .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } - // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); @@ -955,6 +962,17 @@ public void setWebApplicationType(WebApplicationType webApplicationType) { this.webApplicationType = webApplicationType; } + /** + * Sets if bean definition overriding, by registering a definition with the same name + * as an existing definition, should be allowed. Defaults to {@code false}. + * @param allowBeanDefinitionOverriding if overriding is allowed + * @since 2.1 + * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean) + */ + public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { + this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; + } + /** * Sets if the application is headless and should not instantiate AWT. Defaults to * {@code true} to prevent java icons appearing. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java new file mode 100644 index 000000000000..2bd543c932b2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.diagnostics.analyzer; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +/** + * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a + * {@link BeanDefinitionOverrideException}. + * + * @author Andy Wilkinson + */ +class BeanDefinitionOverrideFailureAnalyzer + extends AbstractFailureAnalyzer { + + private static final String ACTION = "Consider renaming one of the beans or enabling " + + "overriding by setting spring.main.allow-bean-definition-overriding=true"; + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, + BeanDefinitionOverrideException cause) { + return new FailureAnalysis(getDescription(cause), ACTION, cause); + } + + private String getDescription(BeanDefinitionOverrideException ex) { + StringWriter description = new StringWriter(); + PrintWriter printer = new PrintWriter(description); + printer.printf( + "The bean '%s', defined in %s, could not be registered. A bean with that " + + "name has already been defined in %s and overriding is disabled.", + ex.getBeanName(), ex.getBeanDefinition().getResourceDescription(), + ex.getExistingDefinition().getResourceDescription()); + return description.toString(); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f25fb511deb1..c8ef53d679ff 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -172,6 +172,13 @@ "com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner" ] }, + { + "name": "spring.main.allow-bean-definition-overriding", + "type": "java.lang.Boolean", + "sourceType": "org.springframework.boot.SpringApplication", + "description": "Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed", + "defaultValue": false + }, { "name": "spring.main.banner-mode", "type": "org.springframework.boot.Banner$Mode", diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index ff98c96f037d..2250eba38a9b 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -39,6 +39,7 @@ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProce # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ +org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java index 0e7dd9c30cf5..52913484a6ef 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java @@ -56,6 +56,7 @@ public void primaryBeanInjectedProvingSourcesNotOverridden() { this.context = SpringApplication.run( new Class[] { MainConfiguration.class, TestConfiguration.class }, new String[] { "--spring.main.web-application-type=none", + "--spring.main.allow-bean-definition-overriding=true", "--spring.main.sources=org.springframework.boot.OverrideSourcesTests.MainConfiguration" }); assertThat(this.context.getBean(Service.class).bean.name).isEqualTo("bar"); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index e31a5b6a670a..0d575bc76531 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -45,6 +45,7 @@ import org.springframework.beans.CachedIntrospectionResults; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator; @@ -1118,6 +1119,21 @@ public void run() { assertThat(occurrences).as("Expected single stacktrace").isEqualTo(1); } + @Test + public void beanDefinitionOverridingIsDisabledByDefault() { + this.thrown.expect(BeanDefinitionOverrideException.class); + new SpringApplication(ExampleConfig.class, OverrideConfig.class).run(); + } + + @Test + public void beanDefinitionOverridingCanBeEnabled() { + assertThat( + new SpringApplication(ExampleConfig.class, OverrideConfig.class) + .run("--spring.main.allow-bean-definition-overriding=true", + "--spring.main.web-application-type=none") + .getBean("someBean")).isEqualTo("override"); + } + private Condition matchingPropertySource( final Class propertySourceClass, final String name) { return new Condition("has property source") { @@ -1228,6 +1244,21 @@ public Banner.Mode getBannerMode() { @Configuration static class ExampleConfig { + @Bean + public String someBean() { + return "test"; + } + + } + + @Configuration + static class OverrideConfig { + + @Bean + public String someBean() { + return "override"; + } + } @Configuration diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java new file mode 100644 index 000000000000..861e52159df8 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2018 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.diagnostics.analyzer; + +import org.junit.Test; + +import org.springframework.beans.factory.support.BeanDefinitionOverrideException; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BeanDefinitionOverrideFailureAnalyzer}. + * + * @author Andy Wilkinson + */ +public class BeanDefinitionOverrideFailureAnalyzerTests { + + @Test + public void bindExceptionWithFieldErrorsDueToValidationFailure() { + FailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class); + String description = analysis.getDescription(); + assertThat(description).contains("The bean 'testBean', defined in " + + SecondConfiguration.class.getName() + ", could not be registered."); + assertThat(description).contains(FirstConfiguration.class.getName()); + } + + private FailureAnalysis performAnalysis(Class configuration) { + BeanDefinitionOverrideException failure = createFailure(configuration); + assertThat(failure).isNotNull(); + return new BeanDefinitionOverrideFailureAnalyzer().analyze(failure); + } + + private BeanDefinitionOverrideException createFailure(Class configuration) { + try { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.setAllowBeanDefinitionOverriding(false); + context.register(configuration); + context.refresh(); + context.close(); + return null; + } + catch (BeanDefinitionOverrideException ex) { + return ex; + } + } + + @Configuration + @Import({ FirstConfiguration.class, SecondConfiguration.class }) + static class BeanOverrideConfiguration { + + } + + @Configuration + static class FirstConfiguration { + + @Bean + public String testBean() { + return "test"; + } + + } + + @Configuration + static class SecondConfiguration { + + @Bean + public String testBean() { + return "test"; + } + + } + +} From be837ccb4bcf7ebd32b21e810c88db88a6bf2e8e Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Fri, 6 Jul 2018 23:14:42 +0200 Subject: [PATCH 221/701] Use PropertySources.stream() where possible Closes gh-13724 --- .../EnvironmentEndpointDocumentationTests.java | 4 +--- .../context/properties/CompositePropertySources.java | 6 ++---- .../boot/context/properties/FilteredPropertySources.java | 6 ++---- .../properties/source/ConfigurationPropertySources.java | 7 +++---- ...InvalidConfigurationPropertyValueFailureAnalyzer.java | 9 ++++----- .../SpringApplicationJsonEnvironmentPostProcessor.java | 6 ++---- 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java index c6452af10dc6..59b3bf677c64 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/EnvironmentEndpointDocumentationTests.java @@ -22,7 +22,6 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -156,8 +155,7 @@ public EnvironmentEndpoint endpoint(ConfigurableEnvironment environment) { @Override protected void customizePropertySources( MutablePropertySources propertySources) { - StreamSupport - .stream(environment.getPropertySources().spliterator(), false) + environment.getPropertySources().stream() .filter(this::includedPropertySource) .forEach(propertySources::addLast); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java index b7e416430f51..645c9aa20a07 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -20,7 +20,6 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; @@ -42,8 +41,7 @@ final class CompositePropertySources implements PropertySources { @Override public Iterator> iterator() { - return this.propertySources.stream() - .flatMap((sources) -> StreamSupport.stream(sources.spliterator(), false)) + return this.propertySources.stream().flatMap(PropertySources::stream) .collect(Collectors.toList()).iterator(); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/FilteredPropertySources.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/FilteredPropertySources.java index b213f5cf2126..56f54fddb0c2 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/FilteredPropertySources.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/FilteredPropertySources.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -20,7 +20,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import java.util.stream.StreamSupport; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; @@ -59,8 +58,7 @@ public PropertySource get(String name) { @Override public Iterator> iterator() { - return StreamSupport.stream(this.delegate.spliterator(), false) - .filter(this::included).iterator(); + return this.delegate.stream().filter(this::included).iterator(); } private boolean included(PropertySource propertySource) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java index 23ef8b391572..8168aed508f1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java @@ -18,13 +18,13 @@ import java.util.Collections; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource.StubPropertySource; +import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySourcesPropertyResolver; import org.springframework.util.Assert; @@ -136,9 +136,8 @@ public static Iterable from( } private static Stream> streamPropertySources( - Iterable> sources) { - return StreamSupport.stream(sources.spliterator(), false) - .flatMap(ConfigurationPropertySources::flatten) + PropertySources sources) { + return sources.stream().flatMap(ConfigurationPropertySources::flatten) .filter(ConfigurationPropertySources::isIncluded); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java index b58b1aeee12f..ade8e65ff9aa 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java @@ -16,11 +16,9 @@ package org.springframework.boot.diagnostics.analyzer; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; @@ -74,9 +72,10 @@ private List getDescriptors(String propertyName) { } private Stream> getPropertySources() { - Iterable> sources = (this.environment != null - ? this.environment.getPropertySources() : Collections.emptyList()); - return StreamSupport.stream(sources.spliterator(), false) + if (this.environment == null) { + return Stream.empty(); + } + return this.environment.getPropertySources().stream() .filter((source) -> !ConfigurationPropertySources .isAttachedConfigurationPropertySource(source)); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java index afff3dc634c7..7f412ebba90a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java @@ -20,7 +20,6 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; -import java.util.stream.StreamSupport; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -92,9 +91,8 @@ public void setOrder(int order) { public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { MutablePropertySources propertySources = environment.getPropertySources(); - StreamSupport.stream(propertySources.spliterator(), false) - .map(JsonPropertyValue::get).filter(Objects::nonNull).findFirst() - .ifPresent((v) -> processJson(environment, v)); + propertySources.stream().map(JsonPropertyValue::get).filter(Objects::nonNull) + .findFirst().ifPresent((v) -> processJson(environment, v)); } private void processJson(ConfigurableEnvironment environment, From cf3b1f66531be36148f51196a4b17effdbe8ac43 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 15:05:22 +0100 Subject: [PATCH 222/701] Start building against Spring HATEOAS 0.25.0 snapshots See gh-13742 --- .../hateoas/HypermediaAutoConfiguration.java | 56 +------------------ .../HypermediaAutoConfigurationTests.java | 24 ++------ .../spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 6 insertions(+), 76 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfiguration.java index 3847ad5ec2ed..a35993fef1c2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,11 +18,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -33,7 +28,6 @@ import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.hateoas.EntityLinks; @@ -42,7 +36,6 @@ import org.springframework.hateoas.config.EnableEntityLinks; import org.springframework.hateoas.config.EnableHypermediaSupport; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.plugin.core.Plugin; import org.springframework.web.bind.annotation.RequestMapping; @@ -71,11 +64,6 @@ public class HypermediaAutoConfiguration { @EnableHypermediaSupport(type = HypermediaType.HAL) protected static class HypermediaConfiguration { - @Bean - public static HalObjectMapperConfigurer halObjectMapperConfigurer() { - return new HalObjectMapperConfigurer(); - } - } @Configuration @@ -85,46 +73,4 @@ protected static class EntityLinksConfiguration { } - /** - * {@link BeanPostProcessor} to apply any {@link Jackson2ObjectMapperBuilder} - * configuration to the HAL {@link ObjectMapper}. - */ - private static class HalObjectMapperConfigurer - implements BeanPostProcessor, BeanFactoryAware { - - private BeanFactory beanFactory; - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof ObjectMapper && "_halObjectMapper".equals(beanName)) { - postProcessHalObjectMapper((ObjectMapper) bean); - } - return bean; - } - - private void postProcessHalObjectMapper(ObjectMapper objectMapper) { - try { - Jackson2ObjectMapperBuilder builder = this.beanFactory - .getBean(Jackson2ObjectMapperBuilder.class); - builder.configure(objectMapper); - } - catch (NoSuchBeanDefinitionException ex) { - // No Jackson configuration required - } - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfigurationTests.java index e25fd2af1001..3ee320ebe24e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hateoas/HypermediaAutoConfigurationTests.java @@ -16,12 +16,12 @@ package org.springframework.boot.autoconfigure.hateoas; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration.EntityLinksConfiguration; +import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration.HypermediaConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; @@ -91,24 +91,8 @@ public void doesBackOffIfEnableHypermediaSupportIsDeclaredManually() { TestPropertyValues.of("spring.jackson.serialization.INDENT_OUTPUT:true") .applyTo(this.context); this.context.refresh(); - ObjectMapper objectMapper = this.context.getBean("_halObjectMapper", - ObjectMapper.class); - assertThat(objectMapper.getSerializationConfig() - .isEnabled(SerializationFeature.INDENT_OUTPUT)).isFalse(); - } - - @Test - public void jacksonConfigurationIsAppliedToTheHalObjectMapper() { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.setServletContext(new MockServletContext()); - this.context.register(BaseConfig.class); - TestPropertyValues.of("spring.jackson.serialization.INDENT_OUTPUT:true") - .applyTo(this.context); - this.context.refresh(); - ObjectMapper objectMapper = this.context.getBean("_halObjectMapper", - ObjectMapper.class); - assertThat(objectMapper.getSerializationConfig() - .isEnabled(SerializationFeature.INDENT_OUTPUT)).isTrue(); + assertThat(this.context.getBeansOfType(HypermediaConfiguration.class)).isEmpty(); + assertThat(this.context.getBeansOfType(EntityLinksConfiguration.class)).isEmpty(); } @Test diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b2219a607784..402c87a802d5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -156,7 +156,7 @@ 4.0.1.RELEASE 2.0.2.RELEASE Lovelace-BUILD-SNAPSHOT - 0.24.0.RELEASE + 0.25.0.BUILD-SNAPSHOT 5.0.6.RELEASE 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE From 43e2df105c70608738c082a1cdb3ed2557a5a3c6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 15:57:09 +0100 Subject: [PATCH 223/701] Align with latest changes in Spring Data REST --- ...positoryRestMvcAutoConfigurationTests.java | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java index c552b8cad500..1fffb9bd8062 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,7 +18,6 @@ import java.net.URI; import java.util.Date; -import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -40,7 +39,7 @@ import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies; import org.springframework.data.rest.webmvc.BaseUri; -import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; +import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; import org.springframework.http.MediaType; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; @@ -146,24 +145,6 @@ public void backOffWithCustomConfiguration() { assertThat(bean.getBaseUri()).isEqualTo(URI.create("")); } - @Test - public void objectMappersAreConfiguredUsingObjectMapperBuilder() - throws JsonProcessingException { - load(TestConfigurationWithObjectMapperBuilder.class); - - assertThatDateIsFormattedCorrectly("halObjectMapper"); - assertThatDateIsFormattedCorrectly("objectMapper"); - } - - @Test - public void primaryObjectMapperIsAvailable() { - load(TestConfiguration.class); - Map objectMappers = this.context - .getBeansOfType(ObjectMapper.class); - assertThat(objectMappers.size()).isGreaterThan(1); - this.context.getBean(ObjectMapper.class); - } - public void assertThatDateIsFormattedCorrectly(String beanName) throws JsonProcessingException { ObjectMapper objectMapper = this.context.getBean(beanName, ObjectMapper.class); @@ -221,7 +202,7 @@ public Jackson2ObjectMapperBuilder objectMapperBuilder() { } - static class TestRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter { + static class TestRepositoryRestConfigurer implements RepositoryRestConfigurer { @Override public void configureRepositoryRestConfiguration( From a5b3d549b9d4cc65ad3e69f82d117874dbf03730 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 15:57:47 +0100 Subject: [PATCH 224/701] Ignore Data Elasticsearch test that fails due to DATAES-470 --- .../data/elasticsearch/ElasticsearchAutoConfigurationTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java index 709961f8cf6d..e0ad0c280c07 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.node.DiscoveryNode; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -63,6 +64,7 @@ public void useExistingClient() { } @Test + @Ignore("DATAES-470") public void createTransportClient() { this.context = new AnnotationConfigApplicationContext(); new ElasticsearchNodeTemplate().doWithNode((node) -> { From 87b72cc9818a28b7e4684db81d043ea1e6078d2d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 16:29:10 +0100 Subject: [PATCH 225/701] Polish DevTools auto-configuration tests to avoid bean overrides See gh-13609 --- .../autoconfigure/LocalDevToolsAutoConfigurationTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index 6555ab2fc398..35297c72a7bf 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -33,6 +33,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; @@ -281,7 +282,7 @@ public static class Config { } @Configuration - @Import({ ServletWebServerFactoryAutoConfiguration.class, + @ImportAutoConfiguration({ ServletWebServerFactoryAutoConfiguration.class, LocalDevToolsAutoConfiguration.class, ThymeleafAutoConfiguration.class }) public static class ConfigWithMockLiveReload { From 8cc0d5577e4583e922169e8a4075077b835f6532 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 19:54:21 +0100 Subject: [PATCH 226/701] Avoid unwanted bean overrides in spring-boot-test-autoconfigure See gh-13609 --- .../jdbc/TestDatabaseAutoConfiguration.java | 1 + ...igurationEnabledFalseIntegrationTests.java | 4 ++- ...figurationEnabledTrueIntegrationTests.java | 7 ++-- ...utoConfigurationSpringBootApplication.java | 34 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/{ => override}/OverrideAutoConfigurationEnabledFalseIntegrationTests.java (91%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/{ => override}/OverrideAutoConfigurationEnabledTrueIntegrationTests.java (85%) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationSpringBootApplication.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfiguration.java index d1ba458869b9..cefaf160d045 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfiguration.java @@ -105,6 +105,7 @@ private void process(BeanDefinitionRegistry registry, boolean primary = holder.getBeanDefinition().isPrimary(); logger.info("Replacing '" + beanName + "' DataSource bean with " + (primary ? "primary " : "") + "embedded version"); + registry.removeBeanDefinition(beanName); registry.registerBeanDefinition(beanName, createEmbeddedBeanDefinition(primary)); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledFalseIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledFalseIntegrationTests.java similarity index 91% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledFalseIntegrationTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledFalseIntegrationTests.java index adbe4cd07984..ce9152e88c4c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledFalseIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledFalseIntegrationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.test.autoconfigure; +package org.springframework.boot.test.autoconfigure.override; import org.junit.Rule; import org.junit.Test; @@ -25,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; +import org.springframework.boot.test.autoconfigure.ExampleTestConfig; +import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.ApplicationContext; import org.springframework.test.context.BootstrapWith; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledTrueIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledTrueIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledTrueIntegrationTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledTrueIntegrationTests.java index 7591e5cf6e03..d80da4fd05ca 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationEnabledTrueIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledTrueIntegrationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.test.autoconfigure; +package org.springframework.boot.test.autoconfigure.override; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,6 +22,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; +import org.springframework.boot.test.autoconfigure.ExampleTestConfig; +import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.ApplicationContext; import org.springframework.test.context.BootstrapWith; @@ -47,7 +49,8 @@ public class OverrideAutoConfigurationEnabledTrueIntegrationTests { @Test public void autoConfiguredContext() { ApplicationContext context = this.context; - assertThat(context.getBean(ExampleSpringBootApplication.class)).isNotNull(); + assertThat(context.getBean(OverrideAutoConfigurationSpringBootApplication.class)) + .isNotNull(); assertThat(context.getBean(ConfigurationPropertiesBindingPostProcessor.class)) .isNotNull(); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationSpringBootApplication.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationSpringBootApplication.java new file mode 100644 index 000000000000..133ffae36c89 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationSpringBootApplication.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.override; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; + +/** + * Example {@link SpringBootApplication @SpringBootApplication} for use with + * {@link OverrideAutoConfiguration} tests. + * + * @author Andy Wilkinson + */ +@SpringBootConfiguration +@EnableAutoConfiguration +public class OverrideAutoConfigurationSpringBootApplication { + +} From d7fcec1ada429e2a95387b3927e5f1883fb39778 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 10 Jul 2018 21:17:02 +0100 Subject: [PATCH 227/701] Remove the use of a bean override form SampleKafkaApplicationTests See gh-13609 --- .../kafka/SampleKafkaApplicationTests.java | 31 +++---------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java b/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java index 2eed0de557a2..7123c19a30c7 100644 --- a/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java @@ -15,17 +15,12 @@ */ package sample.kafka; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.rule.OutputCapture; -import org.springframework.context.annotation.Bean; import org.springframework.kafka.test.context.EmbeddedKafka; import org.springframework.test.context.junit4.SpringRunner; @@ -43,34 +38,18 @@ @EmbeddedKafka public class SampleKafkaApplicationTests { - private static final CountDownLatch latch = new CountDownLatch(1); - @Rule public OutputCapture outputCapture = new OutputCapture(); @Test public void testVanillaExchange() throws Exception { - assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + long end = System.currentTimeMillis() + 10000; + while (!this.outputCapture.toString().contains("A simple test message") + && System.currentTimeMillis() < end) { + Thread.sleep(250); + } assertThat(this.outputCapture.toString().contains("A simple test message")) .isTrue(); } - @TestConfiguration - public static class Config { - - @Bean - public Consumer consumer() { - return new Consumer() { - - @Override - public void processMessage(SampleMessage message) { - super.processMessage(message); - latch.countDown(); - } - - }; - } - - } - } From db58654492de8359c1af2e5aa4492c97085e9df8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 11 Jul 2018 09:14:15 +0100 Subject: [PATCH 228/701] Make JAXB API available to Groovy Templates when running on Java 9+ See gh-13670 --- .../pom.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spring-boot-samples/spring-boot-sample-web-groovy-templates/pom.xml b/spring-boot-samples/spring-boot-sample-web-groovy-templates/pom.xml index c57533602299..bf36407c2092 100755 --- a/spring-boot-samples/spring-boot-sample-web-groovy-templates/pom.xml +++ b/spring-boot-samples/spring-boot-sample-web-groovy-templates/pom.xml @@ -35,4 +35,18 @@ + + + java9 + + [9,) + + + + javax.xml.bind + jaxb-api + + + + From 29fcb10f8dd61ed5c3b2b295b6ffde596a568dbc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 11 Jul 2018 14:51:24 +0200 Subject: [PATCH 229/701] Polish --- .../META-INF/additional-spring-configuration-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c8ef53d679ff..07811eb92a57 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -176,7 +176,7 @@ "name": "spring.main.allow-bean-definition-overriding", "type": "java.lang.Boolean", "sourceType": "org.springframework.boot.SpringApplication", - "description": "Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed", + "description": "Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed.", "defaultValue": false }, { From 611f2332e6f8471a20472492eda956a16c20d1ba Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 11 Jul 2018 14:56:36 +0200 Subject: [PATCH 230/701] Polish Flyway keys --- .../src/main/asciidoc/appendix-application-properties.adoc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index a1b8e209bf33..432ac27ab7d3 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -522,20 +522,23 @@ content into your application. Rather, pick only the properties that you need. spring.flyway.baseline-description= # spring.flyway.baseline-on-migrate= # spring.flyway.baseline-version=1 # Version to start migration + spring.flyway.batch = # spring.flyway.check-location=true # Whether to check that migration scripts location exists. spring.flyway.clean-disabled= # spring.flyway.clean-on-validation-error= # spring.flyway.dry-run-output= # spring.flyway.enabled=true # Whether to enable flyway. - spring.flyway.encoding= # spring.flyway.error-handlers= # + spring.flyway.error-overrides= # spring.flyway.group= # + spring.flyway.ignore-ignored-migrations= # spring.flyway.ignore-future-migrations= # spring.flyway.ignore-missing-migrations= # spring.flyway.init-sqls= # SQL statements to execute to initialize a connection immediately after obtaining it. spring.flyway.installed-by= # spring.flyway.locations=classpath:db/migration # The locations of migrations scripts. spring.flyway.mixed= # + spring.flyway.oracle-sqlplus= # spring.flyway.out-of-order= # spring.flyway.password= # JDBC password to use if you want Flyway to create its own DataSource. spring.flyway.placeholder-prefix= # @@ -550,6 +553,7 @@ content into your application. Rather, pick only the properties that you need. spring.flyway.sql-migration-separator= # spring.flyway.sql-migration-suffix=.sql # spring.flyway.sql-migration-suffixes= # + spring.flyway.stream= # spring.flyway.table= # spring.flyway.target= # spring.flyway.undo-sql-migration-prefix= # From 6a48a440b2ec978908fa3768898cb22922fa2be7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 11 Jul 2018 17:25:21 +0100 Subject: [PATCH 231/701] Annotate our test annotations with @ExtendWith(SpringExtension.class) Closes gh-13739 --- .../src/main/asciidoc/spring-boot-features.adoc | 6 ++++-- .../spring-boot-test-autoconfigure/pom.xml | 5 +++++ .../test/autoconfigure/data/ldap/DataLdapTest.java | 4 ++++ .../test/autoconfigure/data/mongo/DataMongoTest.java | 4 ++++ .../test/autoconfigure/data/neo4j/DataNeo4jTest.java | 4 ++++ .../test/autoconfigure/data/redis/DataRedisTest.java | 4 ++++ .../boot/test/autoconfigure/jdbc/JdbcTest.java | 4 ++++ .../boot/test/autoconfigure/jooq/JooqTest.java | 4 ++++ .../boot/test/autoconfigure/orm/jpa/DataJpaTest.java | 4 ++++ .../test/autoconfigure/web/client/RestClientTest.java | 4 ++++ .../test/autoconfigure/web/reactive/WebFluxTest.java | 4 ++++ .../test/autoconfigure/web/servlet/WebMvcTest.java | 4 ++++ spring-boot-project/spring-boot-test/pom.xml | 10 +++++----- .../boot/test/context/SpringBootTest.java | 4 ++++ .../sample/SampleJunitJupiterApplicationTests.java | 5 +---- 15 files changed, 59 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 28c5e7ccf3d8..d1dd83ce5e5e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6186,8 +6186,10 @@ annotations are also provided for <> of an application. -TIP: Don't forget to also add `@RunWith(SpringRunner.class)` to your test, otherwise -the annotations will be ignored. +TIP: If you are using JUnit 4, don't forget to also add `@RunWith(SpringRunner.class)` to +your test, otherwise the annotations will be ignored. If you are using JUnit 5, there's no +need to add the equivalent `@ExtendWith(SpringExtension)` as `@SpringBootTest` and the +other `@…Test` annotations are already annotated with it. You can use the `webEnvironment` attribute of `@SpringBootTest` to further refine how your tests run: diff --git a/spring-boot-project/spring-boot-test-autoconfigure/pom.xml b/spring-boot-project/spring-boot-test-autoconfigure/pom.xml index 63e13a21fb34..3c8550b30aa6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-test-autoconfigure/pom.xml @@ -76,6 +76,11 @@ true + + org.junit.jupiter + junit-jupiter-api + true + org.seleniumhq.selenium htmlunit-driver diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java index 362f89cf7053..37d37eab688d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -32,6 +34,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; /** * Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)} @@ -52,6 +55,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataLdapTypeExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java index cb3544a8369d..a145c1e8862d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -32,6 +34,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; /** * Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)} @@ -53,6 +56,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataMongoTypeExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java index 81ebe31308ac..38b81a8da713 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -32,6 +34,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; /** @@ -55,6 +58,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataNeo4jTypeExcludeFilter.class) @Transactional diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java index 5d3df4355e37..31b36c261d5b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -32,6 +34,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; /** * Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)} @@ -49,6 +52,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataRedisTypeExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java index d8718b83215a..d553414a36c4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -33,6 +35,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; /** @@ -63,6 +66,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(JdbcTypeExcludeFilter.class) @Transactional diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java index 4e52fde508e8..de554d40e2bc 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -32,6 +34,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; /** @@ -56,6 +59,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(JooqTypeExcludeFilter.class) @Transactional diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java index 1e6f4380f878..a1d7cda0a083 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -35,6 +37,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; /** @@ -66,6 +69,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataJpaTypeExcludeFilter.class) @Transactional diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java index 18b2ca8c1276..de7d19a4f322 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -34,6 +36,7 @@ import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Component; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; @@ -64,6 +67,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(RestClientExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java index 26ca5b8b0ca0..f8f5e5f2acb3 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -34,6 +36,7 @@ import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; /** @@ -70,6 +73,7 @@ @Documented @Inherited @BootstrapWith(WebFluxTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(WebFluxTypeExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java index 4fe7b23c3539..f00702adc61e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; @@ -34,6 +36,7 @@ import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; /** @@ -72,6 +75,7 @@ @Documented @Inherited @BootstrapWith(WebMvcTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(WebMvcTypeExcludeFilter.class) @AutoConfigureCache diff --git a/spring-boot-project/spring-boot-test/pom.xml b/spring-boot-project/spring-boot-test/pom.xml index c178191642d3..57c734f394fe 100644 --- a/spring-boot-project/spring-boot-test/pom.xml +++ b/spring-boot-project/spring-boot-test/pom.xml @@ -85,6 +85,11 @@ kotlin-reflect true + + org.junit.jupiter + junit-jupiter-api + true + org.mockito mockito-core @@ -187,11 +192,6 @@ spring-webmvc test - - org.junit.jupiter - junit-jupiter-api - test - com.nhaarman mockito-kotlin diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.java index 736c439ec101..eda5941d129f 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.java @@ -23,6 +23,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.WebApplicationType; @@ -36,6 +38,7 @@ import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextLoader; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.context.WebApplicationContext; /** @@ -72,6 +75,7 @@ @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) public @interface SpringBootTest { /** diff --git a/spring-boot-samples/spring-boot-sample-junit-jupiter/src/test/java/sample/SampleJunitJupiterApplicationTests.java b/spring-boot-samples/spring-boot-sample-junit-jupiter/src/test/java/sample/SampleJunitJupiterApplicationTests.java index 4fcc0b5b522f..7d298d4a95e5 100644 --- a/spring-boot-samples/spring-boot-sample-junit-jupiter/src/test/java/sample/SampleJunitJupiterApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-junit-jupiter/src/test/java/sample/SampleJunitJupiterApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,17 +17,14 @@ package sample; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.Assertions.assertThat; -@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class SampleJunitJupiterApplicationTests { From 6d9fabf5bc60db59da5d6075d023cf2f065d41cb Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 11 Jul 2018 13:15:08 -0700 Subject: [PATCH 232/701] Harmonize mongo auto-configuration Provides a way to easily exclude `MongoAutoConfiguration` or `MongoReactiveAutoConfiguration` so that multiple mongo clients are not present. Fixes gh-12407 --- .../mongo/MongoDataAutoConfiguration.java | 40 ++-------- .../data/mongo/MongoDataConfiguration.java | 73 +++++++++++++++++++ .../MongoReactiveDataAutoConfiguration.java | 21 +++++- .../mongo/MongoReactiveAutoConfiguration.java | 3 +- .../MongoDataAutoConfigurationTests.java | 15 ++++ ...ngoReactiveDataAutoConfigurationTests.java | 20 ++++- 6 files changed, 131 insertions(+), 41 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 63c2ad1fe97b..9ff49965b952 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -16,30 +16,25 @@ package org.springframework.boot.autoconfigure.data.mongo; -import java.util.Collections; - import com.mongodb.ClientSessionOptions; import com.mongodb.DB; import com.mongodb.MongoClient; import com.mongodb.client.ClientSession; import com.mongodb.client.MongoDatabase; -import org.springframework.beans.BeanUtils; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.domain.EntityScanner; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; -import org.springframework.data.annotation.Persistent; -import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; @@ -48,7 +43,6 @@ import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; -import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.gridfs.GridFsTemplate; import org.springframework.util.Assert; @@ -73,17 +67,15 @@ */ @Configuration @ConditionalOnClass({ MongoClient.class, MongoTemplate.class }) +@ConditionalOnBean(MongoClient.class) @EnableConfigurationProperties(MongoProperties.class) +@Import(MongoDataConfiguration.class) @AutoConfigureAfter(MongoAutoConfiguration.class) public class MongoDataAutoConfiguration { - private final ApplicationContext applicationContext; - private final MongoProperties properties; - public MongoDataAutoConfiguration(ApplicationContext applicationContext, - MongoProperties properties) { - this.applicationContext = applicationContext; + public MongoDataAutoConfiguration(MongoProperties properties) { this.properties = properties; } @@ -112,22 +104,6 @@ public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, return mappingConverter; } - @Bean - @ConditionalOnMissingBean - public MongoMappingContext mongoMappingContext(MongoCustomConversions conversions) - throws ClassNotFoundException { - MongoMappingContext context = new MongoMappingContext(); - context.setInitialEntitySet(new EntityScanner(this.applicationContext) - .scan(Document.class, Persistent.class)); - Class strategyClass = this.properties.getFieldNamingStrategy(); - if (strategyClass != null) { - context.setFieldNamingStrategy( - (FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass)); - } - context.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); - return context; - } - @Bean @ConditionalOnMissingBean public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, @@ -137,12 +113,6 @@ public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, mongoTemplate.getConverter()); } - @Bean - @ConditionalOnMissingBean - public MongoCustomConversions mongoCustomConversions() { - return new MongoCustomConversions(Collections.emptyList()); - } - /** * {@link MongoDbFactory} decorator to respect * {@link MongoProperties#getGridFsDatabase()} if set. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.java new file mode 100644 index 000000000000..a10af3a1ab62 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.mongo; + +import java.util.Collections; + +import org.springframework.beans.BeanUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.domain.EntityScanner; +import org.springframework.boot.autoconfigure.mongo.MongoProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.annotation.Persistent; +import org.springframework.data.mapping.model.FieldNamingStrategy; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; + +/** + * Base configuration class for Spring Data's mongo support. + * + * @author Madhura Bhave + */ +@Configuration +class MongoDataConfiguration { + + private final ApplicationContext applicationContext; + + private final MongoProperties properties; + + MongoDataConfiguration(ApplicationContext applicationContext, + MongoProperties properties) { + this.applicationContext = applicationContext; + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean + public MongoMappingContext mongoMappingContext(MongoCustomConversions conversions) + throws ClassNotFoundException { + MongoMappingContext context = new MongoMappingContext(); + context.setInitialEntitySet(new EntityScanner(this.applicationContext) + .scan(Document.class, Persistent.class)); + Class strategyClass = this.properties.getFieldNamingStrategy(); + if (strategyClass != null) { + context.setFieldNamingStrategy( + (FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass)); + } + context.setSimpleTypeHolder(conversions.getSimpleTypeHolder()); + return context; + } + + @Bean + @ConditionalOnMissingBean + public MongoCustomConversions mongoCustomConversions() { + return new MongoCustomConversions(Collections.emptyList()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java index de16566c56e6..560747eee34b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java @@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.mongo.MongoProperties; @@ -27,10 +28,15 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.convert.MongoConverter; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; +import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive mongo @@ -47,9 +53,10 @@ */ @Configuration @ConditionalOnClass({ MongoClient.class, ReactiveMongoTemplate.class }) +@ConditionalOnBean(MongoClient.class) @EnableConfigurationProperties(MongoProperties.class) -@AutoConfigureAfter({ MongoReactiveAutoConfiguration.class, - MongoDataAutoConfiguration.class }) +@Import(MongoDataConfiguration.class) +@AutoConfigureAfter(MongoReactiveAutoConfiguration.class) public class MongoReactiveDataAutoConfiguration { private final MongoProperties properties; @@ -74,4 +81,14 @@ public ReactiveMongoTemplate reactiveMongoTemplate( return new ReactiveMongoTemplate(reactiveMongoDatabaseFactory, converter); } + @Bean + @ConditionalOnMissingBean(MongoConverter.class) + public MappingMongoConverter mappingMongoConverter(MongoMappingContext context, + MongoCustomConversions conversions) { + MappingMongoConverter mappingConverter = new MappingMongoConverter( + NoOpDbRefResolver.INSTANCE, context); + mappingConverter.setCustomConversions(conversions); + return mappingConverter; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java index 5e03c05809ee..de8ff484c6b2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java @@ -24,6 +24,7 @@ import com.mongodb.connection.netty.NettyStreamFactoryFactory; import com.mongodb.reactivestreams.client.MongoClient; import io.netty.channel.socket.SocketChannel; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -44,7 +45,7 @@ * @since 2.0.0 */ @Configuration -@ConditionalOnClass(MongoClient.class) +@ConditionalOnClass({ MongoClient.class, Flux.class }) @EnableConfigurationProperties(MongoProperties.class) public class MongoReactiveAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java index 6fc852fd2669..0080a6f64d99 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java @@ -22,9 +22,12 @@ import com.mongodb.MongoClient; import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.data.mongo.city.City; @@ -60,6 +63,9 @@ public class MongoDataAutoConfigurationTests { private AnnotationConfigApplicationContext context; + @Rule + public ExpectedException thrown = ExpectedException.none(); + @After public void close() { if (this.context != null) { @@ -162,6 +168,15 @@ public void registersDefaultSimpleTypesWithMappingContext() { assertThat(dateProperty.isEntity()).isFalse(); } + @Test + public void backsOffIfMongoClientBeanIsNotPresent() { + this.context = new AnnotationConfigApplicationContext(); + this.context.register(MongoDataAutoConfiguration.class); + this.context.refresh(); + this.thrown.expect(NoSuchBeanDefinitionException.class); + assertThat(this.context.getBean(MongoDataAutoConfiguration.class)).isNull(); + } + public void testFieldNamingStrategy(String strategy, Class expectedType) { this.context = new AnnotationConfigApplicationContext(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfigurationTests.java index f207ab853178..b201360e1eac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfigurationTests.java @@ -17,10 +17,12 @@ package org.springframework.boot.autoconfigure.data.mongo; import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; @@ -36,6 +38,9 @@ public class MongoReactiveDataAutoConfigurationTests { private AnnotationConfigApplicationContext context; + @Rule + public ExpectedException thrown = ExpectedException.none(); + @After public void close() { if (this.context != null) { @@ -46,11 +51,20 @@ public void close() { @Test public void templateExists() { this.context = new AnnotationConfigApplicationContext( - PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class); assertThat(this.context.getBeanNamesForType(ReactiveMongoTemplate.class)) .hasSize(1); } + @Test + public void backsOffIfMongoClientBeanIsNotPresent() { + this.context = new AnnotationConfigApplicationContext( + PropertyPlaceholderAutoConfiguration.class, + MongoReactiveDataAutoConfiguration.class); + this.thrown.expect(NoSuchBeanDefinitionException.class); + this.context.getBean(MongoReactiveDataAutoConfiguration.class); + } + } From 2e5f0c28738d4d4ea4cbf42de19321da09127a8a Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 12 Jul 2018 10:04:45 +0200 Subject: [PATCH 233/701] Fix WebMvc auto-conf tests after Framework change This commit adapts to a recent Spring Framework change (a40d25a) that turns no-op Spring MVC beans (infrastructure components that, given their configuration, won't contribute anything to the application) into `NullBean` instances. --- .../web/servlet/WebMvcAutoConfigurationTests.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 986fedc20a56..2b8f5b50c2e2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -191,9 +191,7 @@ public void resourceHandlerMappingOverrideAll() { public void resourceHandlerMappingDisabled() { this.contextRunner.withPropertyValues("spring.resources.add-mappings:false") .run((context) -> { - Map> locations = getResourceMappingLocations( - context); - assertThat(locations).isEmpty(); + assertThat(context.getBean("resourceHandlerMapping")).isEqualTo(null); }); } From 1b3fa3ff0dd6a146bf68633d4e21467d3ca82542 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 12 Jul 2018 12:33:40 +0900 Subject: [PATCH 234/701] Remove @since tag from getServlet() Closes gh-13757 --- .../boot/web/servlet/ServletRegistrationBean.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistrationBean.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistrationBean.java index cbdee46d2a44..b1297f8610e2 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistrationBean.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistrationBean.java @@ -112,7 +112,6 @@ public void setServlet(T servlet) { /** * Return the servlet being registered. * @return the servlet - * @since 2.0.4 */ public T getServlet() { return this.servlet; From b5cb074219eb72b41228b102cc9e6f036038d044 Mon Sep 17 00:00:00 2001 From: Miguel Gomes Date: Sun, 1 Jul 2018 01:17:47 +0100 Subject: [PATCH 235/701] Upgrade to Liquibase 3.6.2 See gh-13625 --- .../liquibase/LiquibaseAutoConfiguration.java | 6 +++ .../liquibase/LiquibaseProperties.java | 52 +++++++++++++++++++ .../spring-boot-dependencies/pom.xml | 2 +- .../appendix-application-properties.adoc | 4 ++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java index f847e7cb0fb6..32a8915e3005 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java @@ -126,6 +126,12 @@ public SpringLiquibase liquibase() { liquibase.setChangeLog(this.properties.getChangeLog()); liquibase.setContexts(this.properties.getContexts()); liquibase.setDefaultSchema(this.properties.getDefaultSchema()); + liquibase.setLiquibaseSchema(this.properties.getLiquibaseSchema()); + liquibase.setLiquibaseTablespace(this.properties.getLiquibaseTablespace()); + liquibase.setDatabaseChangeLogTable( + this.properties.getDatabaseChangeLogTable()); + liquibase.setDatabaseChangeLogLockTable( + this.properties.getDatabaseChangeLogLockTable()); liquibase.setDropFirst(this.properties.isDropFirst()); liquibase.setShouldRun(this.properties.isEnabled()); liquibase.setLabels(this.properties.getLabels()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java index 62f906c16518..ef3f2d195b5c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java @@ -53,6 +53,26 @@ public class LiquibaseProperties { */ private String defaultSchema; + /** + * Schema to use for Liquibase objects. + */ + private String liquibaseSchema; + + /** + * Tablespace to use for Liquibase objects. + */ + private String liquibaseTablespace; + + /** + * Name of table to use for tracking change history. + */ + private String databaseChangeLogTable; + + /** + * Name of table to use for tracking concurrent Liquibase usage. + */ + private String databaseChangeLogLockTable; + /** * Whether to first drop the database schema. */ @@ -132,6 +152,38 @@ public void setDefaultSchema(String defaultSchema) { this.defaultSchema = defaultSchema; } + public String getLiquibaseSchema() { + return this.liquibaseSchema; + } + + public void setLiquibaseSchema(String liquibaseSchema) { + this.liquibaseSchema = liquibaseSchema; + } + + public String getLiquibaseTablespace() { + return this.liquibaseTablespace; + } + + public void setLiquibaseTablespace(String liquibaseTablespace) { + this.liquibaseTablespace = liquibaseTablespace; + } + + public String getDatabaseChangeLogTable() { + return this.databaseChangeLogTable; + } + + public void setDatabaseChangeLogTable(String databaseChangeLogTable) { + this.databaseChangeLogTable = databaseChangeLogTable; + } + + public String getDatabaseChangeLogLockTable() { + return this.databaseChangeLogLockTable; + } + + public void setDatabaseChangeLogLockTable(String databaseChangeLogLockTable) { + this.databaseChangeLogLockTable = databaseChangeLogLockTable; + } + public boolean isDropFirst() { return this.dropFirst; } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 402c87a802d5..f227e4658ea7 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -118,7 +118,7 @@ 1.1.0 1.2.51 5.1.0.M1 - 3.6.1 + 3.6.2 2.11.0 1.2.3 1.18.0 diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 432ac27ab7d3..fe2a1b305bdd 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -566,6 +566,10 @@ content into your application. Rather, pick only the properties that you need. spring.liquibase.check-change-log-location=true # Whether to check that the change log location exists. spring.liquibase.contexts= # Comma-separated list of runtime contexts to use. spring.liquibase.default-schema= # Default database schema. + spring.liquibase.liquibase-schema= # Schema to use for Liquibase objects. + spring.liquibase.liquibase-tablespace= # Tablespace to use for Liquibase objects. + spring.liquibase.database-change-log-table= # Name of table to use for tracking change history. + spring.liquibase.database-change-log-lock-table= # Name of table to use for tracking concurrent Liquibase usage. spring.liquibase.drop-first=false # Whether to first drop the database schema. spring.liquibase.enabled=true # Whether to enable Liquibase support. spring.liquibase.labels= # Comma-separated list of runtime labels to use. From 4c7c328972c4a7d762d92e66fd3189ca7d28d3e9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 13 Jul 2018 11:40:45 +0200 Subject: [PATCH 236/701] Polish "Upgrade to Liquibase 3.6.2" Closes gh-13625 --- .../LiquibaseAutoConfigurationTests.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index 137ea6da095f..847b8ff1c673 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -46,6 +46,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.FileCopyUtils; @@ -143,6 +144,32 @@ public void overrideDefaultSchema() { .isEqualTo("public"))); } + @Test + public void overrideLiquibaseInfrastructure() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .withPropertyValues("spring.liquibase.liquibase-schema:public", + "spring.liquibase.liquibase-tablespace:infra", + "spring.liquibase.database-change-log-table:LIQUI_LOG", + "spring.liquibase.database-change-log-lock-table:LIQUI_LOCK") + .run((context) -> { + SpringLiquibase liquibase = context.getBean(SpringLiquibase.class); + assertThat(liquibase.getLiquibaseSchema()).isEqualTo("public"); + assertThat(liquibase.getLiquibaseTablespace()).isEqualTo("infra"); + assertThat(liquibase.getDatabaseChangeLogTable()) + .isEqualTo("LIQUI_LOG"); + assertThat(liquibase.getDatabaseChangeLogLockTable()) + .isEqualTo("LIQUI_LOCK"); + JdbcTemplate jdbcTemplate = new JdbcTemplate( + context.getBean(DataSource.class)); + assertThat(jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM public.LIQUI_LOG", Integer.class)) + .isEqualTo(1); + assertThat(jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM public.LIQUI_LOCK", Integer.class)) + .isEqualTo(1); + }); + } + @Test public void overrideDropFirst() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) From c59f31218a6f79a667426afbaf2f95afa170145f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 13 Jul 2018 10:59:37 +0100 Subject: [PATCH 237/701] Revert "Ignore Data Elasticsearch test that fails due to DATAES-470" Closes gh-13744 --- .../data/elasticsearch/ElasticsearchAutoConfigurationTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java index e0ad0c280c07..709961f8cf6d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java @@ -22,7 +22,6 @@ import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.node.DiscoveryNode; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -64,7 +63,6 @@ public void useExistingClient() { } @Test - @Ignore("DATAES-470") public void createTransportClient() { this.context = new AnnotationConfigApplicationContext(); new ElasticsearchNodeTemplate().doWithNode((node) -> { From 42bba4e1c58a7c413a6030c0e7b7ef58b955d075 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 13 Jul 2018 13:41:22 +0200 Subject: [PATCH 238/701] Document Liquibase default values Closes gh-13765 --- .../liquibase/LiquibaseProperties.java | 4 ++-- .../LiquibaseAutoConfigurationTests.java | 16 ++++++++++++++++ .../appendix-application-properties.adoc | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java index ef3f2d195b5c..8f2dc3c1a9dd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseProperties.java @@ -66,12 +66,12 @@ public class LiquibaseProperties { /** * Name of table to use for tracking change history. */ - private String databaseChangeLogTable; + private String databaseChangeLogTable = "DATABASECHANGELOG"; /** * Name of table to use for tracking concurrent Liquibase usage. */ - private String databaseChangeLogLockTable; + private String databaseChangeLogLockTable = "DATABASECHANGELOGLOCK"; /** * Whether to first drop the database schema. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java index 847b8ff1c673..bb1117f65eda 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfigurationTests.java @@ -127,6 +127,22 @@ public void changelogSql() { .isEqualTo("classpath:/db/changelog/db.changelog-override.sql"))); } + @Test + public void defaultValues() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) + .run(assertLiquibase((liquibase) -> { + LiquibaseProperties properties = new LiquibaseProperties(); + assertThat(liquibase.getDatabaseChangeLogTable()) + .isEqualTo(properties.getDatabaseChangeLogTable()); + assertThat(liquibase.getDatabaseChangeLogLockTable()) + .isEqualTo(properties.getDatabaseChangeLogLockTable()); + assertThat(liquibase.isDropFirst()) + .isEqualTo(properties.isDropFirst()); + assertThat(liquibase.isTestRollbackOnUpdate()) + .isEqualTo(properties.isTestRollbackOnUpdate()); + })); + } + @Test public void overrideContexts() { this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index fe2a1b305bdd..be06a22a2877 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -568,8 +568,8 @@ content into your application. Rather, pick only the properties that you need. spring.liquibase.default-schema= # Default database schema. spring.liquibase.liquibase-schema= # Schema to use for Liquibase objects. spring.liquibase.liquibase-tablespace= # Tablespace to use for Liquibase objects. - spring.liquibase.database-change-log-table= # Name of table to use for tracking change history. - spring.liquibase.database-change-log-lock-table= # Name of table to use for tracking concurrent Liquibase usage. + spring.liquibase.database-change-log-table=DATABASECHANGELOG # Name of table to use for tracking change history. + spring.liquibase.database-change-log-lock-table=DATABASECHANGELOGLOCK # Name of table to use for tracking concurrent Liquibase usage. spring.liquibase.drop-first=false # Whether to first drop the database schema. spring.liquibase.enabled=true # Whether to enable Liquibase support. spring.liquibase.labels= # Comma-separated list of runtime labels to use. From d1b85584308cc615a5a3e68be69130b3199fdd14 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 12 Jul 2018 16:54:43 -0700 Subject: [PATCH 239/701] Make /health and /info insecure by default Closes gh-13722 --- ...anagementWebSecurityAutoConfiguration.java | 64 +++++ ...anagementWebSecurityAutoConfiguration.java | 54 +++++ ...anagementWebSecurityConfigurerAdapter.java | 49 ++++ .../main/resources/META-INF/spring.factories | 2 + ...mentWebSecurityAutoConfigurationTests.java | 226 ++++++++++++++++++ ...mentWebSecurityAutoConfigurationTests.java | 133 +++++++++++ .../SampleActuatorApplicationTests.java | 14 +- .../SampleSecureWebFluxApplicationTests.java | 14 +- 8 files changed, 547 insertions(+), 9 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java new file mode 100644 index 000000000000..4ca3edfe8c87 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.reactive; + +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.info.InfoEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.WebFilterChainProxy; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Reactive Spring Security when + * actuator is on the classpath. Specifically, it permits access to the health and info + * endpoints while securing everything else. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class }) +@ConditionalOnMissingBean({ SecurityWebFilterChain.class, WebFilterChainProxy.class }) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) +@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class, + InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + ReactiveOAuth2ClientAutoConfiguration.class }) +public class ReactiveManagementWebSecurityAutoConfiguration { + + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + return http.authorizeExchange() + .matchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)) + .permitAll().anyExchange().authenticated().and().httpBasic().and() + .formLogin().and().build(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java new file mode 100644 index 000000000000..048f347dab5a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.servlet; + +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Security when actuator is + * on the classpath. Specifically, it permits access to the health and info endpoints + * while securing everything else. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass(WebSecurityConfigurerAdapter.class) +@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +@AutoConfigureBefore(SecurityAutoConfiguration.class) +@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class, + InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + OAuth2ClientAutoConfiguration.class }) +@Import({ ManagementWebSecurityConfigurerAdapter.class, + WebSecurityEnablerConfiguration.class }) +public class ManagementWebSecurityAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java new file mode 100644 index 000000000000..28ec587f5027 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.servlet; + +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.actuate.info.InfoEndpoint; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +/** + * The default configuration for web security when the actuator dependency is on the + * classpath. It is different from + * {@link org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration} + * in that it allows unauthenticated access to the {@link HealthEndpoint} and + * {@link InfoEndpoint}. If the user specifies their own + * {@link WebSecurityConfigurerAdapter}, this will back-off completely and the user should + * specify all the bits that they want to configure as part of the custom security + * configuration. + * + * @author Madhura Bhave + * @since 2.0.1 + */ +@Configuration +class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .requestMatchers( + EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)) + .permitAll().anyRequest().authenticated().and().formLogin().and() + .httpBasic(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index ca7b7da9193e..a08bdf2915fe 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -61,6 +61,8 @@ org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoCon org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java new file mode 100644 index 000000000000..52410d6dc289 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java @@ -0,0 +1,226 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.reactive; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.beans.BeansException; +import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration; +import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.http.server.reactive.MockServerHttpResponse; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.HttpWebHandlerAdapter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link ReactiveManagementWebSecurityAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveManagementWebSecurityAutoConfigurationTests { + + private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + HealthIndicatorAutoConfiguration.class, + HealthEndpointAutoConfiguration.class, + InfoEndpointAutoConfiguration.class, + EnvironmentEndpointAutoConfiguration.class, + EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + ReactiveSecurityAutoConfiguration.class, + ReactiveUserDetailsServiceAutoConfiguration.class, + ReactiveManagementWebSecurityAutoConfiguration.class)); + + @Test + public void permitAllForHealth() { + this.contextRunner.run(( + context) -> assertThat(getAuthenticateHeader(context, "/actuator/health")) + .isNull()); + } + + @Test + public void permitAllForInfo() { + this.contextRunner.run( + (context) -> assertThat(getAuthenticateHeader(context, "/actuator/info")) + .isNull()); + } + + @Test + public void securesEverythingElse() { + this.contextRunner.run((context) -> { + assertThat(getAuthenticateHeader(context, "/actuator").get(0)) + .contains("Basic realm="); + assertThat(getAuthenticateHeader(context, "/foo").toString()) + .contains("Basic realm="); + }); + } + + @Test + public void usesMatchersBasedOffConfiguredActuatorBasePath() { + this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/") + .run((context) -> { + assertThat(getAuthenticateHeader(context, "/health")).isNull(); + assertThat(getAuthenticateHeader(context, "/foo").get(0)) + .contains("Basic realm="); + }); + } + + @Test + public void backsOffIfCustomSecurityIsAdded() { + this.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class) + .run((context) -> { + assertThat(getLocationHeader(context, "/actuator/health").toString()) + .contains("/login"); + assertThat(getLocationHeader(context, "/foo")).isNull(); + }); + } + + @Test + public void backsOffWhenWebFilterChainProxyBeanPresent() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .withUserConfiguration(WebFilterChainProxyConfiguration.class) + .run((context) -> { + assertThat(getLocationHeader(context, "/health").toString()) + .contains("/login"); + assertThat(getLocationHeader(context, "/foo").toString()) + .contains("/login"); + }); + } + + private List getAuthenticateHeader( + AssertableReactiveWebApplicationContext context, String path) { + ServerWebExchange exchange = performFilter(context, path); + return exchange.getResponse().getHeaders().get(HttpHeaders.WWW_AUTHENTICATE); + } + + private ServerWebExchange performFilter( + AssertableReactiveWebApplicationContext context, String path) { + ServerWebExchange exchange = webHandler(context).createExchange( + MockServerHttpRequest.get(path).build(), new MockServerHttpResponse()); + WebFilterChainProxy proxy = context.getBean(WebFilterChainProxy.class); + proxy.filter(exchange, (serverWebExchange) -> Mono.empty()).block(); + return exchange; + } + + private URI getLocationHeader(AssertableReactiveWebApplicationContext context, + String path) { + ServerWebExchange exchange = performFilter(context, path); + return exchange.getResponse().getHeaders().getLocation(); + } + + private TestHttpWebHandlerAdapter webHandler( + AssertableReactiveWebApplicationContext context) { + TestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter( + mock(WebHandler.class)); + adapter.setApplicationContext(context); + return adapter; + } + + private static class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter { + + TestHttpWebHandlerAdapter(WebHandler delegate) { + super(delegate); + } + + @Override + protected ServerWebExchange createExchange(ServerHttpRequest request, + ServerHttpResponse response) { + return super.createExchange(request, response); + } + + } + + @Configuration + static class CustomSecurityConfiguration { + + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + return http.authorizeExchange().pathMatchers("/foo").permitAll().anyExchange() + .authenticated().and().formLogin().and().build(); + } + + } + + @Configuration + static class WebFilterChainProxyConfiguration { + + @Bean + public ReactiveAuthenticationManager authenticationManager() { + return mock(ReactiveAuthenticationManager.class); + } + + @Bean + public WebFilterChainProxy webFilterChainProxy(ServerHttpSecurity http) { + return new WebFilterChainProxy(getFilterChains(http)); + } + + @Bean + public TestServerHttpSecurity http( + ReactiveAuthenticationManager authenticationManager) { + TestServerHttpSecurity httpSecurity = new TestServerHttpSecurity(); + httpSecurity.authenticationManager(authenticationManager); + return httpSecurity; + } + + private List getFilterChains(ServerHttpSecurity http) { + return Collections.singletonList(http.authorizeExchange().anyExchange() + .authenticated().and().formLogin().and().build()); + } + + private static class TestServerHttpSecurity extends ServerHttpSecurity + implements ApplicationContextAware { + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + super.setApplicationContext(applicationContext); + } + + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java new file mode 100644 index 000000000000..8a853bc74261 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java @@ -0,0 +1,133 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.servlet; + +import java.io.IOException; + +import org.junit.Test; +import org.testcontainers.shaded.org.apache.http.HttpStatus; + +import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.mock.web.MockFilterChain; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.FilterChainProxy; +import org.springframework.web.context.WebApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ManagementWebSecurityAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ManagementWebSecurityAutoConfigurationTests { + + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + HealthIndicatorAutoConfiguration.class, + HealthEndpointAutoConfiguration.class, + InfoEndpointAutoConfiguration.class, + EnvironmentEndpointAutoConfiguration.class, + EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class, + SecurityAutoConfiguration.class, + ManagementWebSecurityAutoConfiguration.class)); + + @Test + public void permitAllForHealth() { + this.contextRunner.run((context) -> { + int status = getResponseStatus(context, "/actuator/health"); + assertThat(status).isEqualTo(HttpStatus.SC_OK); + }); + } + + @Test + public void permitAllForInfo() { + this.contextRunner.run((context) -> { + int status = getResponseStatus(context, "/actuator/info"); + assertThat(status).isEqualTo(HttpStatus.SC_OK); + }); + } + + @Test + public void securesEverythingElse() { + this.contextRunner.run((context) -> { + int status = getResponseStatus(context, "/actuator"); + assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED); + status = getResponseStatus(context, "/foo"); + assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED); + }); + } + + @Test + public void usesMatchersBasedOffConfiguredActuatorBasePath() { + this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/") + .run((context) -> { + int status = getResponseStatus(context, "/health"); + assertThat(status).isEqualTo(HttpStatus.SC_OK); + }); + } + + @Test + public void backOffIfCustomSecurityIsAdded() { + this.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class) + .run((context) -> { + int status = getResponseStatus(context, "/actuator/health"); + assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED); + status = getResponseStatus(context, "/foo"); + assertThat(status).isEqualTo(HttpStatus.SC_OK); + }); + } + + private int getResponseStatus(AssertableWebApplicationContext context, String path) + throws IOException, javax.servlet.ServletException { + FilterChainProxy filterChainProxy = context.getBean(FilterChainProxy.class); + MockServletContext servletContext = new MockServletContext(); + MockHttpServletResponse response = new MockHttpServletResponse(); + servletContext.setAttribute( + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); + MockHttpServletRequest request = new MockHttpServletRequest(servletContext); + request.setServletPath(path); + request.setMethod("GET"); + filterChainProxy.doFilter(request, response, new MockFilterChain()); + return response.getStatus(); + } + + @Configuration + static class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().antMatchers("/foo").permitAll().anyRequest() + .authenticated().and().formLogin().and().httpBasic(); + } + + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java index 421ab14a5cf1..8d5bf86e0f9b 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java @@ -119,20 +119,18 @@ public void testEnv() { } @Test - public void testHealth() { - ResponseEntity entity = this.restTemplate - .withBasicAuth("user", getPassword()) - .getForEntity("/actuator/health", String.class); + public void healthInsecureByDefault() { + ResponseEntity entity = this.restTemplate.getForEntity("/actuator/health", + String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("\"status\":\"UP\""); assertThat(entity.getBody()).doesNotContain("\"hello\":\"1\""); } @Test - public void testInfo() { - ResponseEntity entity = this.restTemplate - .withBasicAuth("user", getPassword()) - .getForEntity("/actuator/info", String.class); + public void infoInsecureByDefault() { + ResponseEntity entity = this.restTemplate.getForEntity("/actuator/info", + String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()) .contains("\"artifact\":\"spring-boot-sample-actuator\""); diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java index bc8b2311d6de..3bfff6a86029 100644 --- a/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java @@ -47,8 +47,20 @@ public void userDefinedMappingsSecureByDefault() { } @Test - public void actuatorsSecureByDefault() { + public void healthInsecureByDefault() { this.webClient.get().uri("/actuator/health").accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isOk(); + } + + @Test + public void infoInsecureByDefault() { + this.webClient.get().uri("/actuator/info").accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isOk(); + } + + @Test + public void otherActuatorsSecureByDefault() { + this.webClient.get().uri("/actuator/env").accept(MediaType.APPLICATION_JSON) .exchange().expectStatus().isUnauthorized(); } From c0574c84373fc5440e806ead7289af1c903b7087 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 13 Jul 2018 13:40:01 -0700 Subject: [PATCH 240/701] Update docs to reflect new health & info security See gh-13722 --- .../src/main/asciidoc/spring-boot-features.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 02d69f77a73a..db868b63800f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3260,8 +3260,8 @@ default. The `management.endpoints.web.exposure.include` property can be used to the actuators. If Spring Security is on the classpath and no other WebSecurityConfigurerAdapter is -present, the actuators are secured by Spring Boot auto-config. If you define a custom -`WebSecurityConfigurerAdapter`, Spring Boot auto-config will back off and you will be in +present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-config. +If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot auto-config will back off and you will be in full control of actuator access rules. NOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the From ac1f2a5817f3f2e07440e358642c2ce377d81657 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 14 Jul 2018 08:45:34 +0100 Subject: [PATCH 241/701] Polish --- ...veManagementWebSecurityAutoConfiguration.java | 1 + .../ManagementWebSecurityAutoConfiguration.java | 1 + .../ManagementWebSecurityConfigurerAdapter.java | 2 +- ...agementWebSecurityAutoConfigurationTests.java | 1 + ...agementWebSecurityAutoConfigurationTests.java | 1 + .../rest/SpringBootRepositoryRestConfigurer.java | 6 +++--- .../artemis/ArtemisAutoConfigurationTests.java | 10 ++++------ .../orm/jpa/HibernatePropertiesTests.java | 16 ++++++++-------- .../servlet/WebMvcAutoConfigurationTests.java | 5 ++--- ...WebServiceTemplateAutoConfigurationTests.java | 4 +--- .../docs/web/client/SampleWebClientTests.java | 5 ++++- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java index 4ca3edfe8c87..bb096d2c3215 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.autoconfigure.security.reactive; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java index 048f347dab5a..b953f572a0aa 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfiguration.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.autoconfigure.security.servlet; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java index 28ec587f5027..8d6d136a57af 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityConfigurerAdapter.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.autoconfigure.security.servlet; import org.springframework.boot.actuate.health.HealthEndpoint; @@ -32,7 +33,6 @@ * configuration. * * @author Madhura Bhave - * @since 2.0.1 */ @Configuration class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java index 52410d6dc289..963ca7bec44e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.autoconfigure.security.reactive; import java.net.URI; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java index 8a853bc74261..96530664be50 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/ManagementWebSecurityAutoConfigurationTests.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.boot.actuate.autoconfigure.security.servlet; import java.io.IOException; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java index 22791583381a..588ad4059344 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; -import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; +import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; /** @@ -34,7 +34,7 @@ * @author Stephane Nicoll */ @Order(0) -class SpringBootRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter { +class SpringBootRepositoryRestConfigurer implements RepositoryRestConfigurer { @Autowired(required = false) private Jackson2ObjectMapperBuilder objectMapperBuilder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java index df581ab612a2..c65583e6b4fd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java @@ -143,12 +143,10 @@ public void nativeConnectionFactoryCustomHost() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .withPropertyValues("spring.artemis.mode:native", "spring.artemis.host:192.168.1.144", "spring.artemis.port:9876") - .run((context) -> { - assertNettyConnectionFactory( - getActiveMQConnectionFactory( - context.getBean(ConnectionFactory.class)), - "192.168.1.144", 9876); - }); + .run((context) -> assertNettyConnectionFactory( + getActiveMQConnectionFactory( + context.getBean(ConnectionFactory.class)), + "192.168.1.144", 9876)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java index b3d362e5e0a3..869769d74730 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernatePropertiesTests.java @@ -106,10 +106,9 @@ public void hibernate5CustomNamingStrategiesViaJpaProperties() { @Test public void useNewIdGeneratorMappingsDefault() { - this.contextRunner.run(assertHibernateProperties((hibernateProperties) -> { - assertThat(hibernateProperties).containsEntry( - AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true"); - })); + this.contextRunner.run(assertHibernateProperties( + (hibernateProperties) -> assertThat(hibernateProperties).containsEntry( + AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true"))); } @Test @@ -117,10 +116,11 @@ public void useNewIdGeneratorMappingsFalse() { this.contextRunner .withPropertyValues( "spring.jpa.hibernate.use-new-id-generator-mappings:false") - .run(assertHibernateProperties((hibernateProperties) -> { - assertThat(hibernateProperties).containsEntry( - AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false"); - })); + .run(assertHibernateProperties( + (hibernateProperties) -> assertThat(hibernateProperties) + .containsEntry( + AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, + "false"))); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 2b8f5b50c2e2..afed1b4409a9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -190,9 +190,8 @@ public void resourceHandlerMappingOverrideAll() { @Test public void resourceHandlerMappingDisabled() { this.contextRunner.withPropertyValues("spring.resources.add-mappings:false") - .run((context) -> { - assertThat(context.getBean("resourceHandlerMapping")).isEqualTo(null); - }); + .run((context) -> assertThat(context.getBean("resourceHandlerMapping")) + .isEqualTo(null)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java index 6d647e104e08..8703e110fb70 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java @@ -93,9 +93,7 @@ public void webServiceTemplateShouldApplyCustomizer() { @Test public void builderShouldBeFreshForEachUse() { this.contextRunner.withUserConfiguration(DirtyWebServiceTemplateConfig.class) - .run((context) -> { - assertThat(context).hasNotFailed(); - }); + .run((context) -> assertThat(context).hasNotFailed()); } private ContextConsumer assertWebServiceTemplateBuilder( diff --git a/spring-boot-project/spring-boot-docs/src/test/java/org/springframework/boot/docs/web/client/SampleWebClientTests.java b/spring-boot-project/spring-boot-docs/src/test/java/org/springframework/boot/docs/web/client/SampleWebClientTests.java index ae74a85406cd..63e7e096e539 100644 --- a/spring-boot-project/spring-boot-docs/src/test/java/org/springframework/boot/docs/web/client/SampleWebClientTests.java +++ b/spring-boot-project/spring-boot-docs/src/test/java/org/springframework/boot/docs/web/client/SampleWebClientTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.docs.web.client; +import java.time.Duration; + import org.junit.Test; import org.junit.runner.RunWith; @@ -56,7 +58,8 @@ static class Config { @Bean public RestTemplateBuilder restTemplateBuilder() { - return new RestTemplateBuilder().setConnectTimeout(1000).setReadTimeout(1000); + return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1)) + .setReadTimeout(Duration.ofSeconds(1)); } } From 1ae420670a7b1ef0e83ace70214b5578313a94a6 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sun, 15 Jul 2018 23:57:45 +0900 Subject: [PATCH 242/701] Polish Closes gh-13776 --- .../web/embedded/NettyWebServerFactoryCustomizerTests.java | 6 +++--- .../src/main/asciidoc/spring-boot-features.adoc | 6 +++--- .../web/embedded/netty/NettyReactiveWebServerFactory.java | 1 + .../logging/logback/SpringBootJoranConfiguratorTests.java | 2 +- .../embedded/tomcat/TomcatServletWebServerFactoryTests.java | 3 +-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java index c2069b34c182..200b25211394 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java @@ -50,7 +50,7 @@ public void setup() { } @Test - public void deduceUseForwardHeadersUndertow() { + public void deduceUseForwardHeaders() { this.environment.setProperty("DYNO", "-"); NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); this.customizer.customize(factory); @@ -58,14 +58,14 @@ public void deduceUseForwardHeadersUndertow() { } @Test - public void defaultUseForwardHeadersUndertow() { + public void defaultUseForwardHeaders() { NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); this.customizer.customize(factory); verify(factory).setUseForwardHeaders(false); } @Test - public void setUseForwardHeadersUndertow() { + public void setUseForwardHeaders() { this.serverProperties.setUseForwardHeaders(true); NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); this.customizer.customize(factory); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index db868b63800f..82411c5f2fea 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -763,13 +763,13 @@ example: In the preceding example, if the `development` profile is active, the `server.address` property is `127.0.0.1`. Similarly, if the `production` *and* `eu-central` profiles are -active, the `server.address` property is `192.168.1.120`. If the `development` and +active, the `server.address` property is `192.168.1.120`. If the `development`, `production` and `eu-central` profiles are *not* enabled, then the value for the property is `192.168.1.100`. [NOTE] ==== -`spring.profiles` can therefore contains a simple profile name (for example `production`) +`spring.profiles` can therefore contain a simple profile name (for example `production`) or a profile expression. A profile expression allows for more complicated profile logic to be expressed, for example `production & (eu-central | eu-west)`. Check the {spring-reference}core.html#beans-definition-profiles-java[reference guide] for more @@ -1821,7 +1821,7 @@ ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action f The `` tag lets you optionally include or exclude sections of configuration based on the active Spring profiles. Profile sections are supported anywhere within the `` element. Use the `name` attribute to specify which -profile accepts the configuration. The ` tag can contains a simple profile +profile accepts the configuration. The `` tag can contain a simple profile name (for example `staging`) or a profile expression. A profile expression allows for more complicated profile logic to be expressed, for example `production & (eu-central | eu-west)`. Check the diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index 4cd40180c2ba..526cda5fef49 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -102,6 +102,7 @@ public void setLifecycleTimeout(Duration lifecycleTimeout) { /** * Set if x-forward-* headers should be processed. * @param useForwardHeaders if x-forward headers should be used + * @since 2.1.0 */ public void setUseForwardHeaders(boolean useForwardHeaders) { this.useForwardHeaders = useForwardHeaders; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java index 48a0a5f1c9db..c710eb04da70 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java @@ -118,7 +118,7 @@ public void profileExpressionMatchFirst() throws Exception { @Test public void profileExpressionMatchSecond() throws Exception { - this.environment.setActiveProfiles("production"); + this.environment.setActiveProfiles("test"); initialize("profile-expression.xml"); this.logger.trace("Hello"); this.out.expect(containsString("Hello")); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index c2b894d2d94b..c4a5d926272e 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -180,8 +180,7 @@ public void tomcatAdditionalConnectors() { TomcatServletWebServerFactory factory = getFactory(); Connector[] listeners = new Connector[4]; for (int i = 0; i < listeners.length; i++) { - Connector connector = new Connector(); - listeners[i] = connector; + listeners[i] = new Connector(); } factory.addAdditionalTomcatConnectors(listeners); this.webServer = factory.getWebServer(); From 9b60eef0e2e02c5ebbb2d33db3e7dbb1809a1b03 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 16 Jul 2018 10:19:38 +0200 Subject: [PATCH 243/701] Fix build after SPR-17034 in Spring Framework Since SPR-17034, the core container now behaves a bit differently when dealing with `null` beans. Given a `null` `HandlerMapping` bean named "resourceHandlerMapping": * `context.getBean("resourceHandlerMapping", HandlerMapping.class)` still returns a `NullBean` * `ListableBeanFactory.getBeansOfType` will return a Map of all existing beans, not including the `null` ones as values of the map. Closes gh-13760 --- .../autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index afed1b4409a9..626760608691 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -138,7 +138,7 @@ public void handlerAdaptersCreated() { @Test public void handlerMappingsCreated() { this.contextRunner.run((context) -> assertThat(context) - .getBeans(HandlerMapping.class).hasSize(7)); + .getBeans(HandlerMapping.class).hasSize(5)); } @Test From 0654dd4de25eb0f92b8faae40ece4b83756e2455 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 16 Jul 2018 13:49:37 +0200 Subject: [PATCH 244/701] Add JUnit Jupiter API to spring-boot-docs build This is required for the docs module to inspect Spring Boot annotations for meta-annotations. See gh-13739 --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 2d9920727496..6d7433118226 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -318,6 +318,11 @@ junit true + + org.junit.jupiter + junit-jupiter-api + true + net.sf.ehcache ehcache From 910e6dc4ccd6427a64d469f413460cab13cc6790 Mon Sep 17 00:00:00 2001 From: Taras Danylchuk Date: Tue, 26 Jun 2018 17:42:00 +0300 Subject: [PATCH 245/701] Allow to configure Quartz's "overwriteExistingJobs" property See gh-13582 --- .../quartz/QuartzAutoConfiguration.java | 2 + .../quartz/QuartzProperties.java | 13 +++++++ .../quartz/QuartzAutoConfigurationTests.java | 38 +++++++++++++++++++ .../appendix-application-properties.adoc | 1 + .../main/asciidoc/spring-boot-features.adoc | 11 +++++- 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 3e9d06f18067..1bd28a47ae1e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -103,6 +103,8 @@ public SchedulerFactoryBean quartzScheduler() { if (this.triggers != null && this.triggers.length > 0) { schedulerFactoryBean.setTriggers(this.triggers); } + schedulerFactoryBean + .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs()); customize(schedulerFactoryBean); return schedulerFactoryBean; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index de33c0e8e5ca..9b7c6d19f013 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -42,6 +42,11 @@ public class QuartzProperties { */ private final Map properties = new HashMap<>(); + /** + * Allows to reschedule existing jobs. + */ + private boolean overwriteExistingJobs = false; + private final Jdbc jdbc = new Jdbc(); public JobStoreType getJobStoreType() { @@ -60,6 +65,14 @@ public Jdbc getJdbc() { return this.jdbc; } + public boolean isOverwriteExistingJobs() { + return this.overwriteExistingJobs; + } + + public void setOverwriteExistingJobs(boolean overwriteExistingJobs) { + this.overwriteExistingJobs = overwriteExistingJobs; + } + public static class Jdbc { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/quartz/impl/" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 1d65a888def8..43e972ff6e68 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -29,6 +29,7 @@ import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SimpleScheduleBuilder; +import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; @@ -158,6 +159,28 @@ public void withTaskExecutor() { }); } + @Test + public void withOverwriteExistingJobsParameter() { + this.contextRunner.withUserConfiguration(OverwriteTriggerConfiguration.class) + .withPropertyValues("spring.quartz.overwriteExistingJobs=true", + "test-name=withConfiguredJobAndOverwrittenTrigger") + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getJobDetail(JobKey.jobKey("fooJob"))) + .isNotNull(); + Trigger fooTrigger = scheduler + .getTrigger(TriggerKey.triggerKey("fooTrigger")); + assertThat(fooTrigger).isNotNull(); + assertThat(((SimpleTrigger) fooTrigger).getRepeatInterval()) + .isEqualTo(30000); + Thread.sleep(1000L); + this.output.expect( + containsString("withConfiguredJobAndOverwrittenTrigger")); + this.output.expect(containsString("jobDataValue")); + }); + } + @Test public void withConfiguredJobAndTrigger() { this.contextRunner.withUserConfiguration(QuartzFullConfiguration.class) @@ -251,6 +274,21 @@ public Trigger fooTrigger() { } + @Configuration + @Import(QuartzFullConfiguration.class) + protected static class OverwriteTriggerConfiguration extends BaseQuartzConfiguration { + + @Bean + public Trigger anotherFooTrigger(JobDetail fooJob) { + SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() + .withIntervalInSeconds(30).repeatForever(); + + return TriggerBuilder.newTrigger().forJob(fooJob).withIdentity("fooTrigger") + .withSchedule(scheduleBuilder).build(); + } + + } + @Configuration protected static class QuartzCalendarsConfiguration extends BaseQuartzConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index be06a22a2877..a47237dd60d7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -146,6 +146,7 @@ content into your application. Rather, pick only the properties that you need. spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. spring.quartz.properties.*= # Additional Quartz Scheduler properties. + spring.quartz.overwriteExistingJobs=false # Whether overwriting existing job definitions is enabled. # REACTOR ({sc-spring-boot-autoconfigure}/reactor/core/ReactorCoreProperties.{sc-ext}[ReactorCoreProperties]) spring.reactor.stacktrace-mode.enabled=false # Whether Reactor should collect stacktrace information at runtime. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 82411c5f2fea..86831c237562 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5997,7 +5997,7 @@ provided with the Quartz library. It is also possible to provide a custom script setting the `spring.quartz.jdbc.schema` property. Quartz Scheduler configuration can be customized by using Quartz configuration properties -()`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow +(`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow programmatic `SchedulerFactoryBean` customization. NOTE: In particular, an `Executor` bean is not associated with the scheduler as Quartz @@ -6030,6 +6030,15 @@ in a similar manner, as shown in the following example: } ---- +Jobs created by configuration will not overwrite already registered jobs that have been +read in from a persistent job store. To enable overwriting existing job definitions set +`spring.quartz.overwriteExistingJobs` property: + +[source,properties,indent=0] +---- + spring.quartz.overwriteExistingJobs=true +---- + [[boot-features-integration]] From 66cb4ce3c7f9ba1091786d23737a4c0436862cf0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 16 Jul 2018 11:52:54 +0200 Subject: [PATCH 246/701] Polish "Allow to configure Quartz's "overwriteExistingJobs" property" Closes gh-13582 --- .../quartz/QuartzAutoConfiguration.java | 4 ++-- .../quartz/QuartzProperties.java | 24 +++++++++---------- .../quartz/QuartzAutoConfigurationTests.java | 11 ++------- .../appendix-application-properties.adoc | 2 +- .../main/asciidoc/spring-boot-features.adoc | 13 ++++------ 5 files changed, 21 insertions(+), 33 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 1bd28a47ae1e..1ad3d6fbda64 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -90,6 +90,8 @@ public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory( this.applicationContext.getAutowireCapableBeanFactory())); + schedulerFactoryBean + .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs()); if (!this.properties.getProperties().isEmpty()) { schedulerFactoryBean .setQuartzProperties(asProperties(this.properties.getProperties())); @@ -103,8 +105,6 @@ public SchedulerFactoryBean quartzScheduler() { if (this.triggers != null && this.triggers.length > 0) { schedulerFactoryBean.setTriggers(this.triggers); } - schedulerFactoryBean - .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs()); customize(schedulerFactoryBean); return schedulerFactoryBean; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index 9b7c6d19f013..1151a480aeec 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -38,14 +38,14 @@ public class QuartzProperties { private JobStoreType jobStoreType = JobStoreType.MEMORY; /** - * Additional Quartz Scheduler properties. + * Whether configured jobs should overwrite existing job definitions. */ - private final Map properties = new HashMap<>(); + private boolean overwriteExistingJobs = false; /** - * Allows to reschedule existing jobs. + * Additional Quartz Scheduler properties. */ - private boolean overwriteExistingJobs = false; + private final Map properties = new HashMap<>(); private final Jdbc jdbc = new Jdbc(); @@ -57,14 +57,6 @@ public void setJobStoreType(JobStoreType jobStoreType) { this.jobStoreType = jobStoreType; } - public Map getProperties() { - return this.properties; - } - - public Jdbc getJdbc() { - return this.jdbc; - } - public boolean isOverwriteExistingJobs() { return this.overwriteExistingJobs; } @@ -73,6 +65,14 @@ public void setOverwriteExistingJobs(boolean overwriteExistingJobs) { this.overwriteExistingJobs = overwriteExistingJobs; } + public Map getProperties() { + return this.properties; + } + + public Jdbc getJdbc() { + return this.jdbc; + } + public static class Jdbc { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/quartz/impl/" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 43e972ff6e68..3052eac92912 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -160,24 +160,17 @@ public void withTaskExecutor() { } @Test - public void withOverwriteExistingJobsParameter() { + public void withOverwriteExistingJobs() { this.contextRunner.withUserConfiguration(OverwriteTriggerConfiguration.class) - .withPropertyValues("spring.quartz.overwriteExistingJobs=true", - "test-name=withConfiguredJobAndOverwrittenTrigger") + .withPropertyValues("spring.quartz.overwrite-existing-jobs=true") .run((context) -> { assertThat(context).hasSingleBean(Scheduler.class); Scheduler scheduler = context.getBean(Scheduler.class); - assertThat(scheduler.getJobDetail(JobKey.jobKey("fooJob"))) - .isNotNull(); Trigger fooTrigger = scheduler .getTrigger(TriggerKey.triggerKey("fooTrigger")); assertThat(fooTrigger).isNotNull(); assertThat(((SimpleTrigger) fooTrigger).getRepeatInterval()) .isEqualTo(30000); - Thread.sleep(1000L); - this.output.expect( - containsString("withConfiguredJobAndOverwrittenTrigger")); - this.output.expect(containsString("jobDataValue")); }); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index a47237dd60d7..9882fcf46d45 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -146,7 +146,7 @@ content into your application. Rather, pick only the properties that you need. spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. spring.quartz.properties.*= # Additional Quartz Scheduler properties. - spring.quartz.overwriteExistingJobs=false # Whether overwriting existing job definitions is enabled. + spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. # REACTOR ({sc-spring-boot-autoconfigure}/reactor/core/ReactorCoreProperties.{sc-ext}[ReactorCoreProperties]) spring.reactor.stacktrace-mode.enabled=false # Whether Reactor should collect stacktrace information at runtime. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 86831c237562..bd75661aab21 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5996,6 +5996,10 @@ NOTE: By default, the database is detected and initialized by using the standard provided with the Quartz library. It is also possible to provide a custom script by setting the `spring.quartz.jdbc.schema` property. +By default, jobs created by configuration will not overwrite already registered jobs that +have been read from a persistent job store. To enable overwriting existing job definitions +set the `spring.quartz.overwrite-existing-jobs` property. + Quartz Scheduler configuration can be customized by using Quartz configuration properties (`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow programmatic `SchedulerFactoryBean` customization. @@ -6030,15 +6034,6 @@ in a similar manner, as shown in the following example: } ---- -Jobs created by configuration will not overwrite already registered jobs that have been -read in from a persistent job store. To enable overwriting existing job definitions set -`spring.quartz.overwriteExistingJobs` property: - -[source,properties,indent=0] ----- - spring.quartz.overwriteExistingJobs=true ----- - [[boot-features-integration]] From 3c67edafcd4c527eab8ece1e8081d29bb59e1615 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 16 Jul 2018 14:03:22 +0200 Subject: [PATCH 247/701] Expose more Quartz properties Closes gh-13782 --- .../quartz/QuartzAutoConfiguration.java | 6 ++ .../quartz/QuartzProperties.java | 56 ++++++++++++++++++ .../quartz/QuartzAutoConfigurationTests.java | 57 +++++++++++++++++++ .../appendix-application-properties.adoc | 4 ++ .../main/asciidoc/spring-boot-features.adoc | 7 ++- 5 files changed, 127 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 1ad3d6fbda64..22163734d96b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -90,6 +90,12 @@ public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory( this.applicationContext.getAutowireCapableBeanFactory())); + schedulerFactoryBean.setBeanName(this.properties.getSchedulerName()); + schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup()); + schedulerFactoryBean + .setStartupDelay((int) this.properties.getStartupDelay().getSeconds()); + schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown( + this.properties.isWaitForJobsToCompleteOnShutdown()); schedulerFactoryBean .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs()); if (!this.properties.getProperties().isEmpty()) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index 1151a480aeec..1f4e4984a998 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.quartz; +import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -37,6 +38,28 @@ public class QuartzProperties { */ private JobStoreType jobStoreType = JobStoreType.MEMORY; + /** + * Name of the scheduler. + */ + private String schedulerName = "quartzScheduler"; + + /** + * Whether to automatically start the scheduler after initialization. + */ + private boolean autoStartup = true; + + /** + * Delay after which the scheduler is started once initialization completes. Setting + * this property makes sense if no jobs should be run before the entire application + * has started up. + */ + private Duration startupDelay = Duration.ofSeconds(0); + + /** + * Whether to wait for running jobs to complete on shutdown. + */ + private boolean waitForJobsToCompleteOnShutdown = false; + /** * Whether configured jobs should overwrite existing job definitions. */ @@ -57,6 +80,39 @@ public void setJobStoreType(JobStoreType jobStoreType) { this.jobStoreType = jobStoreType; } + public String getSchedulerName() { + return this.schedulerName; + } + + public void setSchedulerName(String schedulerName) { + this.schedulerName = schedulerName; + } + + public boolean isAutoStartup() { + return this.autoStartup; + } + + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + + public Duration getStartupDelay() { + return this.startupDelay; + } + + public void setStartupDelay(Duration startupDelay) { + this.startupDelay = startupDelay; + } + + public boolean isWaitForJobsToCompleteOnShutdown() { + return this.waitForJobsToCompleteOnShutdown; + } + + public void setWaitForJobsToCompleteOnShutdown( + boolean waitForJobsToCompleteOnShutdown) { + this.waitForJobsToCompleteOnShutdown = waitForJobsToCompleteOnShutdown; + } + public boolean isOverwriteExistingJobs() { return this.overwriteExistingJobs; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 3052eac92912..0dcf5be66d22 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -37,6 +37,7 @@ import org.quartz.impl.calendar.WeeklyCalendar; import org.quartz.simpl.RAMJobStore; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -54,6 +55,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.quartz.LocalDataSourceJobStore; import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; @@ -224,6 +226,51 @@ public void withCustomizer() { }); } + @Test + public void validateDefaultProperties() { + this.contextRunner.withUserConfiguration(ManualSchedulerConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(SchedulerFactoryBean.class); + SchedulerFactoryBean schedulerFactory = context + .getBean(SchedulerFactoryBean.class); + DirectFieldAccessor dfa = new DirectFieldAccessor(schedulerFactory); + QuartzProperties properties = new QuartzProperties(); + assertThat(properties.isAutoStartup()) + .isEqualTo(schedulerFactory.isAutoStartup()); + assertThat((int) properties.getStartupDelay().getSeconds()) + .isEqualTo(dfa.getPropertyValue("startupDelay")); + assertThat(properties.isWaitForJobsToCompleteOnShutdown()).isEqualTo( + dfa.getPropertyValue("waitForJobsToCompleteOnShutdown")); + assertThat(properties.isOverwriteExistingJobs()) + .isEqualTo(dfa.getPropertyValue("overwriteExistingJobs")); + + }); + + } + + @Test + public void withCustomConfiguration() { + this.contextRunner.withPropertyValues( + "spring.quartz.scheduler-name=testScheduler", + "spring.quartz.auto-startup=false", "spring.quartz.startup-delay=1m", + "spring.quartz.wait-for-jobs-to-complete-on-shutdown=true", + "spring.quartz.wait-for-jobs-to-complete-on-shutdown=true", + "spring.quartz.overwrite-existing-jobs=true").run((context) -> { + assertThat(context).hasSingleBean(SchedulerFactoryBean.class); + SchedulerFactoryBean schedulerFactory = context + .getBean(SchedulerFactoryBean.class); + DirectFieldAccessor dfa = new DirectFieldAccessor(schedulerFactory); + assertThat(dfa.getPropertyValue("schedulerName")) + .isEqualTo("testScheduler"); + assertThat(schedulerFactory.isAutoStartup()).isFalse(); + assertThat(dfa.getPropertyValue("startupDelay")).isEqualTo(60); + assertThat(dfa.getPropertyValue("waitForJobsToCompleteOnShutdown")) + .isEqualTo(true); + assertThat(dfa.getPropertyValue("overwriteExistingJobs")) + .isEqualTo(true); + }); + } + @Import(ComponentThatUsesScheduler.class) @Configuration protected static class BaseQuartzConfiguration { @@ -318,6 +365,16 @@ public SchedulerFactoryBeanCustomizer customizer() { } + @Configuration + protected static class ManualSchedulerConfiguration { + + @Bean + public SchedulerFactoryBean quartzScheduler() { + return new SchedulerFactoryBean(); + } + + } + @Configuration protected static class MultipleDataSourceConfiguration extends BaseQuartzConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 9882fcf46d45..ef64b5673c66 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -141,12 +141,16 @@ content into your application. Rather, pick only the properties that you need. spring.profiles.include= # Unconditionally activate the specified comma-separated list of profiles (or list of profiles if using YAML). # QUARTZ SCHEDULER ({sc-spring-boot-autoconfigure}/quartz/QuartzProperties.{sc-ext}[QuartzProperties]) + spring.quartz.auto-startup=true # Whether to automatically start the scheduler after initialization. spring.quartz.jdbc.comment-prefix=-- # Prefix for single-line comments in SQL initialization scripts. spring.quartz.jdbc.initialize-schema=embedded # Database schema initialization mode. spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. spring.quartz.properties.*= # Additional Quartz Scheduler properties. + spring.quartz.scheduler-name=quartzScheduler # Name of the scheduler. + spring.quartz.startup-delay=0s # Delay after which the scheduler is started once initialization completes. spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. + spring.quartz.wait-for-jobs-to-complete-on-shutdown=false # Whether to wait for running jobs to complete on shutdown. # REACTOR ({sc-spring-boot-autoconfigure}/reactor/core/ReactorCoreProperties.{sc-ext}[ReactorCoreProperties]) spring.reactor.stacktrace-mode.enabled=false # Whether Reactor should collect stacktrace information at runtime. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index bd75661aab21..1fa65dbdb04a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6000,9 +6000,10 @@ By default, jobs created by configuration will not overwrite already registered have been read from a persistent job store. To enable overwriting existing job definitions set the `spring.quartz.overwrite-existing-jobs` property. -Quartz Scheduler configuration can be customized by using Quartz configuration properties -(`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow -programmatic `SchedulerFactoryBean` customization. +Quartz Scheduler configuration can be customized using `spring.quartz` properties and +`SchedulerFactoryBeanCustomizer` beans, which allow programmatic `SchedulerFactoryBean` +customization. Advanced Quartz configuration properties can be customized using +`spring.quartz.properties.*`. NOTE: In particular, an `Executor` bean is not associated with the scheduler as Quartz offers a way to configure the scheduler via `spring.quartz.properties`. If you need From d9215d5714661bfeea24e9decfcf7008ca6c3574 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 16 Jul 2018 15:44:12 +0200 Subject: [PATCH 248/701] Ignore test affect by a regression in Spring Data Lovelace --- .../sample/session/SampleSessionWebFluxApplicationTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java b/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java index d58c4210f279..7b541e082aec 100644 --- a/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java @@ -18,6 +18,7 @@ import java.util.Base64; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,6 +49,7 @@ public class SampleSessionWebFluxApplicationTests { private WebClient.Builder webClientBuilder; @Test + @Ignore public void userDefinedMappingsSecureByDefault() throws Exception { WebClient webClient = this.webClientBuilder .baseUrl("http://localhost:" + this.port + "/").build(); From 58df752af4a400564ef8c4450fe43dda34e3ef5c Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 17 Jul 2018 04:19:36 +0900 Subject: [PATCH 249/701] Polish See gh-13790 --- .../main/resources/META-INF/spring.factories | 2 +- ...ementWebSecurityAutoConfigurationTests.java | 7 ++----- .../MetricsWebClientFilterFunctionTests.java | 13 +++++-------- .../spring-boot-dependencies/pom.xml | 10 +++++----- .../main/asciidoc/spring-boot-features.adoc | 4 ++-- .../properties/CompositePropertySources.java | 18 +++++------------- 6 files changed, 20 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index a08bdf2915fe..94fac42c97e4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -61,8 +61,8 @@ org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoCon org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java index 963ca7bec44e..a790b5cbcb08 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java @@ -119,12 +119,9 @@ public void backsOffIfCustomSecurityIsAdded() { @Test public void backsOffWhenWebFilterChainProxyBeanPresent() { - this.contextRunner - .withConfiguration( - AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) - .withUserConfiguration(WebFilterChainProxyConfiguration.class) + this.contextRunner.withUserConfiguration(WebFilterChainProxyConfiguration.class) .run((context) -> { - assertThat(getLocationHeader(context, "/health").toString()) + assertThat(getLocationHeader(context, "/actuator/health").toString()) .contains("/login"); assertThat(getLocationHeader(context, "/foo").toString()) .contains("/login"); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java index 0e1eea7187d2..68f4caf3f095 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/client/MetricsWebClientFilterFunctionTests.java @@ -23,6 +23,7 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MockClock; +import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.simple.SimpleConfig; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Before; @@ -128,14 +129,10 @@ public void filterWhenExceptionAndRetryShouldNotCumulateRecordTime() { this.filterFunction.filter(request, exchange).retry(1) .onErrorResume(IllegalArgumentException.class, (t) -> Mono.empty()) .block(); - assertThat(this.registry - .get("http.client.requests").tags("method", "GET", "uri", - "/projects/spring-boot", "status", "CLIENT_ERROR") - .timer().count()).isEqualTo(2); - assertThat(this.registry.get("http.client.requests") - .tags("method", "GET", "uri", "/projects/spring-boot", "status", - "CLIENT_ERROR") - .timer().max(TimeUnit.MILLISECONDS)).isLessThan(600); + Timer timer = this.registry.get("http.client.requests").tags("method", "GET", + "uri", "/projects/spring-boot", "status", "CLIENT_ERROR").timer(); + assertThat(timer.count()).isEqualTo(2); + assertThat(timer.max(TimeUnit.MILLISECONDS)).isLessThan(600); } } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f227e4658ea7..f293a142a004 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1026,16 +1026,16 @@ javax.mail-api ${javax-mail.version} - - javax.persistence - javax.persistence-api - ${javax-persistence.version} - javax.money money-api ${javax-money.version} + + javax.persistence + javax.persistence-api + ${javax-persistence.version} + javax.servlet javax.servlet-api diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1fa65dbdb04a..401a3fb6fc4d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3260,8 +3260,8 @@ default. The `management.endpoints.web.exposure.include` property can be used to the actuators. If Spring Security is on the classpath and no other WebSecurityConfigurerAdapter is -present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-config. -If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot auto-config will back off and you will be in +present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-configuration. +If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot auto-configuration will back off and you will be in full control of actuator access rules. NOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java index 88a72adbf6fb..af5ee9499d96 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/CompositePropertySources.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Objects; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; @@ -45,23 +46,14 @@ public Iterator> iterator() { @Override public boolean contains(String name) { - for (PropertySources sources : this.propertySources) { - if (sources.contains(name)) { - return true; - } - } - return false; + return this.propertySources.stream() + .anyMatch((sources) -> sources.contains(name)); } @Override public PropertySource get(String name) { - for (PropertySources sources : this.propertySources) { - PropertySource source = sources.get(name); - if (source != null) { - return source; - } - } - return null; + return this.propertySources.stream().map((sources) -> sources.get(name)) + .filter(Objects::nonNull).findFirst().orElse(null); } } From fd6023fe498e47b5b5d5d53cf0129db4fcaf7b23 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Jul 2018 10:25:55 +0200 Subject: [PATCH 250/701] Polish contribution Closes gh-13790 --- .../src/main/asciidoc/spring-boot-features.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 401a3fb6fc4d..1b3338f27f9d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3260,9 +3260,9 @@ default. The `management.endpoints.web.exposure.include` property can be used to the actuators. If Spring Security is on the classpath and no other WebSecurityConfigurerAdapter is -present, all actuators other than `/health` and `/info` are secured by Spring Boot auto-configuration. -If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot auto-configuration will back off and you will be in -full control of actuator access rules. +present, all actuators other than `/health` and `/info` are secured by Spring Boot +auto-configuration. If you define a custom `WebSecurityConfigurerAdapter`, Spring Boot +auto-configuration will back off and you will be in full control of actuator access rules. NOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the exposed actuators do not contain sensitive information and/or are secured by placing them From ada699a9f6bb910b14de4a7c69fc62b1085a114a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 16 Jul 2018 16:58:17 +0200 Subject: [PATCH 251/701] Allow to customize the RabbitMQ RetryTemplate This commit adds the ability to customize the RetryTemplate used in the RabbitMQ infrastructure. The customizer is slightly unusual and offer a `Target` enum that define the component that will use the retry template: `SENDER` for the auto-configured `RabbitTemplate` and `LISTENER` for a listener container created by a `RabbitListenerContainerFactoryConfigurer`. Closes gh-13793 --- ...bitListenerContainerFactoryConfigurer.java | 17 ++- .../RabbitAnnotationDrivenConfiguration.java | 10 ++ .../amqp/RabbitAutoConfiguration.java | 18 ++-- .../amqp/RabbitRetryTemplateCustomizer.java | 58 ++++++++++ .../amqp/RetryTemplateFactory.java | 15 ++- .../amqp/RabbitAutoConfigurationTests.java | 100 ++++++++++++++++++ .../main/asciidoc/spring-boot-features.adoc | 14 ++- 7 files changed, 222 insertions(+), 10 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitRetryTemplateCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java index 989a43bbe53f..f5da11de3ab2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.amqp; +import java.util.List; + import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder; import org.springframework.amqp.rabbit.connection.ConnectionFactory; @@ -40,6 +42,8 @@ public abstract class AbstractRabbitListenerContainerFactoryConfigurer retryTemplateCustomizers; + private RabbitProperties rabbitProperties; /** @@ -59,6 +63,15 @@ protected void setMessageRecoverer(MessageRecoverer messageRecoverer) { this.messageRecoverer = messageRecoverer; } + /** + * Set the {@link RabbitRetryTemplateCustomizer} instances to use. + * @param retryTemplateCustomizers the retry template customizers + */ + protected void setRetryTemplateCustomizers( + List retryTemplateCustomizers) { + this.retryTemplateCustomizers = retryTemplateCustomizers; + } + /** * Set the {@link RabbitProperties} to use. * @param rabbitProperties the {@link RabbitProperties} @@ -108,7 +121,9 @@ protected void configure(T factory, ConnectionFactory connectionFactory, ? RetryInterceptorBuilder.stateless() : RetryInterceptorBuilder.stateful()); builder.retryOperations( - new RetryTemplateFactory().createRetryTemplate(retryConfig)); + new RetryTemplateFactory(this.retryTemplateCustomizers) + .createRetryTemplate(retryConfig, + RabbitRetryTemplateCustomizer.Target.LISTENER)); MessageRecoverer recoverer = (this.messageRecoverer != null ? this.messageRecoverer : new RejectAndDontRequeueRecoverer()); builder.recoverer(recoverer); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java index d7c227fdce83..a430002e98f6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.amqp; +import java.util.List; + import org.springframework.amqp.rabbit.annotation.EnableRabbit; import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils; @@ -45,13 +47,17 @@ class RabbitAnnotationDrivenConfiguration { private final ObjectProvider messageRecoverer; + private final ObjectProvider> retryTemplateCustomizers; + private final RabbitProperties properties; RabbitAnnotationDrivenConfiguration(ObjectProvider messageConverter, ObjectProvider messageRecoverer, + ObjectProvider> retryTemplateCustomizers, RabbitProperties properties) { this.messageConverter = messageConverter; this.messageRecoverer = messageRecoverer; + this.retryTemplateCustomizers = retryTemplateCustomizers; this.properties = properties; } @@ -61,6 +67,8 @@ public SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContai SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer(); configurer.setMessageConverter(this.messageConverter.getIfUnique()); configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique()); + configurer.setRetryTemplateCustomizers( + this.retryTemplateCustomizers.getIfAvailable()); configurer.setRabbitProperties(this.properties); return configurer; } @@ -82,6 +90,8 @@ public DirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContai DirectRabbitListenerContainerFactoryConfigurer configurer = new DirectRabbitListenerContainerFactoryConfigurer(); configurer.setMessageConverter(this.messageConverter.getIfUnique()); configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique()); + configurer.setRetryTemplateCustomizers( + this.retryTemplateCustomizers.getIfAvailable()); configurer.setRabbitProperties(this.properties); return configurer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index 2895a5f8a4a0..97ac74e23698 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.amqp; import java.time.Duration; +import java.util.List; import com.rabbitmq.client.Channel; @@ -151,15 +152,18 @@ private RabbitConnectionFactoryBean getRabbitConnectionFactoryBean( @Import(RabbitConnectionFactoryCreator.class) protected static class RabbitTemplateConfiguration { + private final RabbitProperties properties; + private final ObjectProvider messageConverter; - private final RabbitProperties properties; + private final ObjectProvider> retryTemplateCustomizers; - public RabbitTemplateConfiguration( + public RabbitTemplateConfiguration(RabbitProperties properties, ObjectProvider messageConverter, - RabbitProperties properties) { - this.messageConverter = messageConverter; + ObjectProvider> retryTemplateCustomizers) { this.properties = properties; + this.messageConverter = messageConverter; + this.retryTemplateCustomizers = retryTemplateCustomizers; } @Bean @@ -175,8 +179,10 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { template.setMandatory(determineMandatoryFlag()); RabbitProperties.Template properties = this.properties.getTemplate(); if (properties.getRetry().isEnabled()) { - template.setRetryTemplate(new RetryTemplateFactory() - .createRetryTemplate(properties.getRetry())); + template.setRetryTemplate(new RetryTemplateFactory( + this.retryTemplateCustomizers.getIfAvailable()) + .createRetryTemplate(properties.getRetry(), + RabbitRetryTemplateCustomizer.Target.SENDER)); } map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis) .to(template::setReceiveTimeout); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitRetryTemplateCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitRetryTemplateCustomizer.java new file mode 100644 index 000000000000..8b1a3e3ac30f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitRetryTemplateCustomizer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2018 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.autoconfigure.amqp; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; +import org.springframework.retry.support.RetryTemplate; + +/** + * Callback interface that can be used to customize a {@link RetryTemplate} used as part + * of the Rabbit infrastructure. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@FunctionalInterface +public interface RabbitRetryTemplateCustomizer { + + /** + * Callback to customize a {@link RetryTemplate} instance used in the context of the + * specified {@link Target}. + * @param target the {@link Target} of the retry template + * @param retryTemplate the template to customize + */ + void customize(Target target, RetryTemplate retryTemplate); + + /** + * Define the available target for a {@link RetryTemplate}. + */ + enum Target { + + /** + * {@link RabbitTemplate} target. + */ + SENDER, + + /** + * {@link AbstractMessageListenerContainer} target. + */ + LISTENER + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java index a98adca394e0..210a70fa35c1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RetryTemplateFactory.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.amqp; import java.time.Duration; +import java.util.List; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.retry.backoff.ExponentialBackOffPolicy; @@ -31,7 +32,14 @@ */ class RetryTemplateFactory { - public RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) { + private final List customizers; + + RetryTemplateFactory(List customizers) { + this.customizers = customizers; + } + + public RetryTemplate createRetryTemplate(RabbitProperties.Retry properties, + RabbitRetryTemplateCustomizer.Target target) { PropertyMapper map = PropertyMapper.get(); RetryTemplate template = new RetryTemplate(); SimpleRetryPolicy policy = new SimpleRetryPolicy(); @@ -44,6 +52,11 @@ public RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) { map.from(properties::getMaxInterval).whenNonNull().as(Duration::toMillis) .to(backOffPolicy::setMaxInterval); template.setBackOffPolicy(backOffPolicy); + if (this.customizers != null) { + for (RabbitRetryTemplateCustomizer customizer : this.customizers) { + customizer.customize(target, template); + } + } return template; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index 938f861fb916..b86deccb5be4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -32,6 +32,7 @@ import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; @@ -54,8 +55,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.retry.RetryPolicy; +import org.springframework.retry.backoff.BackOffPolicy; import org.springframework.retry.backoff.ExponentialBackOffPolicy; import org.springframework.retry.interceptor.MethodInvocationRecoverer; +import org.springframework.retry.policy.NeverRetryPolicy; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; @@ -280,6 +284,28 @@ public void testRabbitTemplateRetry() { }); } + @Test + public void testRabbitTemplateRetryWithCustomizer() { + this.contextRunner + .withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class) + .withPropertyValues("spring.rabbitmq.template.retry.enabled:true", + "spring.rabbitmq.template.retry.initialInterval:2000") + .run((context) -> { + RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class); + DirectFieldAccessor dfa = new DirectFieldAccessor(rabbitTemplate); + RetryTemplate retryTemplate = (RetryTemplate) dfa + .getPropertyValue("retryTemplate"); + assertThat(retryTemplate).isNotNull(); + dfa = new DirectFieldAccessor(retryTemplate); + assertThat(dfa.getPropertyValue("backOffPolicy")) + .isSameAs(context.getBean( + RabbitRetryTemplateCustomizerConfiguration.class).backOffPolicy); + ExponentialBackOffPolicy backOffPolicy = (ExponentialBackOffPolicy) dfa + .getPropertyValue("backOffPolicy"); + assertThat(backOffPolicy.getInitialInterval()).isEqualTo(100); + }); + } + @Test public void testRabbitTemplateExchangeAndRoutingKey() { this.contextRunner.withUserConfiguration(TestConfiguration.class) @@ -470,6 +496,53 @@ public void testDirectRabbitListenerContainerFactoryWithCustomSettings() { }); } + @Test + public void testSimpleRabbitListenerContainerFactoryRetryWithCustomizer() { + this.contextRunner + .withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class) + .withPropertyValues("spring.rabbitmq.listener.simple.retry.enabled:true", + "spring.rabbitmq.listener.simple.retry.maxAttempts:4") + .run((context) -> { + SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context + .getBean("rabbitListenerContainerFactory", + SimpleRabbitListenerContainerFactory.class); + assertListenerRetryTemplate(rabbitListenerContainerFactory, + context.getBean( + RabbitRetryTemplateCustomizerConfiguration.class).retryPolicy); + }); + } + + @Test + public void testDirectRabbitListenerContainerFactoryRetryWithCustomizer() { + this.contextRunner + .withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class) + .withPropertyValues("spring.rabbitmq.listener.type:direct", + "spring.rabbitmq.listener.direct.retry.enabled:true", + "spring.rabbitmq.listener.direct.retry.maxAttempts:4") + .run((context) -> { + DirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context + .getBean("rabbitListenerContainerFactory", + DirectRabbitListenerContainerFactory.class); + assertListenerRetryTemplate(rabbitListenerContainerFactory, + context.getBean( + RabbitRetryTemplateCustomizerConfiguration.class).retryPolicy); + }); + } + + private void assertListenerRetryTemplate( + AbstractRabbitListenerContainerFactory rabbitListenerContainerFactory, + RetryPolicy retryPolicy) { + DirectFieldAccessor dfa = new DirectFieldAccessor(rabbitListenerContainerFactory); + Advice[] adviceChain = (Advice[]) dfa.getPropertyValue("adviceChain"); + assertThat(adviceChain).isNotNull(); + assertThat(adviceChain.length).isEqualTo(1); + dfa = new DirectFieldAccessor(adviceChain[0]); + RetryTemplate retryTemplate = (RetryTemplate) dfa + .getPropertyValue("retryOperations"); + dfa = new DirectFieldAccessor(retryTemplate); + assertThat(dfa.getPropertyValue("retryPolicy")).isSameAs(retryPolicy); + } + @Test public void testRabbitListenerContainerFactoryConfigurersAreAvailable() { this.contextRunner.withUserConfiguration(TestConfiguration.class) @@ -793,6 +866,33 @@ public ConnectionNameStrategy myConnectionNameStrategy() { } + @Configuration + protected static class RabbitRetryTemplateCustomizerConfiguration { + + private final BackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); + + private final RetryPolicy retryPolicy = new NeverRetryPolicy(); + + @Bean + public RabbitRetryTemplateCustomizer rabbitTemplateRetryTemplateCustomizer() { + return (target, template) -> { + if (target.equals(RabbitRetryTemplateCustomizer.Target.SENDER)) { + template.setBackOffPolicy(this.backOffPolicy); + } + }; + } + + @Bean + public RabbitRetryTemplateCustomizer rabbitListenerRetryTemplateCustomizer() { + return (target, template) -> { + if (target.equals(RabbitRetryTemplateCustomizer.Target.LISTENER)) { + template.setRetryPolicy(this.retryPolicy); + } + }; + } + + } + @Configuration @EnableRabbit protected static class EnableRabbitConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1b3338f27f9d..9fadf5c81b34 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5362,7 +5362,16 @@ If necessary, any `org.springframework.amqp.core.Queue` that is defined as a bea automatically used to declare a corresponding queue on the RabbitMQ instance. To retry operations, you can enable retries on the `AmqpTemplate` (for example, in the -event that the broker connection is lost). Retries are disabled by default. +event that the broker connection is lost): + +[source,properties,indent=0] +---- + spring.rabbitmq.template.retry.enabled=true + spring.rabbitmq.template.retry.initial-interval=2s +---- + +Retries are disabled by default. You can also customize the `RetryTemplate` +programmatically by declaring a `RabbitRetryTemplateCustomizer` bean. @@ -5444,7 +5453,8 @@ You can enable retries to handle situations where your listener throws an except default, `RejectAndDontRequeueRecoverer` is used, but you can define a `MessageRecoverer` of your own. When retries are exhausted, the message is rejected and either dropped or routed to a dead-letter exchange if the broker is configured to do so. By default, -retries are disabled. +retries are disabled. You can also customize the `RetryTemplate` programmatically by +declaring a `RabbitRetryTemplateCustomizer` bean. IMPORTANT: By default, if retries are disabled and the listener throws an exception, the delivery is retried indefinitely. You can modify this behavior in two ways: Set the From 370af6df084bb38c3d6d23c1f428c415c094971d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Jul 2018 11:33:14 +0200 Subject: [PATCH 252/701] Revert "Ignore test affect by a regression in Spring Data Lovelace" This reverts commit d9215d5714661bfeea24e9decfcf7008ca6c3574. Closes gh-13784 --- .../sample/session/SampleSessionWebFluxApplicationTests.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java b/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java index 7b541e082aec..d58c4210f279 100644 --- a/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-session-webflux/src/test/java/sample/session/SampleSessionWebFluxApplicationTests.java @@ -18,7 +18,6 @@ import java.util.Base64; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,7 +48,6 @@ public class SampleSessionWebFluxApplicationTests { private WebClient.Builder webClientBuilder; @Test - @Ignore public void userDefinedMappingsSecureByDefault() throws Exception { WebClient webClient = this.webClientBuilder .baseUrl("http://localhost:" + this.port + "/").build(); From 4fee54cf24c4b8b481314a231a6e7cbe31e16d87 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 16 Jul 2018 11:45:06 -0700 Subject: [PATCH 253/701] Expose a TestDispatcherServlet bean in the MockMvcAutoConfiguration This commit also contains changes to `ServletContextInitializerBeans`. `ServletContextInitializerBeans` can now be configured to only look for specific ServletContextInitializer subclasses, defaulting to ServletContextIntializer.class. `SpringBootMockMvcBuilderCustomizer` only cares about filters so it was unnecessary to look for all `ServletContextInitializer`s. Additionally, adapting `Servlet` beans caused a cycle once the `DispatcherServlet` bean was added and the customizer only needs to adapt `Filter` beans. Closes gh-13241 --- .../web/servlet/MockMvcAutoConfiguration.java | 6 + .../SpringBootMockMvcBuilderCustomizer.java | 34 ++++- .../MockMvcAutoConfigurationTests.java | 47 ++++++ ...ringBootMockMvcBuilderCustomizerTests.java | 135 ++++++++++++++++++ .../ServletContextInitializerBeans.java | 29 ++-- .../ServletContextInitializerBeansTests.java | 45 +++++- 6 files changed, 284 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfiguration.java index 28922d6a1b4a..b3713e058125 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfiguration.java @@ -86,6 +86,12 @@ public MockMvc mockMvc(MockMvcBuilder builder) { return builder.build(); } + @Bean + @ConditionalOnMissingBean + public DispatcherServlet dispatcherServlet(MockMvc mockMvc) { + return mockMvc.getDispatcherServlet(); + } + private static class MockMvcDispatcherServletCustomizer implements DispatcherServletCustomizer { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java index 2b137a2296e1..a0b18038b77e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java @@ -28,9 +28,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.RegistrationBean; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializerBeans; import org.springframework.context.ApplicationContext; @@ -106,8 +108,7 @@ private LinesWriter getLinesWriter() { } private void addFilters(ConfigurableMockMvcBuilder builder) { - ServletContextInitializerBeans initializers = new ServletContextInitializerBeans( - this.context); + FilterRegistrationBeans initializers = new FilterRegistrationBeans(this.context); for (ServletContextInitializer initializer : initializers) { if (initializer instanceof FilterRegistrationBean) { addFilter(builder, (FilterRegistrationBean) initializer); @@ -319,4 +320,33 @@ private PrintStream getPrintStream() { } + private static class FilterRegistrationBeans extends ServletContextInitializerBeans { + + FilterRegistrationBeans(ListableBeanFactory beanFactory) { + super(beanFactory, FilterRegistrationBean.class, + DelegatingFilterProxyRegistrationBean.class); + } + + @Override + protected void addAdaptableBeans(ListableBeanFactory beanFactory) { + addAsRegistrationBean(beanFactory, Filter.class, + new FilterRegistrationBeanAdapter()); + } + + private static class FilterRegistrationBeanAdapter + implements RegistrationBeanAdapter { + + @Override + public RegistrationBean createRegistrationBean(String name, Filter source, + int totalNumberOfSourceBeans) { + FilterRegistrationBean bean = new FilterRegistrationBean<>( + source); + bean.setName(name); + return bean; + } + + } + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfigurationTests.java new file mode 100644 index 000000000000..27fcb7e551b9 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcAutoConfigurationTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.web.servlet; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.DispatcherServlet; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link MockMvcAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class MockMvcAutoConfigurationTests { + + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MockMvcAutoConfiguration.class)); + + @Test + public void registersDispatcherServletFromMockMvc() { + this.contextRunner.run((context) -> { + MockMvc mockMvc = context.getBean(MockMvc.class); + assertThat(context).hasSingleBean(DispatcherServlet.class); + assertThat(context.getBean(DispatcherServlet.class)) + .isEqualTo(mockMvc.getDispatcherServlet()); + }); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java new file mode 100644 index 000000000000..e281e3f02ceb --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java @@ -0,0 +1,135 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.web.servlet; + +import java.util.List; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; + +import org.junit.Test; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringBootMockMvcBuilderCustomizer}. + * + * @author Madhura Bhave + */ +public class SpringBootMockMvcBuilderCustomizerTests { + + private SpringBootMockMvcBuilderCustomizer customizer; + + @Test + @SuppressWarnings("unchecked") + public void customizeShouldAddFilters() { + AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + MockServletContext servletContext = new MockServletContext(); + context.setServletContext(servletContext); + context.register(ServletConfiguration.class, FilterConfiguration.class); + context.refresh(); + DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(context); + this.customizer = new SpringBootMockMvcBuilderCustomizer(context); + this.customizer.customize(builder); + FilterRegistrationBean registrationBean = (FilterRegistrationBean) context + .getBean("filterRegistrationBean"); + Filter testFilter = (Filter) context.getBean("testFilter"); + Filter otherTestFilter = registrationBean.getFilter(); + List filters = (List) ReflectionTestUtils.getField(builder, + "filters"); + assertThat(filters).containsExactlyInAnyOrder(testFilter, otherTestFilter); + } + + static class ServletConfiguration { + + @Bean + public TestServlet testServlet() { + return new TestServlet(); + } + + } + + static class FilterConfiguration { + + @Bean + public FilterRegistrationBean filterRegistrationBean() { + return new FilterRegistrationBean<>(new OtherTestFilter()); + } + + @Bean + public TestFilter testFilter() { + return new TestFilter(); + } + + } + + static class TestServlet extends HttpServlet { + + } + + static class TestFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) { + + } + + @Override + public void destroy() { + + } + + } + + static class OtherTestFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) { + + } + + @Override + public void destroy() { + + } + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index c3663de2efc4..ef032ed2ac92 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -18,6 +18,7 @@ import java.util.AbstractCollection; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.EventListener; @@ -73,10 +74,16 @@ public class ServletContextInitializerBeans private final MultiValueMap, ServletContextInitializer> initializers; + private final List> initializerTypes; + private List sortedList; - public ServletContextInitializerBeans(ListableBeanFactory beanFactory) { + public ServletContextInitializerBeans(ListableBeanFactory beanFactory, + Class... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); + this.initializerTypes = (initializerTypes.length != 0 + ? Arrays.asList(initializerTypes) + : Collections.singletonList(ServletContextInitializer.class)); addServletContextInitializerBeans(beanFactory); addAdaptableBeans(beanFactory); List sortedInitializers = this.initializers.values() @@ -88,10 +95,12 @@ public ServletContextInitializerBeans(ListableBeanFactory beanFactory) { } private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { - for (Entry initializerBean : getOrderedBeansOfType( - beanFactory, ServletContextInitializer.class)) { - addServletContextInitializerBean(initializerBean.getKey(), - initializerBean.getValue(), beanFactory); + for (Class initializerType : this.initializerTypes) { + for (Entry initializerBean : getOrderedBeansOfType( + beanFactory, initializerType)) { + addServletContextInitializerBean(initializerBean.getKey(), + initializerBean.getValue(), beanFactory); + } } } @@ -152,7 +161,7 @@ private String getResourceDescription(String beanName, } @SuppressWarnings("unchecked") - private void addAdaptableBeans(ListableBeanFactory beanFactory) { + protected void addAdaptableBeans(ListableBeanFactory beanFactory) { MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory); addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig)); @@ -172,8 +181,8 @@ private MultipartConfigElement getMultipartConfig(ListableBeanFactory beanFactor return (beans.isEmpty() ? null : beans.get(0).getValue()); } - private void addAsRegistrationBean(ListableBeanFactory beanFactory, Class type, - RegistrationBeanAdapter adapter) { + protected void addAsRegistrationBean(ListableBeanFactory beanFactory, + Class type, RegistrationBeanAdapter adapter) { addAsRegistrationBean(beanFactory, type, type, adapter); } @@ -248,8 +257,10 @@ public int size() { /** * Adapter to convert a given Bean type into a {@link RegistrationBean} (and hence a * {@link ServletContextInitializer}). + * + * @param the type of the Bean to adapt */ - private interface RegistrationBeanAdapter { + protected interface RegistrationBeanAdapter { RegistrationBean createRegistrationBean(String name, T source, int totalNumberOfSourceBeans); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index 944715063311..6e2b9113b4a9 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -20,6 +20,7 @@ import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; +import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; @@ -59,7 +60,17 @@ public void filterThatImplementsServletContextInitializerIsOnlyRegisteredOnce() assertThat(initializerBeans.iterator()).hasOnlyElementsOfType(TestFilter.class); } - private void load(Class configuration) { + @Test + public void looksForInitializerBeansOfSpecifiedType() { + load(TestConfiguration.class); + ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( + this.context.getBeanFactory(), TestServletContextInitializer.class); + assertThat(initializerBeans.size()).isEqualTo(1); + assertThat(initializerBeans.iterator()) + .hasOnlyElementsOfType(TestServletContextInitializer.class); + } + + private void load(Class... configuration) { this.context = new AnnotationConfigApplicationContext(configuration); } @@ -81,6 +92,20 @@ public TestFilter testFilter() { } + static class TestConfiguration { + + @Bean + public TestServletContextInitializer testServletContextInitializer() { + return new TestServletContextInitializer(); + } + + @Bean + public OtherTestServletContextInitializer otherTestServletContextInitializer() { + return new OtherTestServletContextInitializer(); + } + + } + static class TestServlet extends HttpServlet implements ServletContextInitializer { @Override @@ -115,4 +140,22 @@ public void destroy() { } + static class TestServletContextInitializer implements ServletContextInitializer { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + + } + + } + + static class OtherTestServletContextInitializer implements ServletContextInitializer { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + + } + + } + } From f88ebc06ff7c01102b0415b8ac4e45d20ea3fbdb Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 17 Jul 2018 16:02:03 -0700 Subject: [PATCH 254/701] Add support for OIDC Configuration Provider Closes gh-13210 --- .../spring-boot-autoconfigure/pom.xml | 5 + .../oauth2/client/OAuth2ClientProperties.java | 17 +++ ...h2ClientPropertiesRegistrationAdapter.java | 30 +++++ ...entPropertiesRegistrationAdapterTests.java | 107 ++++++++++++++++++ .../spring-boot-dependencies/pom.xml | 2 +- .../src/main/resources/application.yml | 8 +- .../SampleOAuth2ClientApplicationTests.java | 7 +- .../src/main/resources/application.yml | 8 +- ...eReactiveOAuth2ClientApplicationTests.java | 15 +-- 9 files changed, 187 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index ad95125becfb..ff4e84fdbceb 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -725,6 +725,11 @@ json-path test + + com.squareup.okhttp3 + mockwebserver + test + com.sun.xml.messaging.saaj saaj-impl diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index bfbe10884c08..6afaf988ef66 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -208,6 +208,15 @@ public static class Provider { */ private String jwkSetUri; + /** + * URI that an OpenID Connect Provider asserts as its Issuer Identifier. If the + * issuer provided is "https://example.com", then an "OpenID Provider + * Configuration Request" will be made to + * "https://example.com/.well-known/openid-configuration". The result is expected + * to be an "OpenID Provider Configuration Response". + */ + private String issuerUri; + public String getAuthorizationUri() { return this.authorizationUri; } @@ -248,6 +257,14 @@ public void setJwkSetUri(String jwkSetUri) { this.jwkSetUri = jwkSetUri; } + public String getIssuerUri() { + return this.issuerUri; + } + + public void setIssuerUri(String issuerUri) { + this.issuerUri = issuerUri; + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index 4927c2605972..36ca11d0a7e3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -25,6 +25,7 @@ import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.core.convert.ConversionException; import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; +import org.springframework.security.config.oauth2.client.oidc.OidcConfigurationProvider; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -37,6 +38,7 @@ * * @author Phillip Webb * @author Thiago Hirata + * @author Madhura Bhave * @since 2.1.0 */ public final class OAuth2ClientPropertiesRegistrationAdapter { @@ -54,6 +56,13 @@ public static Map getClientRegistrations( private static ClientRegistration getClientRegistration(String registrationId, Registration properties, Map providers) { + String issuer = getIssuerIfPossible(registrationId, properties.getProvider(), + providers); + if (issuer != null) { + return OidcConfigurationProvider.issuer(issuer).registrationId(registrationId) + .clientId(properties.getClientId()) + .clientSecret(properties.getClientSecret()).build(); + } Builder builder = getBuilder(registrationId, properties.getProvider(), providers); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(properties::getClientId).to(builder::clientId); @@ -70,6 +79,27 @@ private static ClientRegistration getClientRegistration(String registrationId, return builder.build(); } + private static String getIssuerIfPossible(String registrationId, + String configuredProviderId, Map providers) { + String providerId = (configuredProviderId != null ? configuredProviderId + : registrationId); + if (providers.containsKey(providerId)) { + Provider provider = providers.get(providerId); + String issuer = provider.getIssuerUri(); + if (issuer != null) { + return cleanIssuerPath(issuer); + } + } + return null; + } + + private static String cleanIssuerPath(String issuer) { + if (issuer.endsWith("/")) { + return issuer.substring(0, issuer.length() - 1); + } + return issuer; + } + private static Builder getBuilder(String registrationId, String configuredProviderId, Map providers) { String providerId = (configuredProviderId != null ? configuredProviderId diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 353c76909151..4a6f6eb41c71 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -17,16 +17,26 @@ package org.springframework.boot.autoconfigure.security.oauth2.client; import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import static org.assertj.core.api.Assertions.assertThat; @@ -40,6 +50,15 @@ */ public class OAuth2ClientPropertiesRegistrationAdapterTests { + private MockWebServer server; + + @After + public void cleanup() throws Exception { + if (this.server != null) { + this.server.shutdown(); + } + } + @Rule public ExpectedException thrown = ExpectedException.none(); @@ -217,4 +236,92 @@ public void getClientRegistrationsWhenProviderNotSpecifiedAndUnknownProviderShou OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties); } + @Test + public void oidcProviderConfigurationWhenProviderNotSpecifiedOnRegistration() + throws Exception { + Registration registration = new Registration(); + registration.setClientId("clientId"); + registration.setClientSecret("clientSecret"); + testOidcConfiguration(registration, "okta"); + } + + @Test + public void oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() + throws Exception { + Registration registration = new Registration(); + registration.setProvider("okta-oidc"); + registration.setClientId("clientId"); + registration.setClientSecret("clientSecret"); + testOidcConfiguration(registration, "okta-oidc"); + } + + private void testOidcConfiguration(Registration registration, String providerId) + throws Exception { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + OAuth2ClientProperties properties = new OAuth2ClientProperties(); + Provider provider = new Provider(); + provider.setIssuerUri(issuer); + properties.getProvider().put(providerId, provider); + properties.getRegistration().put("okta", registration); + Map registrations = OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(properties); + ClientRegistration adapted = registrations.get("okta"); + ProviderDetails providerDetails = adapted.getProviderDetails(); + assertThat(adapted.getClientAuthenticationMethod()) + .isEqualTo(ClientAuthenticationMethod.BASIC); + assertThat(adapted.getAuthorizationGrantType()) + .isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); + assertThat(adapted.getRegistrationId()).isEqualTo("okta"); + assertThat(adapted.getClientName()).isEqualTo(cleanIssuerPath); + assertThat(adapted.getScopes()).containsOnly("openid"); + assertThat(providerDetails.getAuthorizationUri()) + .isEqualTo("https://example.com/o/oauth2/v2/auth"); + assertThat(providerDetails.getTokenUri()) + .isEqualTo("https://example.com/oauth2/v4/token"); + assertThat(providerDetails.getJwkSetUri()) + .isEqualTo("https://example.com/oauth2/v3/certs"); + assertThat(providerDetails.getUserInfoEndpoint().getUri()) + .isEqualTo("https://example.com/oauth2/v3/userinfo"); + } + + private String cleanIssuerPath(String issuer) { + if (issuer.endsWith("/")) { + return issuer.substring(0, issuer.length() - 1); + } + return issuer; + } + + private void setupMockResponse(String issuer) throws Exception { + MockResponse mockResponse = new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .setBody(new ObjectMapper().writeValueAsString(getResponse(issuer))) + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + this.server.enqueue(mockResponse); + } + + private Map getResponse(String issuer) { + Map response = new HashMap<>(); + response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth"); + response.put("claims_supported", Collections.emptyList()); + response.put("code_challenge_methods_supported", Collections.emptyList()); + response.put("id_token_signing_alg_values_supported", Collections.emptyList()); + response.put("issuer", issuer); + response.put("jwks_uri", "https://example.com/oauth2/v3/certs"); + response.put("response_types_supported", Collections.emptyList()); + response.put("revocation_endpoint", "https://example.com/o/oauth2/revoke"); + response.put("scopes_supported", Collections.singletonList("openid")); + response.put("subject_types_supported", Collections.singletonList("public")); + response.put("grant_types_supported", + Collections.singletonList("authorization_code")); + response.put("token_endpoint", "https://example.com/oauth2/v4/token"); + response.put("token_endpoint_auth_methods_supported", + Collections.singletonList("client_secret_basic")); + response.put("userinfo_endpoint", "https://example.com/oauth2/v3/userinfo"); + return response; + } + } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5747aa72c90d..31d10e23e755 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -163,7 +163,7 @@ 1.2.0.RELEASE 2.0.2.BUILD-SNAPSHOT 1.2.2.RELEASE - 5.1.0.M1 + 5.1.0.BUILD-SNAPSHOT Apple-SR3 3.0.1.RELEASE 3.23.1 diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml index 220007d7e4b3..e0a70da4e018 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml @@ -16,4 +16,10 @@ spring: client-name: Github email provider: github scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github \ No newline at end of file + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + google-oidc: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + provider: + google-oidc: + issuer-uri: https://accounts.google.com \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java index 52ef0cd31977..8df3b29edf20 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java @@ -33,7 +33,9 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { - "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret" }) + "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret", + "GOOGLE-CLIENT-ID=my-google-client-id", + "GOOGLE-CLIENT-SECRET=my-google-client-secret" }) public class SampleOAuth2ClientApplicationTests { @LocalServerPort @@ -55,7 +57,8 @@ public void loginShouldHaveBothOAuthClientsToChooseFrom() { ResponseEntity entity = this.restTemplate.getForEntity("/login", String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-1"); + assertThat(entity.getBody()).contains("/oauth2/authorization/google"); + assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); } diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml index 220007d7e4b3..e0a70da4e018 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -16,4 +16,10 @@ spring: client-name: Github email provider: github scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github \ No newline at end of file + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + google-oidc: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + provider: + google-oidc: + issuer-uri: https://accounts.google.com \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java index 74fd195dac60..66fce8a191cd 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java @@ -28,7 +28,9 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { - "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret" }) + "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret", + "GOOGLE-CLIENT-ID=my-google-client-id", + "GOOGLE-CLIENT-SECRET=my-google-client-secret" }) public class SampleReactiveOAuth2ClientApplicationTests { @Autowired @@ -36,17 +38,16 @@ public class SampleReactiveOAuth2ClientApplicationTests { @Test public void everythingShouldRedirectToLogin() { - this.webTestClient.get().uri("/").exchange() - .expectStatus().isFound() - .expectHeader().valueEquals("Location", "/login"); + this.webTestClient.get().uri("/").exchange().expectStatus().isFound() + .expectHeader().valueEquals("Location", "/login"); } @Test public void loginShouldHaveBothOAuthClientsToChooseFrom() { - byte[] body = this.webTestClient.get().uri("/login").exchange() - .expectStatus().isOk() - .returnResult(String.class).getResponseBodyContent(); + byte[] body = this.webTestClient.get().uri("/login").exchange().expectStatus() + .isOk().returnResult(String.class).getResponseBodyContent(); String bodyString = new String(body); + assertThat(bodyString).contains("/oauth2/authorization/google"); assertThat(bodyString).contains("/oauth2/authorization/github-client-1"); assertThat(bodyString).contains("/oauth2/authorization/github-client-2"); } From 4e01eb865bc77c1031644c06679ea0368ea6ad05 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 18 Jul 2018 09:53:09 +0200 Subject: [PATCH 255/701] Polish See gh-13210 --- .../oauth2/client/SampleOAuth2ClientApplicationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java index 8df3b29edf20..f286cddbac17 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java @@ -58,7 +58,7 @@ public void loginShouldHaveBothOAuthClientsToChooseFrom() { String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("/oauth2/authorization/google"); - assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); + assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-1"); assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); } From ceaac988473481fc56cfbfc84f914289ff79fb37 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 18 Jul 2018 12:27:13 -0700 Subject: [PATCH 256/701] Update docs with OIDC provider configuration See gh-13210 --- .../oauth2/client/OAuth2ClientProperties.java | 6 +----- .../src/main/asciidoc/spring-boot-features.adoc | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index 6afaf988ef66..f229839e9097 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -209,11 +209,7 @@ public static class Provider { private String jwkSetUri; /** - * URI that an OpenID Connect Provider asserts as its Issuer Identifier. If the - * issuer provided is "https://example.com", then an "OpenID Provider - * Configuration Request" will be made to - * "https://example.com/.well-known/openid-configuration". The result is expected - * to be an "OpenID Provider Configuration Response". + * URI that an OpenID Connect Provider asserts as its Issuer Identifier. */ private String issuerUri; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index f7683efcee2d..b758f2f5f228 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3240,6 +3240,21 @@ In other words, the two configurations in the following example use the Google p spring.security.oauth2.client.registration.google.client-secret=password ---- +For OpenID Connect providers that support https://openid.net/specs/openid-connect-discovery-1_0.html[OpenID Connect discovery], +the configuration can be further simplified. The provider needs to be configured with an `issuer-uri` which is the +URI that the it asserts as its Issuer Identifier. For example, if the +`issuer-uri` provided is "https://example.com", then an `OpenID Provider Configuration Request` +will be made to "https://example.com/.well-known/openid-configuration". The result is expected +to be an `OpenID Provider Configuration Response`. The following example shows how an OpenID Connect +Provider can be configured with the `issuer-uri`: + +[source,properties,indent=0] +---- + spring.security.oauth2.client.registration.oidc-provider.client-id=abcd + spring.security.oauth2.client.registration.oidc-provider.client-secret=password + spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/ +---- + [[boot-features-security-oauth2-server]] From 184cd0c708f6767d190d2168b1ae84f0106bef70 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 19 Jul 2018 13:58:19 +0200 Subject: [PATCH 257/701] Avoid CGLIB requirement in MessageSourceAutoConfiguration Closes gh-13824 --- .../autoconfigure/context/MessageSourceAutoConfiguration.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java index d3a16cdb54ff..ec87833c6fcc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java @@ -64,8 +64,7 @@ public MessageSourceProperties messageSourceProperties() { } @Bean - public MessageSource messageSource() { - MessageSourceProperties properties = messageSourceProperties(); + public MessageSource messageSource(MessageSourceProperties properties) { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray( From bc7db86c8c0e58c7dc1c5f02e03aa0c816d2ab9b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 19 Jul 2018 09:58:29 +0200 Subject: [PATCH 258/701] Consistently apply exclude on auto-configuration Previously, exclude of an import selector was applied only locally. In other words, if one import selector imports `AcmeAutoConfiguration` and another one exclude it, it would still be imported because exclude were applied separately This commit collects the outcome of all auto-configuration import selectors and then apply exclusions in a single pass. Closes gh-12586 --- .../AutoConfigurationImportSelector.java | 126 +++++++++++++++--- .../condition/ConditionEvaluationReport.java | 13 +- .../ImportAutoConfigurationTests.java | 29 +++- ...tAutoConfigurationImportListenerTests.java | 32 ++++- 4 files changed, 177 insertions(+), 23 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index dadd0faba163..6cb236f12475 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -18,7 +18,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -40,6 +42,7 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DeferredImportSelector; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; @@ -70,6 +73,8 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { + private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry(); + private static final String[] NO_IMPORTS = {}; private static final Log logger = LogFactory @@ -92,6 +97,24 @@ public String[] selectImports(AnnotationMetadata annotationMetadata) { } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); + AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( + autoConfigurationMetadata, annotationMetadata); + return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); + } + + /** + * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata} + * of the importing @{@link Configuration} class. + * @param autoConfigurationMetadata the auto-configuration metadata + * @param annotationMetadata the annotation metadata of the configuration class + * @return the auto-configurations that should be imported + */ + protected AutoConfigurationEntry getAutoConfigurationEntry( + AutoConfigurationMetadata autoConfigurationMetadata, + AnnotationMetadata annotationMetadata) { + if (!isEnabled(annotationMetadata)) { + return EMPTY_ENTRY; + } AnnotationAttributes attributes = getAttributes(annotationMetadata); List configurations = getCandidateConfigurations(annotationMetadata, attributes); @@ -101,7 +124,7 @@ public String[] selectImports(AnnotationMetadata annotationMetadata) { configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); - return StringUtils.toStringArray(configurations); + return new AutoConfigurationEntry(configurations, exclusions); } @Override @@ -357,13 +380,17 @@ public int getOrder() { private static class AutoConfigurationGroup implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware { + private final Map entries = new LinkedHashMap<>(); + + private final List autoConfigurationEntries = new ArrayList<>(); + private ClassLoader beanClassLoader; private BeanFactory beanFactory; private ResourceLoader resourceLoader; - private final Map entries = new LinkedHashMap<>(); + private AutoConfigurationMetadata autoConfigurationMetadata; @Override public void setBeanClassLoader(ClassLoader classLoader) { @@ -383,29 +410,63 @@ public void setResourceLoader(ResourceLoader resourceLoader) { @Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { - String[] imports = deferredImportSelector.selectImports(annotationMetadata); - for (String importClassName : imports) { - this.entries.put(importClassName, annotationMetadata); + Assert.state( + deferredImportSelector instanceof AutoConfigurationImportSelector, + String.format( + "AutoConfigurationImportSelector only supports %s implementations, got %s", + AutoConfigurationImportSelector.class.getSimpleName(), + deferredImportSelector.getClass().getName())); + AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) + .getAutoConfigurationEntry(getAutoConfigurationMetadata(), + annotationMetadata); + this.autoConfigurationEntries.add(autoConfigurationEntry); + for (String importClassName : autoConfigurationEntry.getConfigurations()) { + this.entries.putIfAbsent(importClassName, annotationMetadata); } } @Override public Iterable selectImports() { - return sortAutoConfigurations().stream() - .map((importClassName) -> new Entry(this.entries.get(importClassName), - importClassName)) - .collect(Collectors.toList()); + if (this.autoConfigurationEntries.isEmpty()) { + return Collections.emptyList(); + } + Set allExclusions = this.autoConfigurationEntries.stream() + .map(AutoConfigurationEntry::getExclusions) + .flatMap(Collection::stream).collect(Collectors.toSet()); + Set processedConfigurations = new LinkedHashSet<>(); + Set processedExclusions = new LinkedHashSet<>(); + this.autoConfigurationEntries.forEach((entry) -> { + List configurations = new ArrayList<>(entry.getConfigurations()); + configurations.removeAll(allExclusions); + configurations.removeIf(processedConfigurations::contains); + Set exclusions = new HashSet<>(entry.getExclusions()); + exclusions.removeIf(processedExclusions::contains); + // This now represents the exact state of this entry based on the + // state of all other entries + processedConfigurations.addAll(configurations); + processedExclusions.addAll(exclusions); + }); + + return sortAutoConfigurations(processedConfigurations, + getAutoConfigurationMetadata()) + .stream() + .map((importClassName) -> new Entry( + this.entries.get(importClassName), importClassName)) + .collect(Collectors.toList()); } - private List sortAutoConfigurations() { - List autoConfigurations = new ArrayList<>(this.entries.keySet()); - if (this.entries.size() <= 1) { - return autoConfigurations; + private AutoConfigurationMetadata getAutoConfigurationMetadata() { + if (this.autoConfigurationMetadata == null) { + this.autoConfigurationMetadata = AutoConfigurationMetadataLoader + .loadMetadata(this.beanClassLoader); } - AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader - .loadMetadata(this.beanClassLoader); + return this.autoConfigurationMetadata; + } + + private List sortAutoConfigurations(Set configurations, + AutoConfigurationMetadata autoConfigurationMetadata) { return new AutoConfigurationSorter(getMetadataReaderFactory(), - autoConfigurationMetadata).getInPriorityOrder(autoConfigurations); + autoConfigurationMetadata).getInPriorityOrder(configurations); } private MetadataReaderFactory getMetadataReaderFactory() { @@ -421,4 +482,37 @@ private MetadataReaderFactory getMetadataReaderFactory() { } + protected static class AutoConfigurationEntry { + + private final List configurations; + + private final Set exclusions; + + private AutoConfigurationEntry() { + this.configurations = Collections.EMPTY_LIST; + this.exclusions = Collections.EMPTY_SET; + } + + /** + * Create an entry with the configurations that were contributed and their + * exclusions. + * @param configurations the configurations that should be imported + * @param exclusions the exclusions that were applied to the original list + */ + AutoConfigurationEntry(Collection configurations, + Collection exclusions) { + this.configurations = new ArrayList<>(configurations); + this.exclusions = new HashSet<>(exclusions); + } + + public List getConfigurations() { + return this.configurations; + } + + public Set getExclusions() { + return this.exclusions; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java index 128b7cf3996e..9823a2f0291e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java @@ -43,6 +43,7 @@ * @author Dave Syer * @author Phillip Webb * @author Andy Wilkinson + * @author Stephane Nicoll */ public final class ConditionEvaluationReport { @@ -56,9 +57,9 @@ public final class ConditionEvaluationReport { private ConditionEvaluationReport parent; - private List exclusions = Collections.emptyList(); + private final List exclusions = new ArrayList<>(); - private Set unconditionalClasses = new HashSet<>(); + private final Set unconditionalClasses = new HashSet<>(); /** * Private constructor. @@ -92,7 +93,7 @@ public void recordConditionEvaluation(String source, Condition condition, */ public void recordExclusions(Collection exclusions) { Assert.notNull(exclusions, "exclusions must not be null"); - this.exclusions = new ArrayList<>(exclusions); + this.exclusions.addAll(exclusions); } /** @@ -102,7 +103,7 @@ public void recordExclusions(Collection exclusions) { */ public void recordEvaluationCandidates(List evaluationCandidates) { Assert.notNull(evaluationCandidates, "evaluationCandidates must not be null"); - this.unconditionalClasses = new HashSet<>(evaluationCandidates); + this.unconditionalClasses.addAll(evaluationCandidates); } /** @@ -145,7 +146,9 @@ public List getExclusions() { * @return the names of the unconditional classes */ public Set getUnconditionalClasses() { - return Collections.unmodifiableSet(this.unconditionalClasses); + Set filtered = new HashSet<>(this.unconditionalClasses); + filtered.removeIf(this.exclusions::contains); + return Collections.unmodifiableSet(filtered); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java index bc9421747af1..1934f91be5da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java @@ -56,7 +56,19 @@ public void excluding() { .containsExactly("ConfigA", "ConfigB", "ConfigD"); } - private List getImportedConfigBeans(Class config) { + @Test + public void excludeAppliedGlobally() { + assertThat(getImportedConfigBeans(ExcludeDConfig.class, ImportADConfig.class)) + .containsExactly("ConfigA"); + } + + @Test + public void excludeWithRedundancy() { + assertThat(getImportedConfigBeans(ExcludeADConfig.class, ExcludeDConfig.class, + ImportADConfig.class)).isEmpty(); + } + + private List getImportedConfigBeans(Class... config) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( config); String shortName = ClassUtils.getShortName(ImportAutoConfigurationTests.class); @@ -97,6 +109,21 @@ static class ExcludingConfig { } + @ImportAutoConfiguration(classes = { ConfigA.class, ConfigD.class }) + static class ImportADConfig { + + } + + @ImportAutoConfiguration(exclude = { ConfigA.class, ConfigD.class }) + static class ExcludeADConfig { + + } + + @ImportAutoConfiguration(exclude = ConfigD.class) + static class ExcludeDConfig { + + } + @Retention(RetentionPolicy.RUNTIME) @ImportAutoConfiguration({ ConfigC.class, ConfigA.class }) @interface MetaImportAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListenerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListenerTests.java index 0f7e83968578..224295cebd0e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListenerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,6 +16,7 @@ package org.springframework.boot.autoconfigure.condition; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; @@ -35,6 +36,7 @@ * Tests for {@link ConditionEvaluationReportAutoConfigurationImportListener}. * * @author Phillip Webb + * @author Stephane Nicoll */ public class ConditionEvaluationReportAutoConfigurationImportListenerTests { @@ -81,4 +83,32 @@ public void onAutoConfigurationImportEventShouldRecordExclusions() { assertThat(report.getExclusions()).containsExactlyElementsOf(exclusions); } + @Test + public void onAutoConfigurationImportEventShouldApplyExclusionsGlobally() { + AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, + Arrays.asList("First", "Second"), Collections.emptySet()); + this.listener.onAutoConfigurationImportEvent(event); + AutoConfigurationImportEvent anotherEvent = new AutoConfigurationImportEvent(this, + Collections.emptyList(), Collections.singleton("First")); + this.listener.onAutoConfigurationImportEvent(anotherEvent); + ConditionEvaluationReport report = ConditionEvaluationReport + .get(this.beanFactory); + assertThat(report.getUnconditionalClasses()).containsExactly("Second"); + assertThat(report.getExclusions()).containsExactly("First"); + } + + @Test + public void onAutoConfigurationImportEventShouldApplyExclusionsGloballyWhenExclusionIsAlreadyApplied() { + AutoConfigurationImportEvent excludeEvent = new AutoConfigurationImportEvent(this, + Collections.emptyList(), Collections.singleton("First")); + this.listener.onAutoConfigurationImportEvent(excludeEvent); + AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, + Arrays.asList("First", "Second"), Collections.emptySet()); + this.listener.onAutoConfigurationImportEvent(event); + ConditionEvaluationReport report = ConditionEvaluationReport + .get(this.beanFactory); + assertThat(report.getUnconditionalClasses()).containsExactly("Second"); + assertThat(report.getExclusions()).containsExactly("First"); + } + } From 13835c5dc7175b0b292235a166505b76d1545afb Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 19 Jul 2018 13:33:39 +0100 Subject: [PATCH 259/701] Upgrade to Spring Batch 4.1.0.M2 Closes gh-13820 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 31d10e23e755..d7f9f3849488 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -153,7 +153,7 @@ 7.4.0 5.1.0.BUILD-SNAPSHOT 2.0.4.RELEASE - 4.0.1.RELEASE + 4.1.0.M2 2.0.2.RELEASE Lovelace-BUILD-SNAPSHOT 0.25.0.BUILD-SNAPSHOT From 0f0fc9ec62af2f5c77f5b73a3c7c0dd071bb8352 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 20 Jul 2018 17:12:56 +0200 Subject: [PATCH 260/701] Adapt assertion to logging change in Spring Framework --- .../src/test/java/org/springframework/boot/SimpleMainTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java index 7b09f0bb430a..03b353c75f39 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java @@ -41,7 +41,7 @@ public class SimpleMainTests { @Rule public OutputCapture outputCapture = new OutputCapture(); - private static final String SPRING_STARTUP = "root of context hierarchy"; + private static final String SPRING_STARTUP = "Started SpringApplication in"; @Test(expected = IllegalArgumentException.class) public void emptyApplicationContext() throws Exception { From 5e58a503113161e05401d0a8cb1edb8deb3c76d5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:16 +0100 Subject: [PATCH 261/701] Upgrade to Couchbase Client 2.6.0 Closes gh-13846 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 3d8d02c043be..abf76c80b152 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -50,7 +50,7 @@ 3.7 1.6 2.5.0 - 2.5.9 + 2.6.0 2.1.0 10.14.2.0 1.6.1 From 9d728387966573c378ed547b3c6ff9c87772dc6a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:17 +0100 Subject: [PATCH 262/701] Upgrade to Hazelcast 3.10.3 Closes gh-13847 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index abf76c80b152..44b5cfaaaba5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -66,7 +66,7 @@ 2.8.5 1.4.197 1.3 - 3.10.2 + 3.10.3 1.2.3 5.3.1.Final 6.0.11.Final From a19d340b605adce4ddb726d27df2f27acfbd648d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:17 +0100 Subject: [PATCH 263/701] Upgrade to Undertow 2.0.11.Final Closes gh-13848 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 44b5cfaaaba5..76c20c8098ec 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -177,7 +177,7 @@ 3.0.1.RELEASE 9.0.10 4.0.6 - 2.0.9.Final + 2.0.11.Final 3325375 0.35 1.6.3 From 1df725fddc7ed3824245c1daa9d7d6e4e6a4e53d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:18 +0100 Subject: [PATCH 264/701] Upgrade to Byte Buddy 1.8.13 Closes gh-13849 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 76c20c8098ec..5728b194e5f0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -41,7 +41,7 @@ 3.10.0 4.0.6 2.1.4 - 1.8.12 + 1.8.13 2.6.2 3.5.1 1.3.4 From f28ae9e4c517ea3f88b4a1a51ea5976e581eeb11 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:19 +0100 Subject: [PATCH 265/701] Upgrade to Commons Dbcp2 2.5.0 Closes gh-13850 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5728b194e5f0..aba9d00339ec 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -46,7 +46,7 @@ 3.5.1 1.3.4 1.11 - 2.4.0 + 2.5.0 3.7 1.6 2.5.0 From 7a706b1581310e1a4fa34074d935eef868897ace Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:19 +0100 Subject: [PATCH 266/701] Upgrade to Commons Pool2 2.6.0 Closes gh-13851 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index aba9d00339ec..2c537ace0ca0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -49,7 +49,7 @@ 2.5.0 3.7 1.6 - 2.5.0 + 2.6.0 2.6.0 2.1.0 10.14.2.0 From 921d88355948b59db9dfb18ecbab76731f20874d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:20 +0100 Subject: [PATCH 267/701] Upgrade to Kafka 1.1.1 Closes gh-13852 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2c537ace0ca0..4db7b22ac631 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -115,7 +115,7 @@ 1.3.1 4.12 5.2.0 - 1.1.0 + 1.1.1 1.2.51 5.1.0.M1 3.6.2 From e9d1abf2ce97b4d27d4cea40b23f9730d9093517 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:20 +0100 Subject: [PATCH 268/701] Upgrade to Groovy 2.5.1 Closes gh-13853 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4db7b22ac631..286ce29f6d6f 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -62,7 +62,7 @@ 2.3.28 6.3.0 3.0.0 - 2.5.0 + 2.5.1 2.8.5 1.4.197 1.3 From 98f19fcc8146e06815c4d9be93d24bd4a73e68d2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:21 +0100 Subject: [PATCH 269/701] Upgrade to Elasticsearch 6.3.1 Closes gh-13854 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 286ce29f6d6f..76c0387a1eb2 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -60,7 +60,7 @@ 2.1.1 5.1.3 2.3.28 - 6.3.0 + 6.3.1 3.0.0 2.5.1 2.8.5 From 3b79802c1911cb47ebdd09c8e0b23266b83b8d7f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:22 +0100 Subject: [PATCH 270/701] Upgrade to Flyway 5.1.4 Closes gh-13855 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 76c0387a1eb2..372a77046799 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -58,7 +58,7 @@ 2.10.5 3.5.2 2.1.1 - 5.1.3 + 5.1.4 2.3.28 6.3.1 3.0.0 From 2d340fcae10a0f74fda1b9e7be14d801f1935d30 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:22 +0100 Subject: [PATCH 271/701] Upgrade to Hibernate 5.3.3.Final Closes gh-13856 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 372a77046799..5f065b695e28 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -68,7 +68,7 @@ 1.3 3.10.3 1.2.3 - 5.3.1.Final + 5.3.3.Final 6.0.11.Final 3.2.0 2.4.1 From 0ea85800c4d9d7ddbb98a022cc1801d88aaa3576 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:23 +0100 Subject: [PATCH 272/701] Upgrade to Infinispan 9.3.1.Final Closes gh-13857 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5f065b695e28..2b32f3406ea8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -76,7 +76,7 @@ 4.1.3 4.5.6 4.4.10 - 9.3.0.Final + 9.3.1.Final 2.11 2.9.6 3.0.8 From f8c8c4735128dcfe4a314ae8598cdff9d10765f2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:24 +0100 Subject: [PATCH 273/701] Upgrade to Jooq 3.11.3 Closes gh-13858 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2b32f3406ea8..01c4c6d6658f 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -108,7 +108,7 @@ 2.10 1.6.0 1.1.8 - 3.11.2 + 3.11.3 1.5.0 2.4.0 1.2 From c7f6fb8660d816596e6bdb8d21ad18a1bc04b05e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Jul 2018 16:39:24 +0100 Subject: [PATCH 274/701] Upgrade to Mockito 2.19.1 Closes gh-13859 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 01c4c6d6658f..30b6b3ed604e 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -124,7 +124,7 @@ 1.18.0 2.2.6 1.0.5 - 2.19.0 + 2.19.1 1.9.0 3.8.0 6.4.0.jre8 From d0918f87b2200e36d5a367b39f76434c3e705e18 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Tue, 24 Jul 2018 08:34:49 +0200 Subject: [PATCH 275/701] Fix OAuth2WebSecurityConfigurationTests Closes gh-13872 --- .../OAuth2WebSecurityConfigurationTests.java | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index d6803ce5d018..36990dcb8bc7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -85,12 +85,8 @@ public void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() { public void configurationRegistersAuthorizedClientServiceBean() { this.contextRunner.withUserConfiguration(ClientRepositoryConfiguration.class, OAuth2WebSecurityConfiguration.class).run((context) -> { - OAuth2AuthorizedClientService bean = context - .getBean(OAuth2AuthorizedClientService.class); - OAuth2AuthorizedClientService authorizedClientService = (OAuth2AuthorizedClientService) ReflectionTestUtils - .getField(getAuthCodeFilters(context).get(0), - "authorizedClientService"); - assertThat(authorizedClientService).isEqualTo(bean); + assertThat(context) + .hasSingleBean(OAuth2AuthorizedClientService.class); }); } @@ -110,12 +106,9 @@ public void authorizedClientServiceBeanIsConditionalOnMissingBean() { .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, OAuth2WebSecurityConfiguration.class) .run((context) -> { - OAuth2AuthorizedClientService bean = context - .getBean(OAuth2AuthorizedClientService.class); - OAuth2AuthorizedClientService authorizedClientService = (OAuth2AuthorizedClientService) ReflectionTestUtils - .getField(getAuthCodeFilters(context).get(0), - "authorizedClientService"); - assertThat(authorizedClientService).isEqualTo(bean); + assertThat(context) + .hasSingleBean(OAuth2AuthorizedClientService.class); + assertThat(context).hasBean("testAuthorizedClientService"); }); } From 200ac6db3042e62939d71946a619b203b8351e2d Mon Sep 17 00:00:00 2001 From: Rob Tompkins Date: Fri, 29 Jun 2018 09:21:13 -0400 Subject: [PATCH 276/701] Add configuration for Tomcat's cachingAllowed property See gh-13614 --- .../autoconfigure/web/ServerProperties.java | 30 +++++++++++++++++++ .../TomcatWebServerFactoryCustomizer.java | 20 +++++++++++++ ...TomcatWebServerFactoryCustomizerTests.java | 19 ++++++++++++ .../appendix-application-properties.adoc | 1 + 4 files changed, 70 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 1ec029bcd6e5..d3490ec87973 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -52,6 +52,7 @@ * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy + * @author Rob Tompkins */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -265,6 +266,11 @@ public static class Tomcat { */ private final Accesslog accesslog = new Accesslog(); + /** + * Web resource configuration. + */ + private final WebResource webResource = new WebResource(); + /** * Regular expression matching trusted IP addresses. */ @@ -399,6 +405,10 @@ public Accesslog getAccesslog() { return this.accesslog; } + public WebResource getWebResource() { + return this.webResource; + } + public Duration getBackgroundProcessorDelay() { return this.backgroundProcessorDelay; } @@ -515,6 +525,26 @@ public Resource getResource() { return this.resource; } + /** + * Tomcat web resource properties. + */ + public static class WebResource { + + /** + * Whether tomcat WebResource caching is permitted for this web application. + */ + private Boolean useCaching = Boolean.TRUE; + + public Boolean getUseCaching() { + return this.useCaching; + } + + public void setUseCaching(Boolean useCaching) { + this.useCaching = useCaching; + } + + } + /** * Tomcat access log properties. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index b1e2c0272b18..12369ef899f6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -19,9 +19,11 @@ import java.time.Duration; import org.apache.catalina.Lifecycle; +import org.apache.catalina.WebResourceRoot; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.ErrorReportValve; import org.apache.catalina.valves.RemoteIpValve; +import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.http11.AbstractHttp11Protocol; @@ -46,6 +48,7 @@ * @author Yulin Qin * @author Stephane Nicoll * @author Phillip Webb + * @author Rob Tompkins * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer implements @@ -70,6 +73,8 @@ public int getOrder() { public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; ServerProperties.Tomcat tomcatProperties = properties.getTomcat(); + ServerProperties.Tomcat.WebResource tomcatWebResourceProperties = tomcatProperties + .getWebResource(); PropertyMapper propertyMapper = PropertyMapper.get(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull() .to(factory::setBaseDirectory); @@ -101,6 +106,9 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); + propertyMapper.from(tomcatWebResourceProperties::getUseCaching).whenFalse() + .to((isWebResourceCachingAllowed) -> customizeWebResourceCaching(factory, + isWebResourceCachingAllowed)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -126,6 +134,18 @@ private void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, }); } + private void customizeWebResourceCaching(ConfigurableTomcatWebServerFactory factory, + Boolean useWebResourceCaching) { + factory.addContextCustomizers((context) -> { + WebResourceRoot webResourceRoot = context.getResources(); + if (webResourceRoot == null) { + webResourceRoot = new StandardRoot(context); + } + webResourceRoot.setCachingAllowed(useWebResourceCaching); + context.setResources(webResourceRoot); + }); + } + private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) { factory.addConnectorCustomizers((connector) -> { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index 3cf616e88a8f..c426ae9030cf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -16,14 +16,17 @@ package org.springframework.boot.autoconfigure.web.embedded; +import java.util.Map; import java.util.function.Consumer; import org.apache.catalina.Context; import org.apache.catalina.Valve; +import org.apache.catalina.mapper.Mapper; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.ErrorReportValve; import org.apache.catalina.valves.RemoteIpValve; +import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; import org.junit.Before; import org.junit.Test; @@ -36,6 +39,7 @@ import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; import org.springframework.mock.env.MockEnvironment; import org.springframework.test.context.support.TestPropertySourceUtils; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -44,6 +48,7 @@ * * @author Brian Clozel * @author Phillip Webb + * @author Rob Tompkins */ public class TomcatWebServerFactoryCustomizerTests { @@ -94,6 +99,20 @@ public void customMaxConnections() { .isEqualTo(5)); } + @Test + public void turnOffWebResourceCaching() { + bind("server.tomcat.webresource.use-caching=false"); + customizeAndRunServer((server) -> { + Mapper mapper = server.getTomcat().getService().getMapper(); + Object contextObjectToContextVersionMap = ReflectionTestUtils.getField(mapper, + "contextObjectToContextVersionMap"); + Object tomcatEmbeddedContext = ((Map) contextObjectToContextVersionMap) + .values().toArray()[0]; + assertThat(((StandardRoot) ReflectionTestUtils.getField(tomcatEmbeddedContext, + "resources")).isCachingAllowed()).isFalse(); + }); + } + @Test public void customMaxHttpPostSize() { bind("server.tomcat.max-http-post-size=10000"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index da8528ec568e..98bddec84597 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -262,6 +262,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. + server.tomcat.webresource.use-caching= # Whether tomcat WebResource caching is permitted for this web application. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Whether to enable the access log. server.undertow.accesslog.pattern=common # Format pattern for access logs. From 5fb2060566b0e208830cff4c739a7bb1eb0cff40 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Jul 2018 11:18:52 +0200 Subject: [PATCH 277/701] Polish "Add configuration for Tomcat's cachingAllowed property" Closes gh-13614 --- .../autoconfigure/web/ServerProperties.java | 43 ++++++------------- .../TomcatWebServerFactoryCustomizer.java | 30 +++---------- ...TomcatWebServerFactoryCustomizerTests.java | 28 ++++++------ .../appendix-application-properties.adoc | 2 +- 4 files changed, 33 insertions(+), 70 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index d3490ec87973..b943184bda4b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -52,7 +52,6 @@ * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy - * @author Rob Tompkins */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -266,11 +265,6 @@ public static class Tomcat { */ private final Accesslog accesslog = new Accesslog(); - /** - * Web resource configuration. - */ - private final WebResource webResource = new WebResource(); - /** * Regular expression matching trusted IP addresses. */ @@ -405,10 +399,6 @@ public Accesslog getAccesslog() { return this.accesslog; } - public WebResource getWebResource() { - return this.webResource; - } - public Duration getBackgroundProcessorDelay() { return this.backgroundProcessorDelay; } @@ -525,26 +515,6 @@ public Resource getResource() { return this.resource; } - /** - * Tomcat web resource properties. - */ - public static class WebResource { - - /** - * Whether tomcat WebResource caching is permitted for this web application. - */ - private Boolean useCaching = Boolean.TRUE; - - public Boolean getUseCaching() { - return this.useCaching; - } - - public void setUseCaching(Boolean useCaching) { - this.useCaching = useCaching; - } - - } - /** * Tomcat access log properties. */ @@ -690,11 +660,24 @@ public void setBuffered(boolean buffered) { */ public static class Resource { + /** + * Whether static resource caching is permitted for this web application. + */ + private boolean allowCaching = true; + /** * Time-to-live of the static resource cache. */ private Duration cacheTtl; + public boolean isAllowCaching() { + return this.allowCaching; + } + + public void setAllowCaching(boolean allowCaching) { + this.allowCaching = allowCaching; + } + public Duration getCacheTtl() { return this.cacheTtl; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 12369ef899f6..8df3d8db5cb8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -19,11 +19,9 @@ import java.time.Duration; import org.apache.catalina.Lifecycle; -import org.apache.catalina.WebResourceRoot; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.ErrorReportValve; import org.apache.catalina.valves.RemoteIpValve; -import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.http11.AbstractHttp11Protocol; @@ -48,7 +46,6 @@ * @author Yulin Qin * @author Stephane Nicoll * @author Phillip Webb - * @author Rob Tompkins * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer implements @@ -73,8 +70,6 @@ public int getOrder() { public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; ServerProperties.Tomcat tomcatProperties = properties.getTomcat(); - ServerProperties.Tomcat.WebResource tomcatWebResourceProperties = tomcatProperties - .getWebResource(); PropertyMapper propertyMapper = PropertyMapper.get(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull() .to(factory::setBaseDirectory); @@ -106,9 +101,6 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); - propertyMapper.from(tomcatWebResourceProperties::getUseCaching).whenFalse() - .to((isWebResourceCachingAllowed) -> customizeWebResourceCaching(factory, - isWebResourceCachingAllowed)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -134,18 +126,6 @@ private void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, }); } - private void customizeWebResourceCaching(ConfigurableTomcatWebServerFactory factory, - Boolean useWebResourceCaching) { - factory.addContextCustomizers((context) -> { - WebResourceRoot webResourceRoot = context.getResources(); - if (webResourceRoot == null) { - webResourceRoot = new StandardRoot(context); - } - webResourceRoot.setCachingAllowed(useWebResourceCaching); - context.setResources(webResourceRoot); - }); - } - private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) { factory.addConnectorCustomizers((connector) -> { @@ -261,14 +241,14 @@ private void customizeAccessLog(ConfigurableTomcatWebServerFactory factory) { private void customizeStaticResources(ConfigurableTomcatWebServerFactory factory) { ServerProperties.Tomcat.Resource resource = this.serverProperties.getTomcat() .getResource(); - if (resource.getCacheTtl() == null) { - return; - } factory.addContextCustomizers((context) -> { context.addLifecycleListener((event) -> { if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { - long ttl = resource.getCacheTtl().toMillis(); - context.getResources().setCacheTtl(ttl); + context.getResources().setCachingAllowed(resource.isAllowCaching()); + if (resource.getCacheTtl() != null) { + long ttl = resource.getCacheTtl().toMillis(); + context.getResources().setCacheTtl(ttl); + } } }); }); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index c426ae9030cf..ce43fac13dc8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -99,20 +99,6 @@ public void customMaxConnections() { .isEqualTo(5)); } - @Test - public void turnOffWebResourceCaching() { - bind("server.tomcat.webresource.use-caching=false"); - customizeAndRunServer((server) -> { - Mapper mapper = server.getTomcat().getService().getMapper(); - Object contextObjectToContextVersionMap = ReflectionTestUtils.getField(mapper, - "contextObjectToContextVersionMap"); - Object tomcatEmbeddedContext = ((Map) contextObjectToContextVersionMap) - .values().toArray()[0]; - assertThat(((StandardRoot) ReflectionTestUtils.getField(tomcatEmbeddedContext, - "resources")).isCachingAllowed()).isFalse(); - }); - } - @Test public void customMaxHttpPostSize() { bind("server.tomcat.max-http-post-size=10000"); @@ -140,6 +126,20 @@ public void customRemoteIpValve() { assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1"); } + @Test + public void customStaticResourceAllowCaching() { + bind("server.tomcat.resource.allow-caching=false"); + customizeAndRunServer((server) -> { + Mapper mapper = server.getTomcat().getService().getMapper(); + Object contextObjectToContextVersionMap = ReflectionTestUtils.getField(mapper, + "contextObjectToContextVersionMap"); + Object tomcatEmbeddedContext = ((Map) contextObjectToContextVersionMap) + .values().toArray()[0]; + assertThat(((StandardRoot) ReflectionTestUtils.getField(tomcatEmbeddedContext, + "resources")).isCachingAllowed()).isFalse(); + }); + } + @Test public void customStaticResourceCacheTtl() { bind("server.tomcat.resource.cache-ttl=10000"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 98bddec84597..a149580bdb61 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -259,10 +259,10 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.protocol-header-https-value=https # Value of the protocol header indicating whether the incoming request uses SSL. server.tomcat.redirect-context-root= # Whether requests to the context root should be redirected by appending a / to the path. server.tomcat.remote-ip-header= # Name of the HTTP header from which the remote IP is extracted. For instance, `X-FORWARDED-FOR`. + server.tomcat.resource.allow-caching= # Whether static resource caching is permitted for this web application. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. - server.tomcat.webresource.use-caching= # Whether tomcat WebResource caching is permitted for this web application. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Whether to enable the access log. server.undertow.accesslog.pattern=common # Format pattern for access logs. From c98bb40136ab392c8c6d0ee08c8bba9462d3a49e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Jul 2018 13:36:38 +0200 Subject: [PATCH 278/701] Adapt NoSuchBeanDefinitionFailureAnalyzer to framework change This commit adapts to a Spring Framework change based on SPR-11419 and SPR-15338. Rather than throwing an exception when injecting a List or Map of a candidate bean that is not present, an empty collection/map is injected. --- .../NoSuchBeanDefinitionFailureAnalyzer.java | 8 --- ...uchBeanDefinitionFailureAnalyzerTests.java | 54 ------------------- 2 files changed, 62 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java index 2b9237fd8f22..beaac6db0ac9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java @@ -115,14 +115,6 @@ private String getBeanDescription(NoSuchBeanDefinitionException cause) { } private Class extractBeanType(ResolvableType resolvableType) { - ResolvableType collectionType = resolvableType.asCollection(); - if (!collectionType.equals(ResolvableType.NONE)) { - return collectionType.getGeneric(0).getRawClass(); - } - ResolvableType mapType = resolvableType.asMap(); - if (!mapType.equals(ResolvableType.NONE)) { - return mapType.getGeneric(1).getRawClass(); - } return resolvableType.getRawClass(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java index 98880bed594c..10ade521001f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java @@ -17,9 +17,7 @@ package org.springframework.boot.autoconfigure.diagnostics.analyzer; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.Map; import org.junit.Test; @@ -83,30 +81,6 @@ public void failureAnalysisForMissingPropertyExactType() { assertActionMissingType(analysis, String.class); } - @Test - public void failureAnalysisForMissingCollectionType() { - FailureAnalysis analysis = analyzeFailure( - createFailure(StringCollectionConfiguration.class)); - assertDescriptionConstructorMissingType(analysis, StringCollectionHandler.class, - 0, String.class); - assertBeanMethodDisabled(analysis, - "did not find property 'spring.string.enabled'", - TestPropertyAutoConfiguration.class, "string"); - assertActionMissingType(analysis, String.class); - } - - @Test - public void failureAnalysisForMissingMapType() { - FailureAnalysis analysis = analyzeFailure( - createFailure(StringMapConfiguration.class)); - assertDescriptionConstructorMissingType(analysis, StringMapHandler.class, 0, - String.class); - assertBeanMethodDisabled(analysis, - "did not find property 'spring.string.enabled'", - TestPropertyAutoConfiguration.class, "string"); - assertActionMissingType(analysis, String.class); - } - @Test public void failureAnalysisForMissingPropertySubType() { FailureAnalysis analysis = analyzeFailure( @@ -281,20 +255,6 @@ protected static class StringPropertyTypeConfiguration { } - @Configuration - @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) - @Import(StringCollectionHandler.class) - protected static class StringCollectionConfiguration { - - } - - @Configuration - @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) - @Import(StringMapHandler.class) - protected static class StringMapConfiguration { - - } - @Configuration @ImportAutoConfiguration(TestPropertyAutoConfiguration.class) @Import(NumberHandler.class) @@ -402,18 +362,4 @@ public StringNameHandler(BeanFactory beanFactory) { } - protected static class StringCollectionHandler { - - public StringCollectionHandler(Collection collection) { - } - - } - - protected static class StringMapHandler { - - public StringMapHandler(Map map) { - } - - } - } From dd79143d1a04bd193a20612f7e86df1aba946ab6 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 24 Jul 2018 13:49:01 +0200 Subject: [PATCH 279/701] Support http/2 configuration with Reactor-Netty Just like Jetty, Reactor Netty supports ALPN with JDK8 or with a dependency that delegates TLS to a native library using boringSSL. Closes gh-13333 --- .../spring-boot-dependencies/pom.xml | 6 ++++++ .../src/main/asciidoc/howto.adoc | 16 +++++++++++++++ spring-boot-project/spring-boot/pom.xml | 20 +++++++++++++++++++ .../netty/NettyReactiveWebServerFactory.java | 18 +++++++++++++++-- .../embedded/netty/SslServerCustomizer.java | 18 ++++++++++++----- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index aba2146aafab..7dd41c5040f7 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -133,6 +133,7 @@ 1.9.22 3.1.0 4.1.27.Final + 2.0.12.Final 1.1.0 42.2.4 2.3.0 @@ -924,6 +925,11 @@ import pom + + io.netty + netty-tcnative-boringssl-static + ${netty-tcnative.version} + io.projectreactor reactor-bom diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 3022d8d285f0..f6b27e9112af 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -753,6 +753,22 @@ This error is not fatal, and the application still starts with HTTP/1.1 SSL supp +[[howto-configure-http2-netty]] +==== HTTP/2 with Reactor Netty +The `spring-boot-webflux-starter` is using by default Reactor Netty as a server. +Reactor Netty can be configured for HTTP/2 using the JDK support with JDK 9 or later. +For JDK 8 environments, or for optimal runtime performance, this server also supports +HTTP/2 with native libraries. To enable that, your application needs to have an +additional dependency. + +Spring Boot manages the version for the +`io.netty:netty-tcnative-boringssl-static` "uber jar", containing native libraries for +all platforms. Developers can choose to import only the required dependendencies using +a classifier (see http://netty.io/wiki/forked-tomcat-native.html[the Netty official +documentation]). + + + [[howto-configure-webserver]] === Configure the Web Server diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index f8682f0da0f2..85dca2014d2a 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -76,6 +76,11 @@ reactor-netty true + + io.netty + netty-tcnative-boringssl-static + true + io.undertow undertow-servlet @@ -373,6 +378,21 @@ jaybird-jdk18 test + + org.eclipse.jetty + jetty-client + test + + + org.eclipse.jetty.http2 + http2-client + test + + + org.eclipse.jetty.http2 + http2-http-client-transport + test + org.hsqldb hsqldb diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index 526cda5fef49..0bafb6eabaae 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.List; +import reactor.netty.http.HttpProtocol; import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; @@ -110,10 +111,10 @@ public void setUseForwardHeaders(boolean useForwardHeaders) { private HttpServer createHttpServer() { HttpServer server = HttpServer.create().tcpConfiguration( - (tcpServer) -> tcpServer.addressSupplier(() -> getListenAddress())); + (tcpServer) -> tcpServer.addressSupplier(this::getListenAddress)); if (getSsl() != null && getSsl().isEnabled()) { SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(getSsl(), - getSslStoreProvider()); + getHttp2(), getSslStoreProvider()); server = sslServerCustomizer.apply(server); } if (getCompression() != null && getCompression().getEnabled()) { @@ -121,10 +122,23 @@ private HttpServer createHttpServer() { getCompression()); server = compressionCustomizer.apply(server); } + server = server.protocol(listProtocols()); server = (this.useForwardHeaders ? server.forwarded() : server.noForwarded()); return applyCustomizers(server); } + private HttpProtocol[] listProtocols() { + if (getHttp2() != null && getHttp2().isEnabled()) { + if (getSsl() != null && getSsl().isEnabled()) { + return new HttpProtocol[] { HttpProtocol.H2, HttpProtocol.HTTP11 }; + } + else { + return new HttpProtocol[] { HttpProtocol.H2C, HttpProtocol.HTTP11 }; + } + } + return new HttpProtocol[] { HttpProtocol.HTTP11 }; + } + private InetSocketAddress getListenAddress() { if (getAddress() != null) { return new InetSocketAddress(getAddress().getHostAddress(), getPort()); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index 032547626bd3..e3b800b53997 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -26,8 +26,9 @@ import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; import reactor.netty.http.server.HttpServer; -import reactor.netty.tcp.SslProvider.DefaultConfigurationType; +import reactor.netty.tcp.SslProvider; +import org.springframework.boot.web.server.Http2; import org.springframework.boot.web.server.Ssl; import org.springframework.boot.web.server.SslStoreProvider; import org.springframework.util.ResourceUtils; @@ -42,19 +43,26 @@ public class SslServerCustomizer implements NettyServerCustomizer { private final Ssl ssl; + private final Http2 http2; + private final SslStoreProvider sslStoreProvider; - public SslServerCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) { + public SslServerCustomizer(Ssl ssl, Http2 http2, SslStoreProvider sslStoreProvider) { this.ssl = ssl; + this.http2 = http2; this.sslStoreProvider = sslStoreProvider; } @Override public HttpServer apply(HttpServer server) { try { - return server - .secure((contextSpec) -> contextSpec.sslContext(getContextBuilder()) - .defaultConfiguration(DefaultConfigurationType.NONE)); + return server.secure((contextSpec) -> { + SslProvider.DefaultConfigurationSpec spec = contextSpec + .sslContext(getContextBuilder()); + if (this.http2 != null && this.http2.isEnabled()) { + spec.defaultConfiguration(SslProvider.DefaultConfigurationType.H2); + } + }); } catch (Exception ex) { throw new IllegalStateException(ex); From e15ca514c87f38e0dd5374b12a31b557f78a5140 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 24 Jul 2018 13:56:51 +0200 Subject: [PATCH 280/701] Update HttpResources cleaning for Reactor Netty This commit updates the workaround for issue gh-9146 --- .../boot/web/embedded/netty/NettyWebServer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index 9ba693a3b09c..7191dcf44a1a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -115,15 +115,14 @@ public void run() { @Override public void stop() throws WebServerException { if (this.disposableServer != null) { - // temporary fix for gh-9146 - this.disposableServer.onDispose() - .doFinally((signal) -> HttpResources.reset()); if (this.lifecycleTimeout != null) { this.disposableServer.disposeNow(this.lifecycleTimeout); } else { this.disposableServer.disposeNow(); } + // temporary fix for gh-9146 + HttpResources.shutdown(); this.disposableServer = null; } } From 57dbea0db3eee42358973c472ccd1b47ffc06b79 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 24 Jul 2018 14:56:23 +0200 Subject: [PATCH 281/701] Finalize upgrade to Reactor Netty 0.8 This commit fixes the last issue for the upgrade to Reactor Netty 0.8. Closes: gh-13321 --- .../boot/web/embedded/netty/NettyWebServer.java | 13 +++++++------ .../netty/NettyReactiveWebServerFactoryTests.java | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index 7191dcf44a1a..ac09e2db4262 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -16,11 +16,11 @@ package org.springframework.boot.web.embedded.netty; -import java.net.BindException; import java.time.Duration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import reactor.netty.ChannelBindException; import reactor.netty.DisposableServer; import reactor.netty.http.HttpResources; import reactor.netty.http.server.HttpServer; @@ -69,8 +69,9 @@ public void start() throws WebServerException { this.disposableServer = startHttpServer(); } catch (Exception ex) { - if (findBindException(ex) != null) { - throw new PortInUseException(getPort()); + ChannelBindException bindException = findBindException(ex); + if (bindException != null) { + throw new PortInUseException(bindException.localPort()); } throw new WebServerException("Unable to start Netty", ex); } @@ -87,11 +88,11 @@ private DisposableServer startHttpServer() { return this.httpServer.handle(this.handlerAdapter).bindNow(); } - private BindException findBindException(Exception ex) { + private ChannelBindException findBindException(Exception ex) { Throwable candidate = ex; while (candidate != null) { - if (candidate instanceof BindException) { - return (BindException) candidate; + if (candidate instanceof ChannelBindException) { + return (ChannelBindException) candidate; } candidate = candidate.getCause(); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index 55c8a446785f..fb642a3d93c8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -18,14 +18,14 @@ import java.util.Arrays; -import org.junit.Ignore; +import org.hamcrest.Matchers; import org.junit.Test; import org.mockito.InOrder; import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests; -import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.server.PortInUseException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @@ -46,14 +46,15 @@ protected NettyReactiveWebServerFactory getFactory() { } @Test - @Ignore public void exceptionIsThrownWhenPortIsAlreadyInUse() { AbstractReactiveWebServerFactory factory = getFactory(); factory.setPort(0); this.webServer = factory.getWebServer(new EchoHandler()); this.webServer.start(); factory.setPort(this.webServer.getPort()); - this.thrown.expect(WebServerException.class); + this.thrown.expect(PortInUseException.class); + this.thrown.expect( + Matchers.hasProperty("port", Matchers.equalTo(this.webServer.getPort()))); factory.getWebServer(new EchoHandler()).start(); } From b163120ece317ad137c14fdffc25c9b9db77ce43 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 24 Jul 2018 18:20:11 +0200 Subject: [PATCH 282/701] Upgrade to Reactor Californium-M1 Closes gh-12849 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 7dd41c5040f7..e4cf317ee878 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -139,7 +139,7 @@ 2.3.0 4.2.1 5.3.0 - Californium-BUILD-SNAPSHOT + Californium-M1 3.1.0 1.0.2 1.3.8 From 2dcf19938daf139550d90fcc60f4dc2533b3d9b1 Mon Sep 17 00:00:00 2001 From: artsiom Date: Mon, 23 Jul 2018 18:51:15 +0300 Subject: [PATCH 283/701] Register OAuth2AuthorizedClientRepository bean --- .../OAuth2WebSecurityConfiguration.java | 9 +++++ .../OAuth2WebSecurityConfigurationTests.java | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index 8ece42f6437e..da35e800b3da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -25,6 +25,8 @@ import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; /** * {@link WebSecurityConfigurerAdapter} to add OAuth client support. @@ -44,6 +46,13 @@ public OAuth2AuthorizedClientService authorizedClientService( return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); } + @Bean + @ConditionalOnMissingBean + public OAuth2AuthorizedClientRepository authorizedClientRepository( + OAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + } + @Configuration @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index 36990dcb8bc7..44a9e4cb0ec1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -24,6 +24,7 @@ import org.junit.Test; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; @@ -38,7 +39,9 @@ import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.web.FilterChainProxy; @@ -90,6 +93,19 @@ public void configurationRegistersAuthorizedClientServiceBean() { }); } + @Test + public void configurationRegistersAuthorizedRepositoryServiceBean() { + this.contextRunner.withUserConfiguration(ClientRepositoryConfiguration.class, + OAuth2WebSecurityConfiguration.class).run((context) -> { + OAuth2AuthorizedClientRepository bean = context + .getBean(OAuth2AuthorizedClientRepository.class); + OAuth2AuthorizedClientRepository authorizedClientService = (OAuth2AuthorizedClientRepository) ReflectionTestUtils + .getField(getAuthCodeFilters(context).get(0), + "authorizedClientRepository"); + assertThat(authorizedClientService).isEqualTo(bean); + }); + } + @Test public void securityConfigurerBacksOffWhenOtherWebSecurityAdapterPresent() { this.contextRunner.withUserConfiguration(TestWebSecurityConfigurerConfig.class, @@ -112,6 +128,21 @@ public void authorizedClientServiceBeanIsConditionalOnMissingBean() { }); } + @Test + public void authorizedClientRepositoryBeanIsConditionalOnMissingBean() { + this.contextRunner + .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, + OAuth2WebSecurityConfiguration.class) + .run((context) -> { + OAuth2AuthorizedClientRepository bean = context + .getBean(OAuth2AuthorizedClientRepository.class); + OAuth2AuthorizedClientRepository authorizedClientService = (OAuth2AuthorizedClientRepository) ReflectionTestUtils + .getField(getAuthCodeFilters(context).get(0), + "authorizedClientRepository"); + assertThat(authorizedClientService).isEqualTo(bean); + }); + } + @SuppressWarnings("unchecked") private List getAuthCodeFilters(AssertableApplicationContext context) { FilterChainProxy filterChain = (FilterChainProxy) context @@ -210,6 +241,13 @@ public OAuth2AuthorizedClientService testAuthorizedClientService( clientRegistrationRepository); } + @Bean + @ConditionalOnMissingBean + public OAuth2AuthorizedClientRepository testAuthorizedClientRepository( + OAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + } + } } From f5617601aa2b2457910dc00b52db05af34641bb3 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 24 Jul 2018 13:31:03 -0700 Subject: [PATCH 284/701] Polish "Register OAuth2AuthorizedClientRepository bean" Closes gh-13870 --- .../OAuth2WebSecurityConfiguration.java | 3 +- .../OAuth2WebSecurityConfigurationTests.java | 43 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index da35e800b3da..ffd1f484b7a9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -50,7 +50,8 @@ public OAuth2AuthorizedClientService authorizedClientService( @ConditionalOnMissingBean public OAuth2AuthorizedClientRepository authorizedClientRepository( OAuth2AuthorizedClientService authorizedClientService) { - return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository( + authorizedClientService); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index 44a9e4cb0ec1..20621acd906d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -24,7 +24,6 @@ import org.junit.Test; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; @@ -94,16 +93,12 @@ public void configurationRegistersAuthorizedClientServiceBean() { } @Test - public void configurationRegistersAuthorizedRepositoryServiceBean() { - this.contextRunner.withUserConfiguration(ClientRepositoryConfiguration.class, - OAuth2WebSecurityConfiguration.class).run((context) -> { - OAuth2AuthorizedClientRepository bean = context - .getBean(OAuth2AuthorizedClientRepository.class); - OAuth2AuthorizedClientRepository authorizedClientService = (OAuth2AuthorizedClientRepository) ReflectionTestUtils - .getField(getAuthCodeFilters(context).get(0), - "authorizedClientRepository"); - assertThat(authorizedClientService).isEqualTo(bean); - }); + public void configurationRegistersAuthorizedClientRepositoryBean() { + this.contextRunner + .withUserConfiguration(ClientRepositoryConfiguration.class, + OAuth2WebSecurityConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(OAuth2AuthorizedClientRepository.class)); } @Test @@ -130,16 +125,12 @@ public void authorizedClientServiceBeanIsConditionalOnMissingBean() { @Test public void authorizedClientRepositoryBeanIsConditionalOnMissingBean() { - this.contextRunner - .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, - OAuth2WebSecurityConfiguration.class) - .run((context) -> { - OAuth2AuthorizedClientRepository bean = context - .getBean(OAuth2AuthorizedClientRepository.class); - OAuth2AuthorizedClientRepository authorizedClientService = (OAuth2AuthorizedClientRepository) ReflectionTestUtils - .getField(getAuthCodeFilters(context).get(0), - "authorizedClientRepository"); - assertThat(authorizedClientService).isEqualTo(bean); + this.contextRunner.withUserConfiguration( + OAuth2AuthorizedClientRepositoryConfiguration.class, + OAuth2WebSecurityConfiguration.class).run((context) -> { + assertThat(context) + .hasSingleBean(OAuth2AuthorizedClientRepository.class); + assertThat(context).hasBean("testAuthorizedClientRepository"); }); } @@ -241,11 +232,17 @@ public OAuth2AuthorizedClientService testAuthorizedClientService( clientRegistrationRepository); } + } + + @Configuration + @Import(ClientRepositoryConfiguration.class) + static class OAuth2AuthorizedClientRepositoryConfiguration { + @Bean - @ConditionalOnMissingBean public OAuth2AuthorizedClientRepository testAuthorizedClientRepository( OAuth2AuthorizedClientService authorizedClientService) { - return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository( + authorizedClientService); } } From eefa0ada9ff51079d54e545a0ef657acf129d9e6 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 24 Jul 2018 15:11:05 -0700 Subject: [PATCH 285/701] Allow property overrides for OIDC Configuration Provider Closes gh-13869 --- ...h2ClientPropertiesRegistrationAdapter.java | 18 +++---- ...entPropertiesRegistrationAdapterTests.java | 48 +++++++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index 36ca11d0a7e3..5879c46cec2f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -56,14 +56,11 @@ public static Map getClientRegistrations( private static ClientRegistration getClientRegistration(String registrationId, Registration properties, Map providers) { - String issuer = getIssuerIfPossible(registrationId, properties.getProvider(), - providers); - if (issuer != null) { - return OidcConfigurationProvider.issuer(issuer).registrationId(registrationId) - .clientId(properties.getClientId()) - .clientSecret(properties.getClientSecret()).build(); + Builder builder = getBuilderFromIssuerIfPossible(registrationId, + properties.getProvider(), providers); + if (builder == null) { + builder = getBuilder(registrationId, properties.getProvider(), providers); } - Builder builder = getBuilder(registrationId, properties.getProvider(), providers); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(properties::getClientId).to(builder::clientId); map.from(properties::getClientSecret).to(builder::clientSecret); @@ -79,7 +76,7 @@ private static ClientRegistration getClientRegistration(String registrationId, return builder.build(); } - private static String getIssuerIfPossible(String registrationId, + private static Builder getBuilderFromIssuerIfPossible(String registrationId, String configuredProviderId, Map providers) { String providerId = (configuredProviderId != null ? configuredProviderId : registrationId); @@ -87,7 +84,10 @@ private static String getIssuerIfPossible(String registrationId, Provider provider = providers.get(providerId); String issuer = provider.getIssuerUri(); if (issuer != null) { - return cleanIssuerPath(issuer); + String cleanedIssuer = cleanIssuerPath(issuer); + Builder builder = OidcConfigurationProvider.issuer(cleanedIssuer) + .registrationId(registrationId); + return getBuilder(builder, provider); } } return null; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 4a6f6eb41c71..7bbe6caf534e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -255,6 +255,54 @@ public void oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() testOidcConfiguration(registration, "okta-oidc"); } + @Test + public void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDefaults() + throws Exception { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + Registration registration = new Registration(); + registration.setProvider("okta-oidc"); + registration.setClientId("clientId"); + registration.setClientSecret("clientSecret"); + registration.setClientAuthenticationMethod("post"); + registration.setRedirectUriTemplate("http://example.com/redirect"); + registration.setScope(Collections.singleton("user")); + Provider provider = new Provider(); + provider.setIssuerUri(issuer); + provider.setAuthorizationUri("http://example.com/auth"); + provider.setTokenUri("http://example.com/token"); + provider.setUserInfoUri("http://example.com/info"); + provider.setUserNameAttribute("sub"); + provider.setJwkSetUri("http://example.com/jwk"); + OAuth2ClientProperties properties = new OAuth2ClientProperties(); + properties.getProvider().put("okta-oidc", provider); + properties.getRegistration().put("okta", registration); + Map registrations = OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(properties); + ClientRegistration adapted = registrations.get("okta"); + ProviderDetails providerDetails = adapted.getProviderDetails(); + assertThat(adapted.getClientAuthenticationMethod()) + .isEqualTo(ClientAuthenticationMethod.POST); + assertThat(adapted.getAuthorizationGrantType()) + .isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE); + assertThat(adapted.getRegistrationId()).isEqualTo("okta"); + assertThat(adapted.getClientName()).isEqualTo(cleanIssuerPath); + assertThat(adapted.getScopes()).containsOnly("user"); + assertThat(adapted.getRedirectUriTemplate()) + .isEqualTo("http://example.com/redirect"); + assertThat(providerDetails.getAuthorizationUri()) + .isEqualTo("http://example.com/auth"); + assertThat(providerDetails.getTokenUri()).isEqualTo("http://example.com/token"); + assertThat(providerDetails.getJwkSetUri()).isEqualTo("http://example.com/jwk"); + assertThat(providerDetails.getUserInfoEndpoint().getUri()) + .isEqualTo("http://example.com/info"); + assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName()) + .isEqualTo("sub"); + } + private void testOidcConfiguration(Registration registration, String providerId) throws Exception { this.server = new MockWebServer(); From 61c41555c8b90213048e126cfe5b9a7e10a62a3f Mon Sep 17 00:00:00 2001 From: artsiom Date: Sun, 22 Jul 2018 12:49:18 +0300 Subject: [PATCH 286/701] Add reactive health indicator for Cassandra See gh-13864 --- ...ctiveHealthIndicatorAutoConfiguration.java | 66 +++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + ...HealthIndicatorAutoConfigurationTests.java | 72 ++++++++++++++++ .../CassandraReactiveHealthIndicator.java | 59 +++++++++++++ .../CassandraReactiveHealthIndicatorTest.java | 83 +++++++++++++++++++ 5 files changed, 281 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java new file mode 100644 index 000000000000..7ffe22269291 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2017 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.autoconfigure.cassandra; + +import com.datastax.driver.core.Cluster; +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +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.data.cassandra.CassandraReactiveDataAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; + +import java.util.Map; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for + * {@link org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator}. + * + * @author Artsiom Yudovin + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass({ReactiveCassandraOperations.class, Cluster.class }) +@ConditionalOnBean(ReactiveCassandraOperations.class) +@ConditionalOnEnabledHealthIndicator("cassandra") +@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) +@AutoConfigureAfter({ CassandraAutoConfiguration.class, + CassandraReactiveDataAutoConfiguration.class }) +public class CassandraReactiveHealthIndicatorAutoConfiguration extends + CompositeReactiveHealthIndicatorConfiguration { + private final Map reactiveCassandraOperations; + + public CassandraReactiveHealthIndicatorAutoConfiguration( + Map reactiveCassandraOperations) { + this.reactiveCassandraOperations = reactiveCassandraOperations; + } + + @Bean + @ConditionalOnMissingBean(name = "cassandraReactiveHealthIndicator") + public ReactiveHealthIndicator cassandraHealthIndicator() { + return createHealthIndicator(this.reactiveCassandraOperations); + } +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 94fac42c97e4..04abe7d44cd3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -5,6 +5,7 @@ org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConf org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthIndicatorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.cassandra.CassandraReactiveHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java new file mode 100644 index 000000000000..cbc894f49406 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2017 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.autoconfigure.cassandra; + +import org.junit.Test; +import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ApplicationHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CassandraReactiveHealthIndicatorAutoConfiguration}. + * + * @author Artsiom Yudovin + */ +public class CassandraReactiveHealthIndicatorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthIndicatorAutoConfigurationTests.CassandraConfiguration.class, + CassandraReactiveHealthIndicatorAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)); + + @Test + public void runShouldCreateIndicator() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(CassandraReactiveHealthIndicator.class) + .doesNotHaveBean(CassandraHealthIndicator.class) + .doesNotHaveBean(ApplicationHealthIndicator.class)); + } + + @Test + public void runWhenDisabledShouldNotCreateIndicator() { + this.contextRunner.withPropertyValues("management.health.cassandra.enabled:false") + .run((context) -> assertThat(context) + .doesNotHaveBean(CassandraReactiveHealthIndicator.class) + .hasSingleBean(ApplicationHealthIndicator.class)); + } + + @Configuration + @AutoConfigureBefore(CassandraReactiveHealthIndicatorAutoConfiguration.class) + protected static class CassandraConfiguration { + + @Bean + public ReactiveCassandraOperations cassandraOperations() { + return mock(ReactiveCassandraOperations.class); + } + + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java new file mode 100644 index 000000000000..af60168444be --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2018 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.cassandra; + +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select; +import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.data.cassandra.ReactiveResultSet; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; +import org.springframework.util.Assert; +import reactor.core.publisher.Mono; + +/** + * Simple implementation of a {@link HealthIndicator} returning status information for + * Cassandra data stores. + * + * @author Artsiom Yudovin + * @since 2.0.0 + */ +public class CassandraReactiveHealthIndicator extends AbstractReactiveHealthIndicator { + + private final ReactiveCassandraOperations reactiveCassandraOperations; + + /** + * Create a new {@link CassandraHealthIndicator} instance. + * @param reactiveCassandraOperations the Cassandra operations + */ + public CassandraReactiveHealthIndicator(ReactiveCassandraOperations reactiveCassandraOperations) { + Assert.notNull(reactiveCassandraOperations, "ReactiveCassandraOperations must not be null"); + this.reactiveCassandraOperations = reactiveCassandraOperations; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + Select select = QueryBuilder.select("release_version").from("system", "local"); + Mono results = this.reactiveCassandraOperations.getReactiveCqlOperations() + .queryForObject(select, String.class); + + return results + .map(version -> builder.up().withDetail("version", version).build()) + .single(); + + } +} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java new file mode 100644 index 000000000000..a4a0237dcf3f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2018 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.cassandra; + +import com.datastax.driver.core.Row; +import com.datastax.driver.core.querybuilder.Select; +import org.junit.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Status; +import org.springframework.data.cassandra.CassandraInternalException; +import org.springframework.data.cassandra.ReactiveResultSet; +import org.springframework.data.cassandra.core.ReactiveCassandraOperations; +import org.springframework.data.cassandra.core.cql.ReactiveCqlOperations; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.assertj.core.api.Assertions.anyOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * A {@link ReactiveHealthIndicator} for Mongo. + * + * @author Artsiom Yudovin + * @since 2.0.0 + */ +public class CassandraReactiveHealthIndicatorTest { + + @Test + public void testCassandraIsUp() { + ReactiveCqlOperations reactiveCqlOperations = mock(ReactiveCqlOperations.class); + ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class); + + given(reactiveCqlOperations.queryForObject(any(Select.class), eq(String.class))) + .willReturn(Mono.just("6.0.0")); + given(reactiveCassandraOperations.getReactiveCqlOperations()).willReturn(reactiveCqlOperations); + + CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = + new CassandraReactiveHealthIndicator(reactiveCassandraOperations); + Mono health = cassandraReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("version"); + assertThat(h.getDetails().get("version")).isEqualTo("6.0.0"); + }).verifyComplete(); + } + + @Test + public void testCassandraIsDown() { + ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class); + + given(reactiveCassandraOperations.getReactiveCqlOperations()) + .willThrow(new CassandraInternalException("Connection failed")); + + CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = + new CassandraReactiveHealthIndicator(reactiveCassandraOperations); + Mono health = cassandraReactiveHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith((h) -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails().get("error")) + .isEqualTo(CassandraInternalException.class.getName() + ": Connection failed"); + }).verifyComplete(); + } +} From af0aa11d15e5bcb98c57458cb3592b4696345cc1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Jul 2018 10:03:35 +0200 Subject: [PATCH 287/701] Polish "Add reactive health indicator for Cassandra" Closes gh-13864 --- ...andraHealthIndicatorAutoConfiguration.java | 42 +++++--------- ...CassandraHealthIndicatorConfiguration.java | 55 +++++++++++++++++++ ...ReactiveHealthIndicatorConfiguration.java} | 31 ++++------- .../main/resources/META-INF/spring.factories | 1 - ...iveHealthIndicatorConfigurationTests.java} | 19 ++++--- .../CassandraReactiveHealthIndicator.java | 27 +++++---- ...assandraReactiveHealthIndicatorTests.java} | 39 ++++++------- .../asciidoc/production-ready-features.adoc | 3 + 8 files changed, 122 insertions(+), 95 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorConfiguration.java rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/{CassandraReactiveHealthIndicatorAutoConfiguration.java => CassandraReactiveHealthIndicatorConfiguration.java} (61%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/{CassandraReactiveHealthIndicatorAutoConfigurationTests.java => CassandraReactiveHealthIndicatorConfigurationTests.java} (78%) rename spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/{CassandraReactiveHealthIndicatorTest.java => CassandraReactiveHealthIndicatorTests.java} (76%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorAutoConfiguration.java index 55918bf48ec2..a514e46486de 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,55 +16,39 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; -import java.util.Map; - import com.datastax.driver.core.Cluster; -import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration; import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; -import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; -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.data.cassandra.CassandraDataAutoConfiguration; -import org.springframework.context.annotation.Bean; +import org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration; import org.springframework.context.annotation.Configuration; -import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.context.annotation.Import; /** - * {@link EnableAutoConfiguration Auto-configuration} for - * {@link CassandraHealthIndicator}. + * {@link EnableAutoConfiguration Auto-configuration} for {@link CassandraHealthIndicator} + * and {@link CassandraReactiveHealthIndicator}. * * @author Julien Dubois + * @author Stephane Nicoll * @since 2.0.0 */ @Configuration -@ConditionalOnClass({ CassandraOperations.class, Cluster.class }) -@ConditionalOnBean(CassandraOperations.class) +@ConditionalOnClass(Cluster.class) @ConditionalOnEnabledHealthIndicator("cassandra") @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureAfter({ CassandraAutoConfiguration.class, - CassandraDataAutoConfiguration.class }) -public class CassandraHealthIndicatorAutoConfiguration extends - CompositeHealthIndicatorConfiguration { - - private final Map cassandraOperations; - - public CassandraHealthIndicatorAutoConfiguration( - Map cassandraOperations) { - this.cassandraOperations = cassandraOperations; - } - - @Bean - @ConditionalOnMissingBean(name = "cassandraHealthIndicator") - public HealthIndicator cassandraHealthIndicator() { - return createHealthIndicator(this.cassandraOperations); - } + CassandraDataAutoConfiguration.class, + CassandraReactiveDataAutoConfiguration.class }) +@Import({ CassandraReactiveHealthIndicatorConfiguration.class, + CassandraHealthIndicatorConfiguration.class }) +public class CassandraHealthIndicatorAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorConfiguration.java new file mode 100644 index 000000000000..0bbb8224bd02 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraHealthIndicatorConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.autoconfigure.cassandra; + +import java.util.Map; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration; +import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.CassandraOperations; + +/** + * Configuration for {@link CassandraHealthIndicator}. + * + * @author Julien Dubois + */ +@Configuration +@ConditionalOnClass(CassandraOperations.class) +@ConditionalOnBean(CassandraOperations.class) +class CassandraHealthIndicatorConfiguration extends + CompositeHealthIndicatorConfiguration { + + private final Map cassandraOperations; + + CassandraHealthIndicatorConfiguration( + Map cassandraOperations) { + this.cassandraOperations = cassandraOperations; + } + + @Bean + @ConditionalOnMissingBean(name = "cassandraHealthIndicator") + public HealthIndicator cassandraHealthIndicator() { + return createHealthIndicator(this.cassandraOperations); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfiguration.java similarity index 61% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfiguration.java index 7ffe22269291..d41c769f9ae6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -15,45 +15,33 @@ */ package org.springframework.boot.actuate.autoconfigure.cassandra; -import com.datastax.driver.core.Cluster; +import java.util.Map; + import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration; -import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; -import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; import org.springframework.boot.actuate.health.ReactiveHealthIndicator; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; 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.data.cassandra.CassandraReactiveDataAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; -import java.util.Map; - /** - * {@link EnableAutoConfiguration Auto-configuration} for - * {@link org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator}. + * Configuration for {@link CassandraReactiveHealthIndicator}. * * @author Artsiom Yudovin - * @since 2.0.0 + * @author Stephane Nicoll */ @Configuration -@ConditionalOnClass({ReactiveCassandraOperations.class, Cluster.class }) +@ConditionalOnClass(ReactiveCassandraOperations.class) @ConditionalOnBean(ReactiveCassandraOperations.class) -@ConditionalOnEnabledHealthIndicator("cassandra") -@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) -@AutoConfigureAfter({ CassandraAutoConfiguration.class, - CassandraReactiveDataAutoConfiguration.class }) -public class CassandraReactiveHealthIndicatorAutoConfiguration extends +class CassandraReactiveHealthIndicatorConfiguration extends CompositeReactiveHealthIndicatorConfiguration { + private final Map reactiveCassandraOperations; - public CassandraReactiveHealthIndicatorAutoConfiguration( + CassandraReactiveHealthIndicatorConfiguration( Map reactiveCassandraOperations) { this.reactiveCassandraOperations = reactiveCassandraOperations; } @@ -63,4 +51,5 @@ public CassandraReactiveHealthIndicatorAutoConfiguration( public ReactiveHealthIndicator cassandraHealthIndicator() { return createHealthIndicator(this.reactiveCassandraOperations); } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 04abe7d44cd3..94fac42c97e4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -5,7 +5,6 @@ org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConf org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthIndicatorAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.cassandra.CassandraReactiveHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfigurationTests.java similarity index 78% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfigurationTests.java index cbc894f49406..cc3cb35f7ac2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cassandra/CassandraReactiveHealthIndicatorConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,12 +17,12 @@ package org.springframework.boot.actuate.autoconfigure.cassandra; import org.junit.Test; + import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.cassandra.CassandraHealthIndicator; import org.springframework.boot.actuate.cassandra.CassandraReactiveHealthIndicator; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -32,16 +32,17 @@ import static org.mockito.Mockito.mock; /** - * Tests for {@link CassandraReactiveHealthIndicatorAutoConfiguration}. + * Tests for {@link CassandraReactiveHealthIndicatorConfiguration}. * * @author Artsiom Yudovin + * @author Stephane Nicoll */ -public class CassandraReactiveHealthIndicatorAutoConfigurationTests { +public class CassandraReactiveHealthIndicatorConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(CassandraReactiveHealthIndicatorAutoConfigurationTests.CassandraConfiguration.class, - CassandraReactiveHealthIndicatorAutoConfiguration.class, - HealthIndicatorAutoConfiguration.class)); + .withUserConfiguration(CassandraMockConfiguration.class).withConfiguration( + AutoConfigurations.of(CassandraHealthIndicatorAutoConfiguration.class, + HealthIndicatorAutoConfiguration.class)); @Test public void runShouldCreateIndicator() { @@ -60,8 +61,7 @@ public void runWhenDisabledShouldNotCreateIndicator() { } @Configuration - @AutoConfigureBefore(CassandraReactiveHealthIndicatorAutoConfiguration.class) - protected static class CassandraConfiguration { + protected static class CassandraMockConfiguration { @Bean public ReactiveCassandraOperations cassandraOperations() { @@ -69,4 +69,5 @@ public ReactiveCassandraOperations cassandraOperations() { } } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java index af60168444be..15e2eb03f29d 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicator.java @@ -17,20 +17,19 @@ import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.Select; +import reactor.core.publisher.Mono; + import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.data.cassandra.ReactiveResultSet; +import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; import org.springframework.util.Assert; -import reactor.core.publisher.Mono; /** - * Simple implementation of a {@link HealthIndicator} returning status information for - * Cassandra data stores. + * A {@link ReactiveHealthIndicator} for Cassandra. * * @author Artsiom Yudovin - * @since 2.0.0 + * @since 2.1.0 */ public class CassandraReactiveHealthIndicator extends AbstractReactiveHealthIndicator { @@ -40,20 +39,20 @@ public class CassandraReactiveHealthIndicator extends AbstractReactiveHealthIndi * Create a new {@link CassandraHealthIndicator} instance. * @param reactiveCassandraOperations the Cassandra operations */ - public CassandraReactiveHealthIndicator(ReactiveCassandraOperations reactiveCassandraOperations) { - Assert.notNull(reactiveCassandraOperations, "ReactiveCassandraOperations must not be null"); + public CassandraReactiveHealthIndicator( + ReactiveCassandraOperations reactiveCassandraOperations) { + Assert.notNull(reactiveCassandraOperations, + "ReactiveCassandraOperations must not be null"); this.reactiveCassandraOperations = reactiveCassandraOperations; } @Override protected Mono doHealthCheck(Health.Builder builder) { Select select = QueryBuilder.select("release_version").from("system", "local"); - Mono results = this.reactiveCassandraOperations.getReactiveCqlOperations() - .queryForObject(select, String.class); - - return results - .map(version -> builder.up().withDetail("version", version).build()) + return this.reactiveCassandraOperations.getReactiveCqlOperations() + .queryForObject(select, String.class) + .map((version) -> builder.up().withDetail("version", version).build()) .single(); + } - } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java similarity index 76% rename from spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java rename to spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java index a4a0237dcf3f..3761d0a818e3 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTest.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java @@ -15,21 +15,17 @@ */ package org.springframework.boot.actuate.cassandra; -import com.datastax.driver.core.Row; import com.datastax.driver.core.querybuilder.Select; import org.junit.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.ReactiveHealthIndicator; import org.springframework.boot.actuate.health.Status; import org.springframework.data.cassandra.CassandraInternalException; -import org.springframework.data.cassandra.ReactiveResultSet; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; import org.springframework.data.cassandra.core.cql.ReactiveCqlOperations; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; -import static org.assertj.core.api.Assertions.anyOf; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -37,24 +33,24 @@ import static org.mockito.Mockito.mock; /** - * A {@link ReactiveHealthIndicator} for Mongo. + * Tests for {@link CassandraReactiveHealthIndicatorTests}. * * @author Artsiom Yudovin - * @since 2.0.0 */ -public class CassandraReactiveHealthIndicatorTest { +public class CassandraReactiveHealthIndicatorTests { @Test public void testCassandraIsUp() { ReactiveCqlOperations reactiveCqlOperations = mock(ReactiveCqlOperations.class); - ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class); - given(reactiveCqlOperations.queryForObject(any(Select.class), eq(String.class))) .willReturn(Mono.just("6.0.0")); - given(reactiveCassandraOperations.getReactiveCqlOperations()).willReturn(reactiveCqlOperations); + ReactiveCassandraOperations reactiveCassandraOperations = mock( + ReactiveCassandraOperations.class); + given(reactiveCassandraOperations.getReactiveCqlOperations()) + .willReturn(reactiveCqlOperations); - CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = - new CassandraReactiveHealthIndicator(reactiveCassandraOperations); + CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraReactiveHealthIndicator( + reactiveCassandraOperations); Mono health = cassandraReactiveHealthIndicator.health(); StepVerifier.create(health).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.UP); @@ -65,19 +61,20 @@ public void testCassandraIsUp() { @Test public void testCassandraIsDown() { - ReactiveCassandraOperations reactiveCassandraOperations = mock(ReactiveCassandraOperations.class); - + ReactiveCassandraOperations reactiveCassandraOperations = mock( + ReactiveCassandraOperations.class); given(reactiveCassandraOperations.getReactiveCqlOperations()) .willThrow(new CassandraInternalException("Connection failed")); - CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = - new CassandraReactiveHealthIndicator(reactiveCassandraOperations); + CassandraReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraReactiveHealthIndicator( + reactiveCassandraOperations); Mono health = cassandraReactiveHealthIndicator.health(); StepVerifier.create(health).consumeNextWith((h) -> { assertThat(h.getStatus()).isEqualTo(Status.DOWN); assertThat(h.getDetails()).containsOnlyKeys("error"); - assertThat(h.getDetails().get("error")) - .isEqualTo(CassandraInternalException.class.getName() + ": Connection failed"); + assertThat(h.getDetails().get("error")).isEqualTo( + CassandraInternalException.class.getName() + ": Connection failed"); }).verifyComplete(); } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 7790ae1ca1cf..7963e6a4f9bc 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -921,6 +921,9 @@ appropriate: |=== |Name |Description +|{sc-spring-boot-actuator}/cassandra/CassandraReactiveHealthIndicator.{sc-ext}[`CassandraReactiveHealthIndicator`] +|Checks that a Cassandra database is up. + |{sc-spring-boot-actuator}/mongo/MongoReactiveHealthIndicator.{sc-ext}[`MongoReactiveHealthIndicator`] |Checks that a Mongo database is up. From 2399092f1615195ec95b98e9a0a35df821bf000b Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Tue, 24 Jul 2018 11:12:10 +0200 Subject: [PATCH 288/701] Fix deprecation in UndertowServletWebServerFactory Closes gh-13873 --- .../web/embedded/undertow/UndertowServletWebServerFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java index f1664639193d..53420263be7d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowServletWebServerFactory.java @@ -348,7 +348,7 @@ private void registerServletContainerInitializerToDriveServletContextInitializer DeploymentInfo deployment, ServletContextInitializer... initializers) { ServletContextInitializer[] mergedInitializers = mergeInitializers(initializers); Initializer initializer = new Initializer(mergedInitializers); - deployment.addServletContainerInitalizer(new ServletContainerInitializerInfo( + deployment.addServletContainerInitializer(new ServletContainerInitializerInfo( Initializer.class, new ImmediateInstanceFactory(initializer), NO_CLASSES)); From 9e34938ce0c29d0efa77619ff86b3d8fd9e3c041 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Jul 2018 14:43:25 +0200 Subject: [PATCH 289/701] Start building against Spring Amqp 2.1.0 snapshots See gh-13885 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e4cf317ee878..c0c45362a544 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -153,7 +153,7 @@ 1.21 7.4.0 5.1.0.BUILD-SNAPSHOT - 2.0.4.RELEASE + 2.1.0.BUILD-SNAPSHOT 4.1.0.M2 2.0.2.RELEASE Lovelace-BUILD-SNAPSHOT From 56542ef8098dbe2c686492da3ab11b4f0640b1de Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Jul 2018 14:50:14 +0200 Subject: [PATCH 290/701] Start building against Spring Integration 2.1.0 snapshots See gh-13891 --- .../autoconfigure/integration/IntegrationAutoConfiguration.java | 2 +- .../integration/IntegrationAutoConfigurationTests.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 9cdd2f215d7d..b56a29f42221 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -39,11 +39,11 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.config.EnableIntegrationManagement; +import org.springframework.integration.config.IntegrationManagementConfigurer; import org.springframework.integration.gateway.GatewayProxyFactoryBean; import org.springframework.integration.jdbc.store.JdbcMessageStore; import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport; import org.springframework.integration.monitor.IntegrationMBeanExporter; -import org.springframework.integration.support.management.IntegrationManagementConfigurer; import org.springframework.util.StringUtils; /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index a5eacf2cb5e3..b3d72fd87a80 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -36,12 +36,12 @@ import org.springframework.context.annotation.Primary; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; +import org.springframework.integration.config.IntegrationManagementConfigurer; import org.springframework.integration.core.MessageSource; import org.springframework.integration.endpoint.MessageProcessorMessageSource; import org.springframework.integration.gateway.RequestReplyExchanger; import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.support.channel.HeaderChannelRegistry; -import org.springframework.integration.support.management.IntegrationManagementConfigurer; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jmx.export.MBeanExporter; diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c0c45362a544..1c863544cc27 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -158,7 +158,7 @@ 2.0.2.RELEASE Lovelace-BUILD-SNAPSHOT 0.25.0.BUILD-SNAPSHOT - 5.0.6.RELEASE + 5.1.0.BUILD-SNAPSHOT 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE 1.2.0.RELEASE From 1e7aa7c4bc210b866fb166aa70fce0c9710ced1c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 25 Jul 2018 16:25:06 +0200 Subject: [PATCH 291/701] Fix Spring Integration imports --- .../IntegrationGraphEndpointAutoConfiguration.java | 2 +- .../IntegrationGraphEndpointDocumentationTests.java | 2 +- .../IntegrationGraphEndpointAutoConfigurationTests.java | 2 +- .../boot/actuate/integration/IntegrationGraphEndpoint.java | 4 ++-- .../actuate/integration/IntegrationGraphEndpointTests.java | 4 ++-- .../IntegrationGraphEndpointWebIntegrationTests.java | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java index e6b29a8a2e92..328e2feb2c83 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java @@ -26,8 +26,8 @@ import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.integration.graph.IntegrationGraphServer; import org.springframework.integration.support.channel.HeaderChannelRegistry; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; /** * {@link EnableAutoConfiguration Auto-configuration} for the diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java index d8587e1c9ed6..02dd54295e81 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/IntegrationGraphEndpointDocumentationTests.java @@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.integration.config.EnableIntegration; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.integration.graph.IntegrationGraphServer; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java index 1263f04e4537..81200b158b15 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfigurationTests.java @@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.integration.graph.IntegrationGraphServer; import static org.assertj.core.api.Assertions.assertThat; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java index a4be984bd967..b0a90cd1a1c5 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpoint.java @@ -19,8 +19,8 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; -import org.springframework.integration.support.management.graph.Graph; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.integration.graph.Graph; +import org.springframework.integration.graph.IntegrationGraphServer; /** * {@link Endpoint} to expose the Spring Integration graph. diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java index 59c9339df28a..5bbc4f52c63d 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointTests.java @@ -22,8 +22,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.integration.support.management.graph.Graph; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.integration.graph.Graph; +import org.springframework.integration.graph.IntegrationGraphServer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java index 00a62969b9f8..80e913eeb78b 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/integration/IntegrationGraphEndpointWebIntegrationTests.java @@ -24,7 +24,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.integration.config.EnableIntegration; -import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.integration.graph.IntegrationGraphServer; import org.springframework.test.web.reactive.server.WebTestClient; /** From 787927ba819b2bd791d74c8c49f42aadee05bab5 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 26 Jul 2018 11:11:58 +0200 Subject: [PATCH 292/701] Upgrade to Spring Framework 5.1.0.RC1 Closes gh-13911 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1c863544cc27..d460858260f8 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -152,7 +152,7 @@ 1.7.25 1.21 7.4.0 - 5.1.0.BUILD-SNAPSHOT + 5.1.0.RC1 2.1.0.BUILD-SNAPSHOT 4.1.0.M2 2.0.2.RELEASE From 276f9782615b5d19dfe2486e815705af84ee3d33 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 26 Jul 2018 13:19:16 +0200 Subject: [PATCH 293/701] Upgrade to Spring Data Lovelace RC1 Closes gh-13740 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 083a9eb09197..8b7268b9e3d1 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -156,7 +156,7 @@ 2.1.0.BUILD-SNAPSHOT 4.1.0.M2 2.0.2.RELEASE - Lovelace-BUILD-SNAPSHOT + Lovelace-RC1 0.25.0.BUILD-SNAPSHOT 5.1.0.BUILD-SNAPSHOT 2.2.0.BUILD-SNAPSHOT From 4bb78d5a48261cb3928017c7ddae482c5234dc75 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Thu, 26 Jul 2018 07:39:10 +0200 Subject: [PATCH 294/701] Fix unchecked assignment in AutoConfigurationImportSelector Closes gh-13908 --- .../boot/autoconfigure/AutoConfigurationImportSelector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index 6cb236f12475..ef16563fef20 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -489,8 +489,8 @@ protected static class AutoConfigurationEntry { private final Set exclusions; private AutoConfigurationEntry() { - this.configurations = Collections.EMPTY_LIST; - this.exclusions = Collections.EMPTY_SET; + this.configurations = Collections.emptyList(); + this.exclusions = Collections.emptySet(); } /** From df6feb3e2a796e09997cc6660a787b741d719c70 Mon Sep 17 00:00:00 2001 From: artsiom Date: Wed, 25 Jul 2018 23:39:18 +0300 Subject: [PATCH 295/701] Make SpringBootConfigurationFinder public and usable with other annotations See gh-13904 --- .../SpringBootConfigurationFinder.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java index 54f07aaa493e..728669bc5f44 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java @@ -16,6 +16,7 @@ package org.springframework.boot.test.context; +import java.lang.annotation.Annotation; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -29,21 +30,34 @@ import org.springframework.util.ClassUtils; /** - * Internal utility class to scan for a {@link SpringBootConfiguration} class. + * Utility class to scan for a {@link SpringBootConfiguration} or custom annotation. * * @author Phillip Webb + * @author Artsiom Yudovin + * @since 2.1.0 */ -final class SpringBootConfigurationFinder { +public final class SpringBootConfigurationFinder { private static final Map> cache = Collections .synchronizedMap(new Cache(40)); private final ClassPathScanningCandidateComponentProvider scanner; - SpringBootConfigurationFinder() { + /** + * Default constructor initializing finder to scan for a {@link SpringBootConfiguration} annotation. + */ + public SpringBootConfigurationFinder() { + this(SpringBootConfiguration.class); + } + + /** + * Customiable constructor allow to provide the custom annotation to scan for. + * @param annotationType Annotation to scan for. + */ + public SpringBootConfigurationFinder(Class annotationType) { this.scanner = new ClassPathScanningCandidateComponentProvider(false); this.scanner.addIncludeFilter( - new AnnotationTypeFilter(SpringBootConfiguration.class)); + new AnnotationTypeFilter(annotationType)); this.scanner.setResourcePattern("*.class"); } From f78017977796961adb9e0e1ebc9363c1f6dca7a0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 26 Jul 2018 17:20:37 +0200 Subject: [PATCH 296/701] Polish contribution Closes gh-13904 --- ...nFinder.java => AnnotatedClassFinder.java} | 37 +++++++++++-------- .../SpringBootTestContextBootstrapper.java | 2 +- ...ts.java => AnnotatedClassFinderTests.java} | 8 ++-- .../test/context/example/ExampleConfig.java | 4 +- .../test/context/example/scan/Example.java | 4 +- .../example/scan/sub/SubExampleConfig.java | 6 +-- 6 files changed, 35 insertions(+), 26 deletions(-) rename spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/{SpringBootConfigurationFinder.java => AnnotatedClassFinder.java} (70%) rename spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/{SpringBootConfigurationFinderTests.java => AnnotatedClassFinderTests.java} (90%) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java similarity index 70% rename from spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java rename to spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java index 728669bc5f44..d2510b9ef0ba 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootConfigurationFinder.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java @@ -23,20 +23,20 @@ import java.util.Set; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** - * Utility class to scan for a {@link SpringBootConfiguration} or custom annotation. + * Utility class to find a class annotated with a particular annotation in a hierarchy. * * @author Phillip Webb * @author Artsiom Yudovin + * @author Stephane Nicoll * @since 2.1.0 */ -public final class SpringBootConfigurationFinder { +public final class AnnotatedClassFinder { private static final Map> cache = Collections .synchronizedMap(new Cache(40)); @@ -44,28 +44,35 @@ public final class SpringBootConfigurationFinder { private final ClassPathScanningCandidateComponentProvider scanner; /** - * Default constructor initializing finder to scan for a {@link SpringBootConfiguration} annotation. + * Create a new instance with the {@code annotationType} to find. + * @param annotationType the annotation to find */ - public SpringBootConfigurationFinder() { - this(SpringBootConfiguration.class); - } - - /** - * Customiable constructor allow to provide the custom annotation to scan for. - * @param annotationType Annotation to scan for. - */ - public SpringBootConfigurationFinder(Class annotationType) { + public AnnotatedClassFinder(Class annotationType) { + Assert.notNull(annotationType, "AnnotationType must not be null"); this.scanner = new ClassPathScanningCandidateComponentProvider(false); - this.scanner.addIncludeFilter( - new AnnotationTypeFilter(annotationType)); + this.scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType)); this.scanner.setResourcePattern("*.class"); } + /** + * Find the first {@link Class} that is annotated with the target annotation, starting + * from the package defined by the given {@code source} up to the root. + * @param source the source class to use to initiate the search + * @return the first {@link Class} annotated with the target annotation within the + * hierarchy defined by the given {@code source} or {@code null} if none is found. + */ public Class findFromClass(Class source) { Assert.notNull(source, "Source must not be null"); return findFromPackage(ClassUtils.getPackageName(source)); } + /** + * Find the first {@link Class} that is annotated with the target annotation, starting + * from the package defined by the given {@code source} up to the root. + * @param source the source package to use to initiate the search + * @return the first {@link Class} annotated with the target annotation within the + * hierarchy defined by the given {@code source} or {@code null} if none is found. + */ public Class findFromPackage(String source) { Assert.notNull(source, "Source must not be null"); Class configuration = cache.get(source); diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java index 3ee521bed711..f9f3c259cc63 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java @@ -238,7 +238,7 @@ protected Class[] getOrFindConfigurationClasses( if (containsNonTestComponent(classes) || mergedConfig.hasLocations()) { return classes; } - Class found = new SpringBootConfigurationFinder() + Class found = new AnnotatedClassFinder(SpringBootConfiguration.class) .findFromClass(mergedConfig.getTestClass()); Assert.state(found != null, "Unable to find a @SpringBootConfiguration, you need to use " diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootConfigurationFinderTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java similarity index 90% rename from spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootConfigurationFinderTests.java rename to spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java index d1899fca71f4..67a088d8033b 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootConfigurationFinderTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java @@ -20,22 +20,24 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.example.ExampleConfig; import org.springframework.boot.test.context.example.scan.Example; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link SpringBootConfigurationFinder}. + * Tests for {@link AnnotatedClassFinder}. * * @author Phillip Webb */ -public class SpringBootConfigurationFinderTests { +public class AnnotatedClassFinderTests { @Rule public ExpectedException thrown = ExpectedException.none(); - private SpringBootConfigurationFinder finder = new SpringBootConfigurationFinder(); + private AnnotatedClassFinder finder = new AnnotatedClassFinder( + SpringBootConfiguration.class); @Test public void findFromClassWhenSourceIsNullShouldThrowException() { diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java index c7aecf45ea76..e9a8582d8f29 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java @@ -17,10 +17,10 @@ package org.springframework.boot.test.context.example; import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootConfigurationFinderTests; +import org.springframework.boot.test.context.AnnotatedClassFinderTests; /** - * Example config used in {@link SpringBootConfigurationFinderTests}. + * Example config used in {@link AnnotatedClassFinderTests}. * * @author Phillip Webb */ diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java index ab96ac6cd2f5..535f4d2fc797 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java @@ -16,10 +16,10 @@ package org.springframework.boot.test.context.example.scan; -import org.springframework.boot.test.context.SpringBootConfigurationFinderTests; +import org.springframework.boot.test.context.AnnotatedClassFinderTests; /** - * Example class used in {@link SpringBootConfigurationFinderTests}. + * Example class used in {@link AnnotatedClassFinderTests}. * * @author Phillip Webb */ diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java index 21813a33005b..7bf52b74594a 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java @@ -17,11 +17,11 @@ package org.springframework.boot.test.context.example.scan.sub; import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootConfigurationFinderTests; +import org.springframework.boot.test.context.AnnotatedClassFinderTests; /** - * Example config used in {@link SpringBootConfigurationFinderTests}. Should not be found - * since scanner should only search upwards. + * Example config used in {@link AnnotatedClassFinderTests}. Should not be found since + * scanner should only search upwards. * * @author Phillip Webb */ From d8192d7e04f8aed5a0d77846d2eb757cee898ec3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 27 Jul 2018 01:41:08 +0200 Subject: [PATCH 297/701] Upgrade to Spring Amqp 2.1.0.M1 Closes gh-13885 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 17c1c36c5bb7..6e1c032fd2ce 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -153,7 +153,7 @@ 1.21 7.4.0 5.1.0.RC1 - 2.1.0.BUILD-SNAPSHOT + 2.1.0.M1 4.1.0.M2 2.0.2.RELEASE Lovelace-RC1 From 4139e1b9ab189d79a7defffa099a869bc2ee0482 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 27 Jul 2018 01:51:51 +0200 Subject: [PATCH 298/701] Upgrade to Spring Kafka 2.2.0.M1 Closes gh-13023 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b8267f59a73a..1c486166838e 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -159,7 +159,7 @@ Lovelace-RC1 0.25.0.RELEASE 5.1.0.BUILD-SNAPSHOT - 2.2.0.BUILD-SNAPSHOT + 2.2.0.M1 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 3d43bf7797a5cb3e4024b8d1b62e93957899db9b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 27 Jul 2018 09:23:40 +0200 Subject: [PATCH 299/701] Upgrade to Spring Security 5.1.0.M2 Closes gh-13899 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1c486166838e..29fdd7afcbff 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -164,7 +164,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.BUILD-SNAPSHOT + 5.1.0.M2 Apple-SR3 3.0.3.RELEASE 3.23.1 From ce9c053cbfc41f4753830bbb6c55ee7b2487856b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 27 Jul 2018 23:58:57 +0100 Subject: [PATCH 300/701] Fix checkstyle issues on master Fix checkstyle issues following 2.0.x merge and spring-javaformat upgrade. See gh-13932 --- .../springframework/boot/actuate/cache/CachesEndpoint.java | 2 +- .../boot/actuate/cache/CachesEndpointWebExtension.java | 4 ++-- .../springframework/boot/actuate/health/HealthEndpoint.java | 4 ++-- .../metrics/web/reactive/client/WebClientExchangeTags.java | 2 +- .../boot/autoconfigure/orm/jpa/HibernateProperties.java | 2 +- .../client/OAuth2ClientPropertiesRegistrationAdapter.java | 4 ++-- .../java/org/springframework/boot/maven/EnvVariables.java | 2 +- .../java/org/springframework/boot/maven/RepackageMojo.java | 6 +++--- .../boot/web/servlet/ServletContextInitializerBeans.java | 4 ++-- .../client/HttpWebServiceMessageSenderBuilder.java | 4 ++-- .../boot/webservices/client/WebServiceTemplateBuilder.java | 4 ++-- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java index 26d73e0303e8..291463dcf55a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpoint.java @@ -147,7 +147,7 @@ private boolean clearCache(CacheEntry entry) { } private Predicate isNameMatch(String name) { - return (name != null ? ((requested) -> requested.equals(name)) : matchAll()); + return (name != null) ? ((requested) -> requested.equals(name)) : matchAll(); } private Predicate matchAll() { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java index 8258ead0bc96..8029e7ee5bb0 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java @@ -44,8 +44,8 @@ public WebEndpointResponse cache(@Selector String cache, @Nullable String cacheManager) { try { CacheEntry entry = this.delegate.cache(cache, cacheManager); - int status = (entry != null ? WebEndpointResponse.STATUS_OK - : WebEndpointResponse.STATUS_NOT_FOUND); + int status = (entry != null) ? WebEndpointResponse.STATUS_OK + : WebEndpointResponse.STATUS_NOT_FOUND; return new WebEndpointResponse<>(entry, status); } catch (NonUniqueCacheException ex) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index 8004a5520252..2692da774727 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -60,7 +60,7 @@ public Health health() { public Health healthForComponent(@Selector String component) { HealthIndicator indicator = getNestedHealthIndicator(this.healthIndicator, component); - return (indicator != null ? indicator.health() : null); + return (indicator != null) ? indicator.health() : null; } /** @@ -77,7 +77,7 @@ public Health healthForComponentInstance(@Selector String component, HealthIndicator indicator = getNestedHealthIndicator(this.healthIndicator, component); HealthIndicator nestedIndicator = getNestedHealthIndicator(indicator, instance); - return (nestedIndicator != null ? nestedIndicator.health() : null); + return (nestedIndicator != null) ? nestedIndicator.health() : null; } private HealthIndicator getNestedHealthIndicator(HealthIndicator healthIndicator, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java index 5ffc05009c27..c5577f4cb207 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/client/WebClientExchangeTags.java @@ -93,7 +93,7 @@ public static Tag status(ClientResponse response) { * @return the status tag */ public static Tag status(Throwable throwable) { - return (throwable instanceof IOException ? IO_ERROR : CLIENT_ERROR); + return (throwable instanceof IOException) ? IO_ERROR : CLIENT_ERROR; } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java index 13e1112a97c3..d4100bcc3503 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateProperties.java @@ -127,7 +127,7 @@ private String determineDdlAuto(Map existing, if (ddlAuto != null) { return ddlAuto; } - return (this.ddlAuto != null ? this.ddlAuto : defaultDdlAuto.get()); + return (this.ddlAuto != null) ? this.ddlAuto : defaultDdlAuto.get(); } public static class Naming { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index a12c7864bcd7..f01e6539405c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -78,8 +78,8 @@ private static ClientRegistration getClientRegistration(String registrationId, private static Builder getBuilderFromIssuerIfPossible(String registrationId, String configuredProviderId, Map providers) { - String providerId = (configuredProviderId != null ? configuredProviderId - : registrationId); + String providerId = (configuredProviderId != null) ? configuredProviderId + : registrationId; if (providers.containsKey(providerId)) { Provider provider = providers.get(providerId); String issuer = provider.getIssuerUri(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java index a38d4876e1cb..eae12a73104e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java @@ -49,7 +49,7 @@ private static Map parseEnvVariables(Map args) { } private static String getValue(String value) { - return (value != null ? value : ""); + return (value != null) ? value : ""; } public Map asMap() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 306d93ce8b09..8444b1a36f0c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -236,7 +236,7 @@ private void repackage() throws MojoExecutionException { */ private Artifact getSourceArtifact() { Artifact sourceArtifact = getArtifact(this.classifier); - return (sourceArtifact != null ? sourceArtifact : this.project.getArtifact()); + return (sourceArtifact != null) ? sourceArtifact : this.project.getArtifact(); } private Artifact getArtifact(String classifier) { @@ -345,8 +345,8 @@ private void attachArtifact(Artifact source, File target) { this.classifier, target); } else { - String artifactId = (this.classifier != null - ? "artifact with classifier " + this.classifier : "main artifact"); + String artifactId = (this.classifier != null) + ? "artifact with classifier " + this.classifier : "main artifact"; getLog().info(String.format("Replacing %s %s", artifactId, source.getFile())); source.setFile(target); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index a08fc0bac420..5c92ff5d450f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -81,9 +81,9 @@ public class ServletContextInitializerBeans public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); - this.initializerTypes = (initializerTypes.length != 0 + this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes) - : Collections.singletonList(ServletContextInitializer.class)); + : Collections.singletonList(ServletContextInitializer.class); addServletContextInitializerBeans(beanFactory); addAdaptableBeans(beanFactory); List sortedInitializers = this.initializers.values() diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java index 2c97d952ba35..530c3b11d555 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java @@ -77,9 +77,9 @@ public HttpWebServiceMessageSenderBuilder requestFactory( } public WebServiceMessageSender build() { - ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null + ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null) ? this.requestFactorySupplier.get() - : new ClientHttpRequestFactorySupplier().get()); + : new ClientHttpRequestFactorySupplier().get(); if (this.connectTimeout != null) { new TimeoutRequestFactoryCustomizer(this.connectTimeout, "setConnectTimeout") .customize(requestFactory); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java index a855d780cace..1baf8d7196c9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -549,8 +549,8 @@ private Set append(Set set, T addition) { } private static Set append(Set set, Collection additions) { - Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); - result.addAll(additions != null ? additions : Collections.emptyList()); + Set result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); + result.addAll((additions != null) ? additions : Collections.emptyList()); return Collections.unmodifiableSet(result); } From bb7401a80db17cb5eed36baab42137760b4f8180 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sat, 28 Jul 2018 15:54:21 +0200 Subject: [PATCH 301/701] Upgrade to Spring Integration 5.1.0.M1 Closes gh-13891 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 29fdd7afcbff..743820935fdc 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -158,7 +158,7 @@ 2.0.2.RELEASE Lovelace-RC1 0.25.0.RELEASE - 5.1.0.BUILD-SNAPSHOT + 5.1.0.M1 2.2.0.M1 2.3.2.RELEASE 1.2.0.RELEASE From 4d86ac47131e132d479fe1226239ceec4a647485 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sun, 29 Jul 2018 09:30:26 +0100 Subject: [PATCH 302/701] Polish copyright date on changed files --- .../autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java | 2 +- .../boot/autoconfigure/solr/SolrAutoConfiguration.java | 2 +- .../boot/autoconfigure/ImportAutoConfigurationTests.java | 2 +- .../boot/devtools/env/DevToolPropertiesIntegrationTests.java | 2 +- .../boot/test/autoconfigure/data/ldap/DataLdapTest.java | 2 +- .../boot/test/autoconfigure/data/mongo/DataMongoTest.java | 2 +- .../boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java | 2 +- .../boot/test/autoconfigure/data/redis/DataRedisTest.java | 2 +- .../springframework/boot/test/autoconfigure/jdbc/JdbcTest.java | 2 +- .../springframework/boot/test/autoconfigure/jooq/JooqTest.java | 2 +- .../boot/test/autoconfigure/orm/jpa/DataJpaTest.java | 2 +- .../boot/test/autoconfigure/web/client/RestClientTest.java | 2 +- .../boot/test/autoconfigure/web/reactive/WebFluxTest.java | 2 +- .../boot/test/context/AnnotatedClassFinderTests.java | 2 +- .../boot/test/context/example/ExampleConfig.java | 2 +- .../springframework/boot/test/context/example/scan/Example.java | 2 +- .../boot/test/context/example/scan/sub/SubExampleConfig.java | 2 +- .../boot/web/servlet/ServletContextInitializerBeansTests.java | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java index a430002e98f6..68f4fd42dbbf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java index c661ae820256..2d0aea037df8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/solr/SolrAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java index 1934f91be5da..9aa926d9fabf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java index 125dd6bb4ffe..264cc94a6e35 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java index 37d37eab688d..1f1d3d349e19 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java index a145c1e8862d..8e2d7603f31f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java index 38b81a8da713..c31164d431b3 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java index 31b36c261d5b..2fa21a901048 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java index d553414a36c4..39b0747fae4c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java index de554d40e2bc..5821db890a0e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java index a1d7cda0a083..c3f935f286af 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java index de7d19a4f322..853b44fc4b0b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java index f8f5e5f2acb3..bcc1be8a6ba6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java index 67a088d8033b..2e8c0060080b 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java index e9a8582d8f29..9da25b55600d 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java index 535f4d2fc797..ee8137a1c3e0 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java index 7bf52b74594a..91935e2704b0 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index 6e2b9113b4a9..fd316220e005 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. From e7526a458dc5509a045e9cd811a76cd15c69687a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 30 Jul 2018 08:42:32 +0200 Subject: [PATCH 303/701] Upgrade to Spring Session Bean-M1 Closes gh-13889 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 45b8138efc3a..8abd7658024b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.M2 - Apple-SR4 + Bean-M1 3.0.3.RELEASE 3.23.1 3.1.0 From daf3f82006f41cf87437607193c7b8432d1d3a92 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Mon, 30 Jul 2018 13:44:43 +0900 Subject: [PATCH 304/701] Polish AutoConfigurationGroup.selectImports() Closes gh-13943 --- .../AutoConfigurationImportSelector.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index 4b1a128f12ee..99ee468f118a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -433,19 +433,11 @@ public Iterable selectImports() { Set allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions) .flatMap(Collection::stream).collect(Collectors.toSet()); - Set processedConfigurations = new LinkedHashSet<>(); - Set processedExclusions = new LinkedHashSet<>(); - this.autoConfigurationEntries.forEach((entry) -> { - List configurations = new ArrayList<>(entry.getConfigurations()); - configurations.removeAll(allExclusions); - configurations.removeIf(processedConfigurations::contains); - Set exclusions = new HashSet<>(entry.getExclusions()); - exclusions.removeIf(processedExclusions::contains); - // This now represents the exact state of this entry based on the - // state of all other entries - processedConfigurations.addAll(configurations); - processedExclusions.addAll(exclusions); - }); + Set processedConfigurations = this.autoConfigurationEntries.stream() + .map(AutoConfigurationEntry::getConfigurations) + .flatMap(Collection::stream) + .collect(Collectors.toCollection(LinkedHashSet::new)); + processedConfigurations.removeAll(allExclusions); return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()) From 449e1cce9f58b85efd1b3c221253f046dcec75e1 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sun, 29 Jul 2018 20:41:29 +0200 Subject: [PATCH 305/701] Avoid annotation attribute lookup in OnBeanCondition Close gh-13941 --- .../boot/autoconfigure/condition/OnBeanCondition.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index 30ff152a4b28..5da7222d54a8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -365,8 +365,7 @@ private static class BeanSearchSpec { collect(attributes, "annotation", this.annotations); collect(attributes, "ignored", this.ignoredTypes); collect(attributes, "ignoredType", this.ignoredTypes); - this.strategy = (SearchStrategy) metadata - .getAnnotationAttributes(annotationType.getName()).get("search"); + this.strategy = (SearchStrategy) attributes.getFirst("search"); BeanTypeDeductionException deductionException = null; try { if (this.types.isEmpty() && this.names.isEmpty()) { From fe4b3e493d406e5ef0e5d3c22b11cb3dd39ca75c Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sat, 28 Jul 2018 16:47:38 +0200 Subject: [PATCH 306/701] Fix deprecation in KafkaAutoConfigurationIntegrationTests Closes gh-13937 --- .../KafkaAutoConfigurationIntegrationTests.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java index 3504c0303d09..7a6e773c1698 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,7 +32,7 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.KafkaHeaders; -import org.springframework.kafka.test.rule.KafkaEmbedded; +import org.springframework.kafka.test.rule.EmbeddedKafkaRule; import org.springframework.messaging.handler.annotation.Header; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +49,7 @@ public class KafkaAutoConfigurationIntegrationTests { private static final String ADMIN_CREATED_TOPIC = "adminCreatedTopic"; @ClassRule - public static final KafkaEmbedded kafkaEmbedded = new KafkaEmbedded(1, true, + public static final EmbeddedKafkaRule embeddedKafka = new EmbeddedKafkaRule(1, true, TEST_TOPIC); private AnnotationConfigApplicationContext context; @@ -65,7 +65,7 @@ public void close() { @Test public void testEndToEnd() throws Exception { load(KafkaConfig.class, - "spring.kafka.bootstrap-servers:" + kafkaEmbedded.getBrokersAsString(), + "spring.kafka.bootstrap-servers:" + getEmbeddedKafkaBrokersAsString(), "spring.kafka.consumer.group-id=testGroup", "spring.kafka.consumer.auto-offset-reset=earliest"); KafkaTemplate template = this.context @@ -97,6 +97,10 @@ private AnnotationConfigApplicationContext doLoad(Class[] configs, return applicationContext; } + private String getEmbeddedKafkaBrokersAsString() { + return embeddedKafka.getEmbeddedKafka().getBrokersAsString(); + } + public static class KafkaConfig { @Bean From d7621261b2ab9ab66773e0405995747cc8c86e08 Mon Sep 17 00:00:00 2001 From: artsiom Date: Fri, 27 Jul 2018 20:40:43 +0300 Subject: [PATCH 307/701] Make RabbitTemplate default receive queue configurable See gh-13930 --- .../autoconfigure/amqp/RabbitAutoConfiguration.java | 2 ++ .../boot/autoconfigure/amqp/RabbitProperties.java | 13 +++++++++++++ .../amqp/RabbitAutoConfigurationTests.java | 12 ++++++++++++ .../asciidoc/appendix-application-properties.adoc | 1 + 4 files changed, 28 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index b5610970b70d..c9573b4fee55 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -79,6 +79,7 @@ * @author Stephane Nicoll * @author Gary Russell * @author Phillip Webb + * @author Artsiom Yudovin */ @Configuration @ConditionalOnClass({ RabbitTemplate.class, Channel.class }) @@ -190,6 +191,7 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { .to(template::setReplyTimeout); map.from(properties::getExchange).to(template::setExchange); map.from(properties::getRoutingKey).to(template::setRoutingKey); + map.from(properties::getQueue).whenNonNull().to(template::setQueue); return template; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index abf24b7650aa..b0e057eb22b6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -37,6 +37,7 @@ * @author Andy Wilkinson * @author Josh Thornhill * @author Gary Russell + * @author Artsiom Yudovin */ @ConfigurationProperties(prefix = "spring.rabbitmq") public class RabbitProperties { @@ -713,6 +714,11 @@ public static class Template { */ private String routingKey = ""; + /** + * Default queue name that will be used for synchronous receives. + */ + private String queue; + public Retry getRetry() { return this.retry; } @@ -757,6 +763,13 @@ public void setRoutingKey(String routingKey) { this.routingKey = routingKey; } + public String getQueue() { + return queue; + } + + public void setQueue(String queue) { + this.queue = queue; + } } public static class Retry { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index b86deccb5be4..37ef790aabfb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -62,6 +62,7 @@ import org.springframework.retry.policy.NeverRetryPolicy; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyString; @@ -319,6 +320,17 @@ public void testRabbitTemplateExchangeAndRoutingKey() { }); } + @Test + public void testRabbitTemplateDefaultQueue() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.rabbitmq.template.queue:default-queue") + .run((context) -> { + RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class); + assertThat(ReflectionTestUtils.getField(rabbitTemplate, "queue")) + .isEqualTo("default-queue"); + }); + } + @Test public void testRabbitTemplateMandatory() { this.contextRunner.withUserConfiguration(TestConfiguration.class) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index a149580bdb61..83cbfe4cdabc 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1166,6 +1166,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.template.retry.max-interval=10000ms # Maximum duration between attempts. spring.rabbitmq.template.retry.multiplier=1 # Multiplier to apply to the previous retry interval. spring.rabbitmq.template.routing-key= # Value of a default routing key to use for send operations. + spring.rabbitmq.template.queue= # Value of a default queue name that will be used for synchronous receives. spring.rabbitmq.username=guest # Login user to authenticate to the broker. spring.rabbitmq.virtual-host= # Virtual host to use when connecting to the broker. From fd85cebfef08805e70149310358f3ee3ab94ec72 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 30 Jul 2018 10:53:24 +0200 Subject: [PATCH 308/701] Polish "Make RabbitTemplate default receive queue configurable" Closes gh-13930 --- .../boot/autoconfigure/amqp/RabbitProperties.java | 6 ++++-- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index b0e057eb22b6..02292ebeccb1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -715,7 +715,8 @@ public static class Template { private String routingKey = ""; /** - * Default queue name that will be used for synchronous receives. + * Name of the default queue to receive messages from when none is specified + * explicitly. */ private String queue; @@ -764,12 +765,13 @@ public void setRoutingKey(String routingKey) { } public String getQueue() { - return queue; + return this.queue; } public void setQueue(String queue) { this.queue = queue; } + } public static class Retry { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 83cbfe4cdabc..f870f4385ab8 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1158,6 +1158,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.ssl.algorithm= # SSL algorithm to use. By default, configured by the Rabbit client library. spring.rabbitmq.template.exchange= # Name of the default exchange to use for send operations. spring.rabbitmq.template.mandatory= # Whether to enable mandatory messages. + spring.rabbitmq.template.queue= # Name of the default queue to receive messages from when none is specified explicitly. spring.rabbitmq.template.receive-timeout= # Timeout for `receive()` operations. spring.rabbitmq.template.reply-timeout= # Timeout for `sendAndReceive()` operations. spring.rabbitmq.template.retry.enabled=false # Whether publishing retries are enabled. @@ -1166,7 +1167,6 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.template.retry.max-interval=10000ms # Maximum duration between attempts. spring.rabbitmq.template.retry.multiplier=1 # Multiplier to apply to the previous retry interval. spring.rabbitmq.template.routing-key= # Value of a default routing key to use for send operations. - spring.rabbitmq.template.queue= # Value of a default queue name that will be used for synchronous receives. spring.rabbitmq.username=guest # Login user to authenticate to the broker. spring.rabbitmq.virtual-host= # Virtual host to use when connecting to the broker. From 435c47925ec80f4f98e488400d79889eeedab8e3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 31 Jul 2018 15:19:20 +0200 Subject: [PATCH 309/701] Switch JMS pooling to `pooled-jms` This commit removes support for `activemq-pool` in benefit of `pooled-jms`. While the former is not JMS 2 compliant, the latter is and is independent of the ActiveMQ codebase (so potentially reusable in custom code). Closes gh-13927 --- .../spring-boot-autoconfigure/pom.xml | 22 +++--- ...a => JmsPoolConnectionFactoryFactory.java} | 31 ++++---- ...> JmsPoolConnectionFactoryProperties.java} | 24 ++++-- ...ctiveMQConnectionFactoryConfiguration.java | 10 +-- .../jms/activemq/ActiveMQProperties.java | 5 +- ...ArtemisConnectionFactoryConfiguration.java | 10 +-- .../jms/artemis/ArtemisProperties.java | 6 +- ...itional-spring-configuration-metadata.json | 12 +++ .../jms/JmsAutoConfigurationTests.java | 14 ++-- .../ActiveMQAutoConfigurationTests.java | 63 ++++++++++------ .../ArtemisAutoConfigurationTests.java | 74 ++++++++++--------- .../spring-boot-dependencies/pom.xml | 6 ++ .../appendix-application-properties.adoc | 8 +- .../main/asciidoc/spring-boot-features.adoc | 10 +-- 14 files changed, 170 insertions(+), 125 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/{activemq/PooledConnectionFactoryFactory.java => JmsPoolConnectionFactoryFactory.java} (64%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/{activemq/PooledConnectionFactoryProperties.java => JmsPoolConnectionFactoryProperties.java} (83%) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index ff4e84fdbceb..ceb8d168dc17 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -183,17 +183,6 @@ - - org.apache.activemq - activemq-pool - true - - - geronimo-jms_1.1_spec - org.apache.geronimo.specs - - - org.apache.activemq artemis-jms-client @@ -346,6 +335,17 @@ jboss-transaction-spi true + + org.messaginghub + pooled-jms + true + + + org.apache.geronimo.specs + geronimo-jms_2.0_spec + + + org.mongodb mongodb-driver-async diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryFactory.java similarity index 64% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryFactory.java index 0a472f9dd8bc..be11c5733f98 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryFactory.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryFactory.java @@ -14,36 +14,37 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.jms.activemq; +package org.springframework.boot.autoconfigure.jms; import javax.jms.ConnectionFactory; -import org.apache.activemq.jms.pool.PooledConnectionFactory; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; /** - * Factory to create a {@link PooledConnectionFactory} from properties defined in - * {@link PooledConnectionFactoryProperties}. + * Factory to create a {@link JmsPoolConnectionFactory} from properties defined in + * {@link JmsPoolConnectionFactoryProperties}. * * @author Stephane Nicoll * @since 2.1.0 */ -public class PooledConnectionFactoryFactory { +public class JmsPoolConnectionFactoryFactory { - private final PooledConnectionFactoryProperties properties; + private final JmsPoolConnectionFactoryProperties properties; - public PooledConnectionFactoryFactory(PooledConnectionFactoryProperties properties) { + public JmsPoolConnectionFactoryFactory( + JmsPoolConnectionFactoryProperties properties) { this.properties = properties; } /** - * Create a {@link PooledConnectionFactory} based on the specified + * Create a {@link JmsPoolConnectionFactory} based on the specified * {@link ConnectionFactory}. * @param connectionFactory the connection factory to wrap * @return a pooled connection factory */ - public PooledConnectionFactory createPooledConnectionFactory( + public JmsPoolConnectionFactory createPooledConnectionFactory( ConnectionFactory connectionFactory) { - PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(); + JmsPoolConnectionFactory pooledConnectionFactory = new JmsPoolConnectionFactory(); pooledConnectionFactory.setConnectionFactory(connectionFactory); pooledConnectionFactory @@ -53,14 +54,14 @@ public PooledConnectionFactory createPooledConnectionFactory( this.properties.getBlockIfFullTimeout().toMillis()); } if (this.properties.getIdleTimeout() != null) { - pooledConnectionFactory - .setIdleTimeout((int) this.properties.getIdleTimeout().toMillis()); + pooledConnectionFactory.setConnectionIdleTimeout( + (int) this.properties.getIdleTimeout().toMillis()); } pooledConnectionFactory.setMaxConnections(this.properties.getMaxConnections()); - pooledConnectionFactory.setMaximumActiveSessionPerConnection( - this.properties.getMaximumActiveSessionPerConnection()); + pooledConnectionFactory.setMaxSessionsPerConnection( + this.properties.getMaxSessionsPerConnection()); if (this.properties.getTimeBetweenExpirationCheck() != null) { - pooledConnectionFactory.setTimeBetweenExpirationCheckMillis( + pooledConnectionFactory.setConnectionCheckInterval( this.properties.getTimeBetweenExpirationCheck().toMillis()); } pooledConnectionFactory diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryProperties.java similarity index 83% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryProperties.java index ad785ca85137..427b67d073e5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/PooledConnectionFactoryProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsPoolConnectionFactoryProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.jms.activemq; +package org.springframework.boot.autoconfigure.jms; import java.time.Duration; @@ -24,10 +24,10 @@ * @author Stephane Nicoll * @since 2.1.0 */ -public class PooledConnectionFactoryProperties { +public class JmsPoolConnectionFactoryProperties { /** - * Whether a PooledConnectionFactory should be created, instead of a regular + * Whether a JmsPoolConnectionFactory should be created, instead of a regular * ConnectionFactory. */ private boolean enabled; @@ -54,9 +54,9 @@ public class PooledConnectionFactoryProperties { private int maxConnections = 1; /** - * Maximum number of active sessions per connection. + * Maximum number of pooled sessions per connection in the pool. */ - private int maximumActiveSessionPerConnection = 500; + private int maxSessionsPerConnection = 500; /** * Time to sleep between runs of the idle connection eviction thread. When negative, @@ -110,13 +110,23 @@ public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } + @Deprecated public int getMaximumActiveSessionPerConnection() { - return this.maximumActiveSessionPerConnection; + return getMaxSessionsPerConnection(); } + @Deprecated public void setMaximumActiveSessionPerConnection( int maximumActiveSessionPerConnection) { - this.maximumActiveSessionPerConnection = maximumActiveSessionPerConnection; + setMaxSessionsPerConnection(maximumActiveSessionPerConnection); + } + + public int getMaxSessionsPerConnection() { + return this.maxSessionsPerConnection; + } + + public void setMaxSessionsPerConnection(int maxSessionsPerConnection) { + this.maxSessionsPerConnection = maxSessionsPerConnection; } public Duration getTimeBetweenExpirationCheck() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java index 1901d140c03e..3eeaddceb42b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java @@ -21,13 +21,14 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.apache.commons.pool2.PooledObject; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryFactory; import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -94,20 +95,19 @@ private ActiveMQConnectionFactory createConnectionFactory() { } @Configuration - @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) + @ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class }) static class PooledConnectionFactoryConfiguration { @Bean(destroyMethod = "stop") @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false) - public PooledConnectionFactory pooledJmsConnectionFactory( + public JmsPoolConnectionFactory pooledJmsConnectionFactory( ActiveMQProperties properties, ObjectProvider> factoryCustomizers) { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory( properties, factoryCustomizers.getIfAvailable()) .createConnectionFactory(ActiveMQConnectionFactory.class); - return new PooledConnectionFactoryFactory(properties.getPool()) + return new JmsPoolConnectionFactoryFactory(properties.getPool()) .createPooledConnectionFactory(connectionFactory); - } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java index 8e9352dd834a..bf25be69a122 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; +import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; @@ -72,7 +73,7 @@ public class ActiveMQProperties { private Duration sendTimeout = Duration.ofMillis(0); @NestedConfigurationProperty - private final PooledConnectionFactoryProperties pool = new PooledConnectionFactoryProperties(); + private final JmsPoolConnectionFactoryProperties pool = new JmsPoolConnectionFactoryProperties(); private final Packages packages = new Packages(); @@ -132,7 +133,7 @@ public void setSendTimeout(Duration sendTimeout) { this.sendTimeout = sendTimeout; } - public PooledConnectionFactoryProperties getPool() { + public JmsPoolConnectionFactoryProperties getPool() { return this.pool; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java index 01390df47d0f..a4b526df823a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisConnectionFactoryConfiguration.java @@ -19,15 +19,15 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; -import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.apache.commons.pool2.PooledObject; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryFactory; import org.springframework.boot.autoconfigure.jms.JmsProperties; -import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.connection.CachingConnectionFactory; @@ -87,17 +87,17 @@ private ActiveMQConnectionFactory createConnectionFactory() { } @Configuration - @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) + @ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class }) static class PooledConnectionFactoryConfiguration { @Bean(destroyMethod = "stop") @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "true", matchIfMissing = false) - public PooledConnectionFactory pooledJmsConnectionFactory( + public JmsPoolConnectionFactory pooledJmsConnectionFactory( ListableBeanFactory beanFactory, ArtemisProperties properties) { ActiveMQConnectionFactory connectionFactory = new ArtemisConnectionFactoryFactory( beanFactory, properties) .createConnectionFactory(ActiveMQConnectionFactory.class); - return new PooledConnectionFactoryFactory(properties.getPool()) + return new JmsPoolConnectionFactoryFactory(properties.getPool()) .createPooledConnectionFactory(connectionFactory); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java index 0a6fcf4a5315..b2791343ba47 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisProperties.java @@ -23,7 +23,7 @@ import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants; -import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryProperties; +import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; @@ -65,7 +65,7 @@ public class ArtemisProperties { private final Embedded embedded = new Embedded(); @NestedConfigurationProperty - private final PooledConnectionFactoryProperties pool = new PooledConnectionFactoryProperties(); + private final JmsPoolConnectionFactoryProperties pool = new JmsPoolConnectionFactoryProperties(); public ArtemisMode getMode() { return this.mode; @@ -111,7 +111,7 @@ public Embedded getEmbedded() { return this.embedded; } - public PooledConnectionFactoryProperties getPool() { + public JmsPoolConnectionFactoryProperties getPool() { return this.pool; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index b0f2e0fe1ffc..1538437dbf41 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -49,6 +49,18 @@ "description": "Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).", "defaultValue": true }, + { + "name": "spring.activemq.pool.maximum-active-session-per-connection", + "deprecation": { + "replacement": "spring.activemq.pool.max-sessions-per-connection" + } + }, + { + "name": "spring.artemis.pool.maximum-active-session-per-connection", + "deprecation": { + "replacement": "spring.artemis.pool.max-sessions-per-connection" + } + }, { "name": "spring.application.admin.enabled", "type": "java.lang.Boolean", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java index 552afb6b9dcf..2d3f6dfdbaa2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java @@ -20,8 +20,8 @@ import javax.jms.Session; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Test; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.BeansException; import org.springframework.beans.DirectFieldAccessor; @@ -369,8 +369,8 @@ public void testActiveMQOverriddenPool() { .withPropertyValues("spring.activemq.pool.enabled:true") .run((context) -> { JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - PooledConnectionFactory pool = context - .getBean(PooledConnectionFactory.class); + JmsPoolConnectionFactory pool = context + .getBean(JmsPoolConnectionFactory.class); assertThat(jmsTemplate).isNotNull(); assertThat(pool).isNotNull(); assertThat(pool).isEqualTo(jmsTemplate.getConnectionFactory()); @@ -387,8 +387,8 @@ public void testActiveMQOverriddenPoolAndStandalone() { "spring.activemq.inMemory:false") .run((context) -> { JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - PooledConnectionFactory pool = context - .getBean(PooledConnectionFactory.class); + JmsPoolConnectionFactory pool = context + .getBean(JmsPoolConnectionFactory.class); assertThat(jmsTemplate).isNotNull(); assertThat(pool).isNotNull(); assertThat(pool).isEqualTo(jmsTemplate.getConnectionFactory()); @@ -405,8 +405,8 @@ public void testActiveMQOverriddenPoolAndRemoteServer() { "spring.activemq.brokerUrl:tcp://remote-host:10000") .run((context) -> { JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); - PooledConnectionFactory pool = context - .getBean(PooledConnectionFactory.class); + JmsPoolConnectionFactory pool = context + .getBean(JmsPoolConnectionFactory.class); assertThat(jmsTemplate).isNotNull(); assertThat(pool).isNotNull(); assertThat(pool).isEqualTo(jmsTemplate.getConnectionFactory()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java index b2a74595efaa..4194f84cdd8b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java @@ -19,8 +19,8 @@ import javax.jms.ConnectionFactory; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Test; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; @@ -165,71 +165,86 @@ public void customConnectionFactoryIsApplied() { } @Test - public void defaultPooledConnectionFactoryIsApplied() { + public void defaultPoolConnectionFactoryIsApplied() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .withPropertyValues("spring.activemq.pool.enabled=true") .run((context) -> { - assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) .hasSize(1); - PooledConnectionFactory connectionFactory = context - .getBean(PooledConnectionFactory.class); - PooledConnectionFactory defaultFactory = new PooledConnectionFactory(); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); + JmsPoolConnectionFactory defaultFactory = new JmsPoolConnectionFactory(); assertThat(connectionFactory.isBlockIfSessionPoolIsFull()) .isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull()); assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) .isEqualTo( defaultFactory.getBlockIfSessionPoolIsFullTimeout()); - assertThat(connectionFactory.getIdleTimeout()) - .isEqualTo(defaultFactory.getIdleTimeout()); + assertThat(connectionFactory.getConnectionIdleTimeout()) + .isEqualTo(defaultFactory.getConnectionIdleTimeout()); assertThat(connectionFactory.getMaxConnections()) .isEqualTo(defaultFactory.getMaxConnections()); - assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) - .isEqualTo(defaultFactory - .getMaximumActiveSessionPerConnection()); - assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) - .isEqualTo( - defaultFactory.getTimeBetweenExpirationCheckMillis()); + assertThat(connectionFactory.getMaxSessionsPerConnection()) + .isEqualTo(defaultFactory.getMaxSessionsPerConnection()); + assertThat(connectionFactory.getConnectionCheckInterval()) + .isEqualTo(defaultFactory.getConnectionCheckInterval()); assertThat(connectionFactory.isUseAnonymousProducers()) .isEqualTo(defaultFactory.isUseAnonymousProducers()); }); } @Test - public void customPooledConnectionFactoryIsApplied() { + public void customPoolConnectionFactoryIsApplied() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .withPropertyValues("spring.activemq.pool.enabled=true", "spring.activemq.pool.blockIfFull=false", "spring.activemq.pool.blockIfFullTimeout=64", "spring.activemq.pool.idleTimeout=512", "spring.activemq.pool.maxConnections=256", - "spring.activemq.pool.maximumActiveSessionPerConnection=1024", + "spring.activemq.pool.maxSessionsPerConnection=1024", "spring.activemq.pool.timeBetweenExpirationCheck=2048", "spring.activemq.pool.useAnonymousProducers=false") .run((context) -> { - assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) .hasSize(1); - PooledConnectionFactory connectionFactory = context - .getBean(PooledConnectionFactory.class); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); assertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse(); assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) .isEqualTo(64); - assertThat(connectionFactory.getIdleTimeout()).isEqualTo(512); + assertThat(connectionFactory.getConnectionIdleTimeout()) + .isEqualTo(512); assertThat(connectionFactory.getMaxConnections()).isEqualTo(256); - assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) + assertThat(connectionFactory.getMaxSessionsPerConnection()) .isEqualTo(1024); - assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) + assertThat(connectionFactory.getConnectionCheckInterval()) .isEqualTo(2048); assertThat(connectionFactory.isUseAnonymousProducers()).isFalse(); }); } @Test - public void pooledConnectionFactoryConfiguration() { + @Deprecated + public void customPoolConnectionFactoryIsAppliedWithDeprecatedSettings() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.activemq.pool.enabled=true", + "spring.activemq.pool.maximumActiveSessionPerConnection=1024") + .run((context) -> { + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) + .hasSize(1); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); + assertThat(connectionFactory.getMaxSessionsPerConnection()) + .isEqualTo(1024); + }); + } + + @Test + public void poolConnectionFactoryConfiguration() { this.contextRunner.withUserConfiguration(EmptyConfiguration.class) .withPropertyValues("spring.activemq.pool.enabled:true") .run((context) -> { ConnectionFactory factory = context.getBean(ConnectionFactory.class); - assertThat(factory).isInstanceOf(PooledConnectionFactory.class); + assertThat(factory).isInstanceOf(JmsPoolConnectionFactory.class); context.getSourceApplicationContext().close(); assertThat(factory.createConnection()).isNull(); }); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java index c65583e6b4fd..8985127847bf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java @@ -37,10 +37,10 @@ import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl; import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl; import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS; -import org.apache.activemq.jms.pool.PooledConnectionFactory; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; @@ -350,81 +350,83 @@ public void connectToASpecificEmbeddedBroker() { } @Test - public void defaultPooledConnectionFactoryIsApplied() { + public void defaultPoolConnectionFactoryIsApplied() { this.contextRunner.withPropertyValues("spring.artemis.pool.enabled=true") .run((context) -> { - assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) .hasSize(1); - PooledConnectionFactory connectionFactory = context - .getBean(PooledConnectionFactory.class); - PooledConnectionFactory defaultFactory = new PooledConnectionFactory(); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); + JmsPoolConnectionFactory defaultFactory = new JmsPoolConnectionFactory(); assertThat(connectionFactory.isBlockIfSessionPoolIsFull()) .isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull()); assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) .isEqualTo( defaultFactory.getBlockIfSessionPoolIsFullTimeout()); - assertThat(connectionFactory.isCreateConnectionOnStartup()) - .isEqualTo(defaultFactory.isCreateConnectionOnStartup()); - assertThat(connectionFactory.getExpiryTimeout()) - .isEqualTo(defaultFactory.getExpiryTimeout()); - assertThat(connectionFactory.getIdleTimeout()) - .isEqualTo(defaultFactory.getIdleTimeout()); + assertThat(connectionFactory.getConnectionIdleTimeout()) + .isEqualTo(defaultFactory.getConnectionIdleTimeout()); assertThat(connectionFactory.getMaxConnections()) .isEqualTo(defaultFactory.getMaxConnections()); - assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) - .isEqualTo(defaultFactory - .getMaximumActiveSessionPerConnection()); - assertThat(connectionFactory.isReconnectOnException()) - .isEqualTo(defaultFactory.isReconnectOnException()); - assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) - .isEqualTo( - defaultFactory.getTimeBetweenExpirationCheckMillis()); + assertThat(connectionFactory.getMaxSessionsPerConnection()) + .isEqualTo(defaultFactory.getMaxSessionsPerConnection()); + assertThat(connectionFactory.getConnectionCheckInterval()) + .isEqualTo(defaultFactory.getConnectionCheckInterval()); assertThat(connectionFactory.isUseAnonymousProducers()) .isEqualTo(defaultFactory.isUseAnonymousProducers()); }); } @Test - public void customPooledConnectionFactoryIsApplied() { + public void customPoolConnectionFactoryIsApplied() { this.contextRunner .withPropertyValues("spring.artemis.pool.enabled=true", "spring.artemis.pool.blockIfFull=false", "spring.artemis.pool.blockIfFullTimeout=64", - "spring.artemis.pool.createConnectionOnStartup=false", - "spring.artemis.pool.expiryTimeout=4096", "spring.artemis.pool.idleTimeout=512", "spring.artemis.pool.maxConnections=256", - "spring.artemis.pool.maximumActiveSessionPerConnection=1024", - "spring.artemis.pool.reconnectOnException=false", + "spring.artemis.pool.maxSessionsPerConnection=1024", "spring.artemis.pool.timeBetweenExpirationCheck=2048", "spring.artemis.pool.useAnonymousProducers=false") .run((context) -> { - assertThat(context.getBeansOfType(PooledConnectionFactory.class)) + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) .hasSize(1); - PooledConnectionFactory connectionFactory = context - .getBean(PooledConnectionFactory.class); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); assertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse(); assertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()) .isEqualTo(64); - assertThat(connectionFactory.isCreateConnectionOnStartup()).isFalse(); - assertThat(connectionFactory.getExpiryTimeout()).isEqualTo(4096); - assertThat(connectionFactory.getIdleTimeout()).isEqualTo(512); + assertThat(connectionFactory.getConnectionIdleTimeout()) + .isEqualTo(512); assertThat(connectionFactory.getMaxConnections()).isEqualTo(256); - assertThat(connectionFactory.getMaximumActiveSessionPerConnection()) + assertThat(connectionFactory.getMaxSessionsPerConnection()) .isEqualTo(1024); - assertThat(connectionFactory.isReconnectOnException()).isFalse(); - assertThat(connectionFactory.getTimeBetweenExpirationCheckMillis()) + assertThat(connectionFactory.getConnectionCheckInterval()) .isEqualTo(2048); assertThat(connectionFactory.isUseAnonymousProducers()).isFalse(); }); } @Test - public void pooledConnectionFactoryConfiguration() { + public void customPoolConnectionFactoryIsAppliedWithDeprecatedSettings() { + this.contextRunner + .withPropertyValues("spring.artemis.pool.enabled=true", + "spring.artemis.pool.maximumActiveSessionPerConnection=1024") + .run((context) -> { + assertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)) + .hasSize(1); + JmsPoolConnectionFactory connectionFactory = context + .getBean(JmsPoolConnectionFactory.class); + assertThat(connectionFactory.getMaxSessionsPerConnection()) + .isEqualTo(1024); + }); + } + + @Test + public void poolConnectionFactoryConfiguration() { this.contextRunner.withPropertyValues("spring.artemis.pool.enabled:true") .run((context) -> { ConnectionFactory factory = context.getBean(ConnectionFactory.class); - assertThat(factory).isInstanceOf(PooledConnectionFactory.class); + assertThat(factory).isInstanceOf(JmsPoolConnectionFactory.class); context.getSourceApplicationContext().close(); assertThat(factory.createConnection()).isNull(); }); diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8abd7658024b..081379a4d32d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -135,6 +135,7 @@ 4.1.27.Final 2.0.12.Final 1.1.0 + 1.0.2 42.2.4 2.3.0 4.2.1 @@ -2282,6 +2283,11 @@ mariadb-java-client ${mariadb.version} + + org.messaginghub + pooled-jms + ${pooled-jms-version} + org.mockito mockito-core diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 37231980b6fe..d56437631d86 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -962,10 +962,10 @@ content into your application. Rather, pick only the properties that you need. spring.activemq.packages.trusted= # Comma-separated list of specific packages to trust (when not trusting all packages). spring.activemq.pool.block-if-full=true # Whether to block when a connection is requested and the pool is full. Set it to false to throw a "JMSException" instead. spring.activemq.pool.block-if-full-timeout=-1ms # Blocking period before throwing an exception if the pool is still full. - spring.activemq.pool.enabled=false # Whether a PooledConnectionFactory should be created, instead of a regular ConnectionFactory. + spring.activemq.pool.enabled=false # Whether a JmsPoolConnectionFactory should be created, instead of a regular ConnectionFactory. spring.activemq.pool.idle-timeout=30s # Connection idle timeout. spring.activemq.pool.max-connections=1 # Maximum number of pooled connections. - spring.activemq.pool.maximum-active-session-per-connection=500 # Maximum number of active sessions per connection. + spring.activemq.pool.max-sessions-per-connection=500 # Maximum number of pooled sessions per connection in the pool. spring.activemq.pool.time-between-expiration-check=-1ms # Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs. spring.activemq.pool.use-anonymous-producers=true # Whether to use only one anonymous "MessageProducer" instance. Set it to false to create one "MessageProducer" every time one is required. @@ -983,11 +983,11 @@ content into your application. Rather, pick only the properties that you need. spring.artemis.pool.block-if-full=true # Whether to block when a connection is requested and the pool is full. Set it to false to throw a "JMSException" instead. spring.artemis.pool.block-if-full-timeout=-1ms # Blocking period before throwing an exception if the pool is still full. spring.artemis.pool.create-connection-on-startup=true # Whether to create a connection on startup. Can be used to warm up the pool on startup. - spring.artemis.pool.enabled=false # Whether a PooledConnectionFactory should be created, instead of a regular ConnectionFactory. + spring.artemis.pool.enabled=false # Whether a JmsPoolConnectionFactory should be created, instead of a regular ConnectionFactory. spring.artemis.pool.expiry-timeout=0ms # Connection expiration timeout. spring.artemis.pool.idle-timeout=30s # Connection idle timeout. spring.artemis.pool.max-connections=1 # Maximum number of pooled connections. - spring.artemis.pool.maximum-active-session-per-connection=500 # Maximum number of active sessions per connection. + spring.artemis.pool.max-sessions-per-connection=500 # Maximum number of pooled sessions per connection in the pool. spring.artemis.pool.reconnect-on-exception=true # Reset the connection when a "JMSException" occurs. spring.artemis.pool.time-between-expiration-check=-1ms # Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs. spring.artemis.pool.use-anonymous-producers=true # Whether to use only one anonymous "MessageProducer" instance. Set it to false to create one "MessageProducer" every time one is required. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 85de1dc6e3b8..a4f257a2d948 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5110,8 +5110,8 @@ sensible settings that you can control by external configuration properties in ---- If you'd rather use native pooling, you can do so by adding a dependency to -`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` -accordingly, as shown in the following example: +`org.messaginghub:pooled-jms` and configuring the `JmsPoolConnectionFactory` accordingly, +as shown in the following example: [source,properties,indent=0] ---- @@ -5119,8 +5119,6 @@ accordingly, as shown in the following example: spring.activemq.pool.max-connections=50 ---- -WARNING: `PooledConnectionFactory` is not JMS 2.0 compliant - TIP: See {sc-spring-boot-autoconfigure}/jms/activemq/ActiveMQProperties.{sc-ext}[`ActiveMQProperties`] for more of the supported options. You can also register an arbitrary number of beans @@ -5178,8 +5176,8 @@ sensible settings that you can control by external configuration properties in ---- If you'd rather use native pooling, you can do so by adding a dependency to -`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` -accordingly, as shown in the following example: +`org.messaginghub:pooled-jms` and configuring the `JmsPoolConnectionFactory` accordingly, +as shown in the following example: [source,properties,indent=0] ---- From 14b413bf08cfec6fe1521e48e61e87bd3cd8f76c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 31 Jul 2018 17:00:33 +0200 Subject: [PATCH 310/701] Remove outdated hint --- .../additional-spring-configuration-metadata.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1538437dbf41..ca4e754d7d03 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -582,14 +582,6 @@ "level": "error" } }, - { - "name": "flyway.encoding", - "type": "java.lang.String", - "deprecation": { - "replacement": "spring.flyway.encoding", - "level": "error" - } - }, { "name": "flyway.init-description", "type": "java.lang.String", From 8367c57d96c0f117f80d7de8c6d3bdc1aeb37b76 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 31 Jul 2018 17:19:07 +0200 Subject: [PATCH 311/701] Avoid double binding of Flyway's locations Closes gh-4995 --- .../autoconfigure/flyway/FlywayAutoConfiguration.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index 301c59ea85bb..da93e098cf0d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -169,10 +169,7 @@ else if (this.flywayDataSource != null) { + " One type must be used exclusively."); } } - String[] locations = new LocationResolver(flyway.getDataSource()) - .resolveLocations(this.properties.getLocations()); - checkLocationExists(locations); - flyway.setLocations(locations); + checkLocationExists(flyway); return flyway; } @@ -182,7 +179,9 @@ private String getProperty(Supplier property, return (value != null) ? value : defaultValue.get(); } - private void checkLocationExists(String... locations) { + private void checkLocationExists(Flyway flyway) { + String[] locations = new LocationResolver(flyway.getDataSource()) + .resolveLocations(this.properties.getLocations()); if (this.properties.isCheckLocation()) { Assert.state(locations.length != 0, "Migration script locations not configured"); From 7b72fe0ffa5e40c52dd163a745dee7cb47f9c043 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Wed, 1 Aug 2018 17:41:15 +0900 Subject: [PATCH 312/701] Polish See gh-13963 --- .../CassandraReactiveHealthIndicatorTests.java | 2 +- .../autoconfigure/AutoConfigurationImportSelector.java | 2 +- .../condition/ConditionEvaluationReport.java | 2 +- .../main/asciidoc/appendix-application-properties.adoc | 10 +++++----- .../spring-boot-docs/src/main/asciidoc/howto.adoc | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java index 3761d0a818e3..1e21c9834069 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cassandra/CassandraReactiveHealthIndicatorTests.java @@ -33,7 +33,7 @@ import static org.mockito.Mockito.mock; /** - * Tests for {@link CassandraReactiveHealthIndicatorTests}. + * Tests for {@link CassandraReactiveHealthIndicator}. * * @author Artsiom Yudovin */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index 99ee468f118a..0416868dec2c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -412,7 +412,7 @@ public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state( deferredImportSelector instanceof AutoConfigurationImportSelector, - String.format( + () -> String.format( "AutoConfigurationImportSelector only supports %s implementations, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java index 9823a2f0291e..a5a09f2d7d8d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java @@ -147,7 +147,7 @@ public List getExclusions() { */ public Set getUnconditionalClasses() { Set filtered = new HashSet<>(this.unconditionalClasses); - filtered.removeIf(this.exclusions::contains); + filtered.removeAll(this.exclusions); return Collections.unmodifiableSet(filtered); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index d56437631d86..dbc2f8d9af15 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -259,7 +259,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.protocol-header-https-value=https # Value of the protocol header indicating whether the incoming request uses SSL. server.tomcat.redirect-context-root= # Whether requests to the context root should be redirected by appending a / to the path. server.tomcat.remote-ip-header= # Name of the HTTP header from which the remote IP is extracted. For instance, `X-FORWARDED-FOR`. - server.tomcat.resource.allow-caching= # Whether static resource caching is permitted for this web application. + server.tomcat.resource.allow-caching=true # Whether static resource caching is permitted for this web application. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. @@ -571,14 +571,14 @@ content into your application. Rather, pick only the properties that you need. spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.yaml # Change log configuration path. spring.liquibase.check-change-log-location=true # Whether to check that the change log location exists. spring.liquibase.contexts= # Comma-separated list of runtime contexts to use. - spring.liquibase.default-schema= # Default database schema. - spring.liquibase.liquibase-schema= # Schema to use for Liquibase objects. - spring.liquibase.liquibase-tablespace= # Tablespace to use for Liquibase objects. - spring.liquibase.database-change-log-table=DATABASECHANGELOG # Name of table to use for tracking change history. spring.liquibase.database-change-log-lock-table=DATABASECHANGELOGLOCK # Name of table to use for tracking concurrent Liquibase usage. + spring.liquibase.database-change-log-table=DATABASECHANGELOG # Name of table to use for tracking change history. + spring.liquibase.default-schema= # Default database schema. spring.liquibase.drop-first=false # Whether to first drop the database schema. spring.liquibase.enabled=true # Whether to enable Liquibase support. spring.liquibase.labels= # Comma-separated list of runtime labels to use. + spring.liquibase.liquibase-schema= # Schema to use for Liquibase objects. + spring.liquibase.liquibase-tablespace= # Tablespace to use for Liquibase objects. spring.liquibase.parameters.*= # Change log parameters. spring.liquibase.password= # Login password of the database to migrate. spring.liquibase.rollback-file= # File to which rollback SQL is written when an update is performed. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index 6ed1af63d088..aa88fce6272c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -763,7 +763,7 @@ additional dependency. Spring Boot manages the version for the `io.netty:netty-tcnative-boringssl-static` "uber jar", containing native libraries for -all platforms. Developers can choose to import only the required dependendencies using +all platforms. Developers can choose to import only the required dependencies using a classifier (see http://netty.io/wiki/forked-tomcat-native.html[the Netty official documentation]). From f7032bd8d3c8bb6a721bd5860bba9a43e611561e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 1 Aug 2018 11:08:59 +0200 Subject: [PATCH 313/701] Polish contribution Closes gh-13963 --- .../boot/autoconfigure/AutoConfigurationImportSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index 0416868dec2c..45a35dad77e3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -413,7 +413,7 @@ public void process(AnnotationMetadata annotationMetadata, Assert.state( deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format( - "AutoConfigurationImportSelector only supports %s implementations, got %s", + "Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) From 76d44ca888a0c450314496298bef6949258d6ed9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 1 Aug 2018 13:12:20 +0200 Subject: [PATCH 314/701] Fix formatting --- .../boot/autoconfigure/AutoConfigurationImportSelector.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index 45a35dad77e3..f4ce0050c42f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -412,8 +412,7 @@ public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state( deferredImportSelector instanceof AutoConfigurationImportSelector, - () -> String.format( - "Only %s implementations are supported, got %s", + () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) From 71d26f9cebd9d342e5b24ca36d5122bef350e19b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 1 Aug 2018 14:16:39 +0200 Subject: [PATCH 315/701] Add missing dependency for Javadoc generation --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 6d7433118226..36753aea6c2b 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -592,6 +592,11 @@ liquibase-core true + + org.messaginghub + pooled-jms + true + org.mockito mockito-core From 02e82cd22b5f6115518b331f379e28f9025cb748 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 2 Aug 2018 00:13:17 +0900 Subject: [PATCH 316/701] Remove unused dependencies Closes gh-13973 --- spring-boot-project/spring-boot/pom.xml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index 85dca2014d2a..81c30170a5a2 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -378,21 +378,6 @@ jaybird-jdk18 test - - org.eclipse.jetty - jetty-client - test - - - org.eclipse.jetty.http2 - http2-client - test - - - org.eclipse.jetty.http2 - http2-http-client-transport - test - org.hsqldb hsqldb From 0d40c5aeccacb3123d3d5b4eb4391031cddb4adf Mon Sep 17 00:00:00 2001 From: artsiom Date: Tue, 31 Jul 2018 23:53:30 +0300 Subject: [PATCH 317/701] Make "MaxSwallowSize" more easily configurable See gh-13966 --- .../boot/autoconfigure/web/ServerProperties.java | 14 ++++++++++++++ .../TomcatWebServerFactoryCustomizer.java | 16 ++++++++++++++++ .../autoconfigure/web/ServerPropertiesTests.java | 3 +++ .../TomcatWebServerFactoryCustomizerTests.java | 10 ++++++++++ .../appendix-application-properties.adoc | 1 + 5 files changed, 44 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index b943184bda4b..d793754dfcbb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -52,6 +52,7 @@ * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy + * @author Artsiom Yudovin */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -359,6 +360,11 @@ public static class Tomcat { */ private int acceptCount = 0; + /** + * Maximum amount of request body to swallow. + */ + private int maxSwallowSize = 0; + /** * Comma-separated list of additional patterns that match jars to ignore for TLD * scanning. The special '?' and '*' characters can be used in the pattern to @@ -503,6 +509,14 @@ public void setAcceptCount(int acceptCount) { this.acceptCount = acceptCount; } + public int getMaxSwallowSize() { + return this.maxSwallowSize; + } + + public void setMaxSwallowSize(int maxSwallowSize) { + this.maxSwallowSize = maxSwallowSize; + } + public List getAdditionalTldSkipPatterns() { return this.additionalTldSkipPatterns; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index a39f6df1a34d..be0bcc0d863b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -46,6 +46,7 @@ * @author Yulin Qin * @author Stephane Nicoll * @author Phillip Webb + * @author Artsiom Yudovin * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer implements @@ -101,6 +102,9 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); + propertyMapper.from(tomcatProperties::getMaxSwallowSize) + .when((maxSwallowSize) -> maxSwallowSize != 0) + .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -266,4 +270,16 @@ private void customizeErrorReportValve(ErrorProperties error, } } + @SuppressWarnings("rawtypes") + private void customizeMaxSwallowSize(ConfigurableTomcatWebServerFactory factory, + int maxSwallowSize) { + factory.addConnectorCustomizers((connector) -> { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractHttp11Protocol) { + AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; + protocol.setMaxSwallowSize(maxSwallowSize); + } + }); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 771c3b646caa..c7763e61bbb4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -42,6 +42,7 @@ * @author Eddú Meléndez * @author Quinten De Swaef * @author Venil Noronha + * @author Artsiom Yudovin */ public class ServerPropertiesTests { @@ -91,6 +92,7 @@ public void testTomcatBinding() { map.put("server.tomcat.remote-ip-header", "Remote-Ip"); map.put("server.tomcat.internal-proxies", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); map.put("server.tomcat.background-processor-delay", "10"); + map.put("server.tomcat.max-swallow-size", "2"); bind(map); ServerProperties.Tomcat tomcat = this.properties.getTomcat(); assertThat(tomcat.getAccesslog().getPattern()).isEqualTo("%h %t '%r' %s %b"); @@ -105,6 +107,7 @@ public void testTomcatBinding() { .isEqualTo("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); assertThat(tomcat.getBackgroundProcessorDelay()) .isEqualTo(Duration.ofSeconds(10)); + assertThat(tomcat.getMaxSwallowSize()).isEqualTo(2); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index ce43fac13dc8..ad02f429637d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -28,6 +28,7 @@ import org.apache.catalina.valves.RemoteIpValve; import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; +import org.apache.coyote.http11.AbstractHttp11Protocol; import org.junit.Before; import org.junit.Test; @@ -49,6 +50,7 @@ * @author Brian Clozel * @author Phillip Webb * @author Rob Tompkins + * @author Artsiom Yudovin */ public class TomcatWebServerFactoryCustomizerTests { @@ -67,6 +69,14 @@ public void setup() { this.serverProperties); } + @Test + public void customMaxSwallowSize() { + bind("server.tomcat.max-swallow-size=10"); + customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server + .getTomcat().getConnector().getProtocolHandler()).getMaxSwallowSize()) + .isEqualTo(10)); + } + @Test public void customAcceptCount() { bind("server.tomcat.accept-count=10"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index dbc2f8d9af15..bd12b0a38d4e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -263,6 +263,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. + server.tomcat.max-swallow-size= # Maximum amount of request body to swallow. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Whether to enable the access log. server.undertow.accesslog.pattern=common # Format pattern for access logs. From a8b9718073ec997e3cd4f0a696ed65a4af33364a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 2 Aug 2018 16:06:12 +0200 Subject: [PATCH 318/701] Polish "Make "MaxSwallowSize" more easily configurable" Closes gh-13966 --- .../autoconfigure/web/ServerProperties.java | 27 +++++++++--------- .../TomcatWebServerFactoryCustomizer.java | 28 +++++++++---------- .../web/ServerPropertiesTests.java | 3 -- ...TomcatWebServerFactoryCustomizerTests.java | 20 +++++++++---- .../appendix-application-properties.adoc | 2 +- 5 files changed, 42 insertions(+), 38 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index d793754dfcbb..68bc334d47fc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -52,7 +52,6 @@ * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy - * @author Artsiom Yudovin */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -330,6 +329,11 @@ public static class Tomcat { */ private int maxHttpHeaderSize = 0; + /** + * Maximum amount of request body bytes to swallow. + */ + private int maxSwallowSize = 4096; + /** * Whether requests to the context root should be redirected by appending a / to * the path. @@ -360,11 +364,6 @@ public static class Tomcat { */ private int acceptCount = 0; - /** - * Maximum amount of request body to swallow. - */ - private int maxSwallowSize = 0; - /** * Comma-separated list of additional patterns that match jars to ignore for TLD * scanning. The special '?' and '*' characters can be used in the pattern to @@ -497,6 +496,14 @@ public int getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } + public int getMaxSwallowSize() { + return this.maxSwallowSize; + } + + public void setMaxSwallowSize(int maxSwallowSize) { + this.maxSwallowSize = maxSwallowSize; + } + public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { this.maxHttpHeaderSize = maxHttpHeaderSize; } @@ -509,14 +516,6 @@ public void setAcceptCount(int acceptCount) { this.acceptCount = acceptCount; } - public int getMaxSwallowSize() { - return this.maxSwallowSize; - } - - public void setMaxSwallowSize(int maxSwallowSize) { - this.maxSwallowSize = maxSwallowSize; - } - public List getAdditionalTldSkipPatterns() { return this.additionalTldSkipPatterns; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index be0bcc0d863b..b2f70db2f624 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -86,6 +86,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); + propertyMapper.from(tomcatProperties::getMaxSwallowSize) + .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); propertyMapper.from(tomcatProperties::getMaxHttpPostSize) .when((maxHttpPostSize) -> maxHttpPostSize != 0) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, @@ -102,9 +104,6 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); - propertyMapper.from(tomcatProperties::getMaxSwallowSize) - .when((maxSwallowSize) -> maxSwallowSize != 0) - .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -220,6 +219,17 @@ private void customizeMaxHttpHeaderSize(ConfigurableTomcatWebServerFactory facto }); } + private void customizeMaxSwallowSize(ConfigurableTomcatWebServerFactory factory, + int maxSwallowSize) { + factory.addConnectorCustomizers((connector) -> { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractHttp11Protocol) { + AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; + protocol.setMaxSwallowSize(maxSwallowSize); + } + }); + } + private void customizeMaxHttpPostSize(ConfigurableTomcatWebServerFactory factory, int maxHttpPostSize) { factory.addConnectorCustomizers( @@ -270,16 +280,4 @@ private void customizeErrorReportValve(ErrorProperties error, } } - @SuppressWarnings("rawtypes") - private void customizeMaxSwallowSize(ConfigurableTomcatWebServerFactory factory, - int maxSwallowSize) { - factory.addConnectorCustomizers((connector) -> { - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractHttp11Protocol) { - AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; - protocol.setMaxSwallowSize(maxSwallowSize); - } - }); - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index c7763e61bbb4..771c3b646caa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -42,7 +42,6 @@ * @author Eddú Meléndez * @author Quinten De Swaef * @author Venil Noronha - * @author Artsiom Yudovin */ public class ServerPropertiesTests { @@ -92,7 +91,6 @@ public void testTomcatBinding() { map.put("server.tomcat.remote-ip-header", "Remote-Ip"); map.put("server.tomcat.internal-proxies", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); map.put("server.tomcat.background-processor-delay", "10"); - map.put("server.tomcat.max-swallow-size", "2"); bind(map); ServerProperties.Tomcat tomcat = this.properties.getTomcat(); assertThat(tomcat.getAccesslog().getPattern()).isEqualTo("%h %t '%r' %s %b"); @@ -107,7 +105,6 @@ public void testTomcatBinding() { .isEqualTo("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); assertThat(tomcat.getBackgroundProcessorDelay()) .isEqualTo(Duration.ofSeconds(10)); - assertThat(tomcat.getMaxSwallowSize()).isEqualTo(2); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index ad02f429637d..d5b58abaefc8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -51,6 +51,7 @@ * @author Phillip Webb * @author Rob Tompkins * @author Artsiom Yudovin + * @author Stephane Nicoll */ public class TomcatWebServerFactoryCustomizerTests { @@ -70,11 +71,12 @@ public void setup() { } @Test - public void customMaxSwallowSize() { - bind("server.tomcat.max-swallow-size=10"); - customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server - .getTomcat().getConnector().getProtocolHandler()).getMaxSwallowSize()) - .isEqualTo(10)); + public void defaultsAreConsistent() { + customizeAndRunServer((server) -> { + assertThat(((AbstractHttp11Protocol) server.getTomcat().getConnector() + .getProtocolHandler()).getMaxSwallowSize()).isEqualTo( + this.serverProperties.getTomcat().getMaxSwallowSize()); + }); } @Test @@ -117,6 +119,14 @@ public void customMaxHttpPostSize() { .isEqualTo(10000)); } + @Test + public void customMaxSwallowSize() { + bind("server.tomcat.max-swallow-size=10"); + customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server + .getTomcat().getConnector().getProtocolHandler()).getMaxSwallowSize()) + .isEqualTo(10)); + } + @Test public void customRemoteIpValve() { bind("server.tomcat.remote-ip-header=x-my-remote-ip-header", diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index bd12b0a38d4e..50add4549bec 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -252,6 +252,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time. server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content. + server.tomcat.max-swallow-size=4096 # Maximum amount of request body bytes to swallow. server.tomcat.max-threads=0 # Maximum number of worker threads. server.tomcat.min-spare-threads=0 # Minimum number of worker threads. server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value. @@ -263,7 +264,6 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. - server.tomcat.max-swallow-size= # Maximum amount of request body to swallow. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Whether to enable the access log. server.undertow.accesslog.pattern=common # Format pattern for access logs. From d92441e53f78068e4f975d4d680eef6760375f1f Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 3 Aug 2018 04:27:49 +0900 Subject: [PATCH 319/701] Update assertion message in AnnotatedClassFinder.scanPackage() Closes gh-13989 --- .../boot/test/context/AnnotatedClassFinder.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java index 2e86dfa66958..e7330e7a3614 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java @@ -41,6 +41,8 @@ public final class AnnotatedClassFinder { private static final Map> cache = Collections .synchronizedMap(new Cache(40)); + private final Class annotationType; + private final ClassPathScanningCandidateComponentProvider scanner; /** @@ -49,6 +51,7 @@ public final class AnnotatedClassFinder { */ public AnnotatedClassFinder(Class annotationType) { Assert.notNull(annotationType, "AnnotationType must not be null"); + this.annotationType = annotationType; this.scanner = new ClassPathScanningCandidateComponentProvider(false); this.scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType)); this.scanner.setResourcePattern("*.class"); @@ -88,8 +91,8 @@ private Class scanPackage(String source) { Set components = this.scanner.findCandidateComponents(source); if (!components.isEmpty()) { Assert.state(components.size() == 1, - () -> "Found multiple @SpringBootConfiguration annotated classes " - + components); + () -> "Found multiple @" + this.annotationType.getSimpleName() + + " annotated classes " + components); return ClassUtils.resolveClassName( components.iterator().next().getBeanClassName(), null); } From 844044323753ebafbbd84ea72b6922f9a11451f4 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Thu, 2 Aug 2018 20:41:01 +0200 Subject: [PATCH 320/701] Include @ in javadoc links for annotations Closes gh-13988 --- .../boot/autoconfigure/AutoConfigurationImportSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index f4ce0050c42f..b65ff3017db6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -104,7 +104,7 @@ public String[] selectImports(AnnotationMetadata annotationMetadata) { /** * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata} - * of the importing @{@link Configuration} class. + * of the importing {@link Configuration @Configuration} class. * @param autoConfigurationMetadata the auto-configuration metadata * @param annotationMetadata the annotation metadata of the configuration class * @return the auto-configurations that should be imported From 740d64242f47305d81c08bfb9f9357c01ecca81a Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Thu, 2 Aug 2018 11:09:19 -0400 Subject: [PATCH 321/701] Upgrade to Kafka 2.0.0 Closes gh-13983 --- spring-boot-project/spring-boot-dependencies/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5257f9e47c69..a9a22bc61281 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -115,7 +115,7 @@ 1.3.1 4.12 5.2.0 - 1.1.1 + 2.0.0 1.2.51 5.1.0.M1 3.6.2 @@ -160,7 +160,7 @@ Lovelace-RC1 0.25.0.RELEASE 5.1.0.M1 - 2.2.0.M1 + 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 193b2f187b904fbea4da5b810e831a21ee4273f8 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 5 Aug 2018 05:01:35 +0200 Subject: [PATCH 322/701] Upgrade to Maven Compiler Plugin 3.8.0 Closes gh-14000 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index a9a22bc61281..667bb98133fc 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -192,7 +192,7 @@ 1.8 3.1.0 3.1.0 - 3.7.0 + 3.8.0 3.1.1 2.8.2 3.0.0-M2 From c071f34a4a6f54f3521de1e2d46cdd72089807e6 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 2 Aug 2018 13:36:07 +0200 Subject: [PATCH 323/701] Add auto-configuration support for TaskExecutor This commit adds support for providing a default ThreadPoolTaskExecutor with sensible defaults. A new TaskExecutorBuilder is provided with defaults from the `spring.task.*` namespace and can be used to create custom instances. If no custom `Executor` bean is present, `@EnableAsync` now uses the auto-configure application task executor. Same goes for the async support in Spring MVC. Closes gh-1563 --- .../task/TaskExecutorAutoConfiguration.java | 90 +++++ .../autoconfigure/task/TaskProperties.java | 123 +++++++ .../boot/autoconfigure/task/package-info.java | 20 ++ .../web/servlet/WebMvcAutoConfiguration.java | 12 +- .../main/resources/META-INF/spring.factories | 1 + .../TaskExecutorAutoConfigurationTests.java | 212 ++++++++++++ .../servlet/WebMvcAutoConfigurationTests.java | 93 ++++++ .../appendix-application-properties.adoc | 7 + .../main/asciidoc/spring-boot-features.adoc | 26 ++ .../boot/task/TaskExecutorBuilder.java | 307 ++++++++++++++++++ .../boot/task/TaskExecutorCustomizer.java | 37 +++ .../boot/task/package-info.java | 22 ++ .../boot/task/TaskExecutorBuilderTests.java | 159 +++++++++ 13 files changed, 1108 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorCustomizer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java new file mode 100644 index 000000000000..b3be0b377e35 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.boot.task.TaskExecutorCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskDecorator; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@ConditionalOnClass(ThreadPoolTaskExecutor.class) +@Configuration +@EnableConfigurationProperties(TaskProperties.class) +public class TaskExecutorAutoConfiguration { + + /** + * Bean name of the application {@link TaskExecutor}. + */ + public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor"; + + private final TaskProperties properties; + + private final ObjectProvider taskExecutorCustomizers; + + private final ObjectProvider taskDecorator; + + public TaskExecutorAutoConfiguration(TaskProperties properties, + ObjectProvider taskExecutorCustomizers, + ObjectProvider taskDecorator) { + this.properties = properties; + this.taskExecutorCustomizers = taskExecutorCustomizers; + this.taskDecorator = taskDecorator; + } + + @Bean + @ConditionalOnMissingBean + public TaskExecutorBuilder taskExecutorBuilder() { + TaskExecutorBuilder builder = new TaskExecutorBuilder(); + TaskProperties.Pool pool = this.properties.getPool(); + builder = builder.queueCapacity(pool.getQueueCapacity()) + .corePoolSize(pool.getCoreSize()).maxPoolSize(pool.getMaxSize()) + .allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()) + .keepAlive(pool.getKeepAlive()); + builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix()); + builder = builder.customizers( + this.taskExecutorCustomizers.stream().collect(Collectors.toList())); + TaskDecorator taskDecorator = this.taskDecorator.getIfUnique(); + if (taskDecorator != null) { + builder = builder.taskDecorator(taskDecorator); + } + return builder; + } + + @Bean(name = APPLICATION_TASK_EXECUTOR_BEAN_NAME) + @ConditionalOnMissingBean(Executor.class) + public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { + return builder.build(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java new file mode 100644 index 000000000000..add12aa19674 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import java.time.Duration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for task execution. + * + * @author Stephane Nicoll + */ +@ConfigurationProperties("spring.task") +public class TaskProperties { + + private final Pool pool = new Pool(); + + /** + * Prefix to use for the names of newly created threads. + */ + private String threadNamePrefix = "executor-"; + + public Pool getPool() { + return this.pool; + } + + public String getThreadNamePrefix() { + return this.threadNamePrefix; + } + + public void setThreadNamePrefix(String threadNamePrefix) { + this.threadNamePrefix = threadNamePrefix; + } + + public static class Pool { + + /** + * Queue capacity. A unbounded capacity does not increase the pool and therefore + * ignores the "max-size" parameter. + */ + private int queueCapacity = Integer.MAX_VALUE; + + /** + * Core number of threads. + */ + private int coreSize = 8; + + /** + * Maximum allowed number of threads. If tasks are filling up the queue, the pool + * can expand up to that size to accommodate the load. Ignored if the queue is + * unbounded. + */ + private int maxSize = Integer.MAX_VALUE; + + /** + * Whether core threads are allowed to time out. This enables dynamic growing and + * shrinking of the pool. + */ + private boolean allowCoreThreadTimeout = true; + + /** + * Time limit for which threads may remain idle before being terminated. + */ + private Duration keepAlive = Duration.ofSeconds(60); + + public int getQueueCapacity() { + return this.queueCapacity; + } + + public void setQueueCapacity(int queueCapacity) { + this.queueCapacity = queueCapacity; + } + + public int getCoreSize() { + return this.coreSize; + } + + public void setCoreSize(int coreSize) { + this.coreSize = coreSize; + } + + public int getMaxSize() { + return this.maxSize; + } + + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + public boolean isAllowCoreThreadTimeout() { + return this.allowCoreThreadTimeout; + } + + public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) { + this.allowCoreThreadTimeout = allowCoreThreadTimeout; + } + + public Duration getKeepAlive() { + return this.keepAlive; + } + + public void setKeepAlive(Duration keepAlive) { + this.keepAlive = keepAlive; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java new file mode 100644 index 000000000000..960bf71f3a06 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for task execution. + */ +package org.springframework.boot.autoconfigure.task; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 1ce1bb8c4028..92677c0a7cbf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -46,6 +46,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration; import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; @@ -70,6 +71,7 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.format.support.FormattingConversionService; @@ -140,7 +142,7 @@ @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, - ValidationAutoConfiguration.class }) + TaskExecutorAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { public static final String DEFAULT_PREFIX = ""; @@ -210,6 +212,14 @@ public void configureMessageConverters(List> converters) @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { + if (this.beanFactory.containsBean( + TaskExecutorAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) { + Object taskExecutor = this.beanFactory.getBean( + TaskExecutorAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME); + if (taskExecutor instanceof AsyncTaskExecutor) { + configurer.setTaskExecutor(((AsyncTaskExecutor) taskExecutor)); + } + } Duration timeout = this.mvcProperties.getAsync().getRequestTimeout(); if (timeout != null) { configurer.setDefaultTimeout(timeout.toMillis()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 69b1f0e79041..3b49f16c6f44 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -106,6 +106,7 @@ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ +org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java new file mode 100644 index 000000000000..93c15cb108cc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java @@ -0,0 +1,212 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.function.Consumer; + +import org.junit.Test; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.boot.task.TaskExecutorCustomizer; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.core.task.TaskDecorator; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link TaskExecutorAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class TaskExecutorAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(TaskExecutorAutoConfiguration.class)); + + @Test + public void taskExecutorBuilderShouldApplyCustomSettings() { + this.contextRunner + .withPropertyValues("spring.task.pool.queue-capacity=10", + "spring.task.pool.core-size=2", "spring.task.pool.max-size=4", + "spring.task.pool.allow-core-thread-timeout=true", + "spring.task.pool.keep-alive=5s", + "spring.task.thread-name-prefix=mytest-") + .run(assertTaskExecutor((taskExecutor) -> { + DirectFieldAccessor dfa = new DirectFieldAccessor(taskExecutor); + assertThat(dfa.getPropertyValue("queueCapacity")).isEqualTo(10); + assertThat(taskExecutor.getCorePoolSize()).isEqualTo(2); + assertThat(taskExecutor.getMaxPoolSize()).isEqualTo(4); + assertThat(dfa.getPropertyValue("allowCoreThreadTimeOut")) + .isEqualTo(true); + assertThat(taskExecutor.getKeepAliveSeconds()).isEqualTo(5); + assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("mytest-"); + })); + } + + @Test + public void taskExecutorBuilderWhenHasCustomBuilderShouldUseCustomBuilder() { + this.contextRunner.withUserConfiguration(CustomTaskExecutorBuilderConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(TaskExecutorBuilder.class); + assertThat(context.getBean(TaskExecutorBuilder.class)) + .isSameAs(context.getBean( + CustomTaskExecutorBuilderConfig.class).taskExecutorBuilder); + }); + } + + @Test + public void taskExecutorBuilderShouldUseTaskDecorator() { + this.contextRunner.withUserConfiguration(TaskDecoratorConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(TaskExecutorBuilder.class); + ThreadPoolTaskExecutor executor = context + .getBean(TaskExecutorBuilder.class).build(); + assertThat(ReflectionTestUtils.getField(executor, "taskDecorator")) + .isSameAs(context.getBean(TaskDecorator.class)); + }); + } + + @Test + public void taskExecutorAutoConfigured() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(Executor.class); + assertThat(context).hasBean("applicationTaskExecutor"); + assertThat(context).getBean("applicationTaskExecutor") + .isInstanceOf(ThreadPoolTaskExecutor.class); + }); + } + + @Test + public void taskExecutorWhenHasCustomTaskExecutorShouldBAckOff() { + this.contextRunner.withUserConfiguration(CustomTaskExecutorConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(Executor.class); + assertThat(context.getBean(Executor.class)) + .isSameAs(context.getBean("customTaskExecutorBuilder")); + }); + } + + @Test + public void taskExecutorBuilderShouldApplyCustomizer() { + this.contextRunner.withUserConfiguration(CustomTaskExecutorConfig.class, + TaskExecutorCustomizerConfig.class).run((context) -> { + TaskExecutorCustomizer customizer = context + .getBean(TaskExecutorCustomizer.class); + ThreadPoolTaskExecutor executor = context + .getBean(TaskExecutorBuilder.class).build(); + verify(customizer).customize(executor); + }); + } + + @Test + public void enableAsyncUsesAutoConfiguredOneByDefault() { + this.contextRunner + .withPropertyValues("spring.task.thread-name-prefix=executor-test-") + .withUserConfiguration(AsyncConfiguration.class, TestBean.class) + .run((context) -> { + assertThat(context).hasSingleBean(TaskExecutor.class); + TestBean bean = context.getBean(TestBean.class); + String text = bean.echo("test").get(); + assertThat(text).contains("executor-test-").contains("test"); + }); + } + + private ContextConsumer assertTaskExecutor( + Consumer taskExecutor) { + return (context) -> { + assertThat(context).hasSingleBean(TaskExecutorBuilder.class); + TaskExecutorBuilder builder = context.getBean(TaskExecutorBuilder.class); + taskExecutor.accept(builder.build()); + }; + } + + @Configuration + static class CustomTaskExecutorBuilderConfig { + + private final TaskExecutorBuilder taskExecutorBuilder = new TaskExecutorBuilder(); + + @Bean + public TaskExecutorBuilder customTaskExecutorBuilder() { + return this.taskExecutorBuilder; + } + + } + + @Configuration + static class TaskExecutorCustomizerConfig { + + @Bean + public TaskExecutorCustomizer mockTaskExecutorCustomizer() { + return mock(TaskExecutorCustomizer.class); + } + + } + + @Configuration + static class TaskDecoratorConfig { + + @Bean + public TaskDecorator mockTaskDecorator() { + return mock(TaskDecorator.class); + } + + } + + @Configuration + static class CustomTaskExecutorConfig { + + @Bean + public Executor customTaskExecutorBuilder() { + return new SyncTaskExecutor(); + } + + } + + @Configuration + @EnableAsync + static class AsyncConfiguration { + + } + + static class TestBean { + + @Async + public Future echo(String text) { + return new AsyncResult<>(Thread.currentThread().getName() + " " + text); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 626760608691..63d4cf9dafe2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -36,6 +37,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter; @@ -52,6 +54,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.CacheControl; import org.springframework.http.HttpHeaders; @@ -75,6 +78,7 @@ import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -471,6 +475,63 @@ public void customAsyncRequestTimeout() { "asyncRequestTimeout")).isEqualTo(12345L)); } + @Test + public void asyncTaskExecutorWithApplicationTaskExecutor() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + .run((context) -> { + assertThat(context).hasSingleBean(AsyncTaskExecutor.class); + assertThat(ReflectionTestUtils.getField( + context.getBean(RequestMappingHandlerAdapter.class), + "taskExecutor")) + .isSameAs(context.getBean("applicationTaskExecutor")); + }); + } + + @Test + public void asyncTaskExecutorWithNonMatchApplicationTaskExecutorBean() { + this.contextRunner + .withUserConfiguration(CustomApplicationTaskExecutorConfig.class) + .withConfiguration( + AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + .run((context) -> { + assertThat(context).doesNotHaveBean(AsyncTaskExecutor.class); + assertThat(ReflectionTestUtils.getField( + context.getBean(RequestMappingHandlerAdapter.class), + "taskExecutor")).isNotSameAs( + context.getBean("applicationTaskExecutor")); + }); + } + + @Test + public void asyncTaskExecutorWithMvcConfigurerCanOverrideExecutor() { + this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class) + .withConfiguration( + AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + .run((context) -> { + assertThat(ReflectionTestUtils.getField( + context.getBean(RequestMappingHandlerAdapter.class), + "taskExecutor")) + .isSameAs(context.getBean( + CustomAsyncTaskExecutorConfigurer.class).taskExecutor); + }); + } + + @Test + public void asyncTaskExecutorWithCustomNonApplicationTaskExecutor() { + this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfig.class) + .withConfiguration( + AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + .run((context) -> { + assertThat(context).hasSingleBean(AsyncTaskExecutor.class); + assertThat(ReflectionTestUtils.getField( + context.getBean(RequestMappingHandlerAdapter.class), + "taskExecutor")) + .isNotSameAs(context.getBean("customTaskExecutor")); + }); + } + @Test public void customMediaTypes() { this.contextRunner @@ -1124,4 +1185,36 @@ public void configureContentNegotiation(ContentNegotiationConfigurer configurer) } + @Configuration + static class CustomApplicationTaskExecutorConfig { + + @Bean + public Executor applicationTaskExecutor() { + return mock(Executor.class); + } + + } + + @Configuration + static class CustomAsyncTaskExecutorConfig { + + @Bean + public AsyncTaskExecutor customTaskExecutor() { + return mock(AsyncTaskExecutor.class); + } + + } + + @Configuration + static class CustomAsyncTaskExecutorConfigurer implements WebMvcConfigurer { + + private final AsyncTaskExecutor taskExecutor = mock(AsyncTaskExecutor.class); + + @Override + public void configureAsyncSupport(AsyncSupportConfigurer configurer) { + configurer.setTaskExecutor(this.taskExecutor); + } + + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 50add4549bec..45a611871779 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -160,6 +160,13 @@ content into your application. Rather, pick only the properties that you need. spring.sendgrid.proxy.host= # SendGrid proxy host. spring.sendgrid.proxy.port= # SendGrid proxy port. + # TASK EXECUTION ({sc-spring-boot-autoconfigure}/task/TaskProperties.{sc-ext}[TaskProperties]) + spring.task.pool.allow-core-thread-timeout=true # Whether core threads are allowed to time out. This enables dynamic growing and shrinking of the pool. + spring.task.pool.core-size=8 # Core number of threads. + spring.task.pool.keep-alive=60s # Time limit for which threads may remain idle before being terminated. + spring.task.pool.max-size= # Maximum allowed number of threads. If tasks are filling up the queue, the pool can expand up to that size to accommodate the load. Ignored if the queue is unbounded. + spring.task.pool.queue-capacity= # Queue capacity. A unbounded capacity does not increase the pool and therefore ignores the "max-size" parameter. + spring.task.thread-name-prefix=executor- # Prefix to use for the names of newly created threads. # ---------------------------------------- # WEB PROPERTIES diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index a4f257a2d948..fb243687d3e7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6080,6 +6080,32 @@ in a similar manner, as shown in the following example: +[[boot-features-task-execution]] +== Task Execution +In the absence of a `TaskExecutor` bean in the context, Spring Boot auto-configures a +`ThreadPoolTaskExecutor` with sensible defaults that can be automatically associated to +asynchronous task execution (`@EnableAsync`) and Spring MVC asynchronous request +processing. + +The thread pool uses 8 core threads that can grow and shrink according to the load. Those +default settings can be fine-tuned using the `spring.task` namespace as shown in the +following example: + +[source,properties,indent=0] +---- + spring.task.pool.max-threads=16 + spring.task.pool.queue-capacity=100 + spring.task.pool.keep-alive=10s +---- + +This changes the thread pool to use a bounded queue so that when the queue is full (100 +tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool is more +aggressive as well as threads are reclaimed when they are idle for 10 seconds (rather than +60 seconds by default). + + + + [[boot-features-integration]] == Spring Integration Spring Boot offers several conveniences for working with {spring-integration}[Spring diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java new file mode 100644 index 000000000000..5c3c7e7b3e2a --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java @@ -0,0 +1,307 @@ +/* + * Copyright 2012-2018 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.task; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.beans.BeanUtils; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.core.task.TaskDecorator; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Builder that can be used to configure and create a {@link TaskExecutor}. Provides + * convenience methods to set common {@link ThreadPoolTaskExecutor} settings and register + * {@link #taskDecorator(TaskDecorator)}). For advanced configuration, consider using + * {@link TaskExecutorCustomizer}. + *

+ * In a typical auto-configured Spring Boot application this builder is available as a + * bean and can be injected whenever a {@link TaskExecutor} is needed. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class TaskExecutorBuilder { + + private final Integer queueCapacity; + + private final Integer corePoolSize; + + private final Integer maxPoolSize; + + private final Boolean allowCoreThreadTimeOut; + + private final Duration keepAlive; + + private final String threadNamePrefix; + + private final TaskDecorator taskDecorator; + + private final Set taskExecutorCustomizers; + + public TaskExecutorBuilder(TaskExecutorCustomizer... taskExecutorCustomizers) { + Assert.notNull(taskExecutorCustomizers, + "TaskExecutorCustomizers must not be null"); + this.queueCapacity = null; + this.corePoolSize = null; + this.maxPoolSize = null; + this.allowCoreThreadTimeOut = null; + this.keepAlive = null; + this.threadNamePrefix = null; + this.taskDecorator = null; + this.taskExecutorCustomizers = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(taskExecutorCustomizers))); + } + + public TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, + Integer maxPoolSize, Boolean allowCoreThreadTimeOut, Duration keepAlive, + String threadNamePrefix, TaskDecorator taskDecorator, + Set taskExecutorCustomizers) { + this.queueCapacity = queueCapacity; + this.corePoolSize = corePoolSize; + this.maxPoolSize = maxPoolSize; + this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; + this.keepAlive = keepAlive; + this.threadNamePrefix = threadNamePrefix; + this.taskDecorator = taskDecorator; + this.taskExecutorCustomizers = taskExecutorCustomizers; + } + + /** + * Set the capacity of the queue. A unbounded capacity does not increase the pool and + * therefore ignores {@link #maxPoolSize(int) maxPoolSize}. + * @param queueCapacity the queue capacity to set + * @return a new builder instance + */ + public TaskExecutorBuilder queueCapacity(int queueCapacity) { + return new TaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize, + this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, + this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the core number of threads. Effectively that maximum number of threads as long + * as the queue is not full. + *

+ * Core threads can grow and shrink if {@link #allowCoreThreadTimeOut(boolean)} is + * enabled. + * @param corePoolSize the core pool size to set + * @return a new builder instance + */ + public TaskExecutorBuilder corePoolSize(int corePoolSize) { + return new TaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize, + this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, + this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the maximum allowed number of threads. When the {@link #queueCapacity(int) + * queue} is full, the pool can expand up to that size to accommodate the load. + *

+ * If the {@link #queueCapacity(int) queue capacity} is unbounded, this setting is + * ignored. + * @param maxPoolSize the max pool size to set + * @return a new builder instance + */ + public TaskExecutorBuilder maxPoolSize(int maxPoolSize) { + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize, + this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, + this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set whether core threads are allow to time out. When enabled, this enables dynamic + * growing and shrinking of the pool. + * @param allowCoreThreadTimeOut if core thread are allowed to time out + * @return a new builder instance + */ + public TaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, allowCoreThreadTimeOut, this.keepAlive, + this.threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the time limit for which threads may remain idle before being terminated. + * @param keepAlive the keep alive to set + * @return a new builder instance + */ + public TaskExecutorBuilder keepAlive(Duration keepAlive) { + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, this.allowCoreThreadTimeOut, keepAlive, + this.threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the prefix to use for the names of newly created threads. + * @param threadNamePrefix the thread name prefix to set + * @return a new builder instance + */ + public TaskExecutorBuilder threadNamePrefix(String threadNamePrefix) { + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, + threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the {@link TaskDecorator} to use or {@code null} to not use any. + * @param taskDecorator the task decorator to use + * @return a new builder instance + */ + public TaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) { + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, + this.threadNamePrefix, taskDecorator, this.taskExecutorCustomizers); + } + + /** + * Set the {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be + * applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. + * @param taskExecutorCustomizers the customizers to set + * @return a new builder instance + * @see #additionalCustomizers(TaskExecutorCustomizer...) + */ + public TaskExecutorBuilder customizers( + TaskExecutorCustomizer... taskExecutorCustomizers) { + Assert.notNull(taskExecutorCustomizers, + "TaskExecutorCustomizers must not be null"); + return customizers(Arrays.asList(taskExecutorCustomizers)); + } + + /** + * Set the {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be + * applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. + * @param taskExecutorCustomizers the customizers to set + * @return a new builder instance + * @see #additionalCustomizers(TaskExecutorCustomizer...) + */ + public TaskExecutorBuilder customizers( + Collection taskExecutorCustomizers) { + Assert.notNull(taskExecutorCustomizers, + "TaskExecutorCustomizers must not be null"); + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, + this.threadNamePrefix, this.taskDecorator, + Collections.unmodifiableSet(new LinkedHashSet( + taskExecutorCustomizers))); + } + + /** + * Add {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be applied + * to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order that + * they were added after builder configuration has been applied. + * @param taskExecutorCustomizers the customizers to add + * @return a new builder instance + * @see #customizers(TaskExecutorCustomizer...) + */ + public TaskExecutorBuilder additionalCustomizers( + TaskExecutorCustomizer... taskExecutorCustomizers) { + Assert.notNull(taskExecutorCustomizers, + "TaskExecutorCustomizers must not be null"); + return additionalCustomizers(Arrays.asList(taskExecutorCustomizers)); + } + + /** + * Add {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be applied + * to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order that + * they were added after builder configuration has been applied. + * @param taskExecutorCustomizers the customizers to add + * @return a new builder instance + * @see #customizers(TaskExecutorCustomizer...) + */ + public TaskExecutorBuilder additionalCustomizers( + Collection taskExecutorCustomizers) { + Assert.notNull(taskExecutorCustomizers, + "TaskExecutorCustomizers must not be null"); + return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, + this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, + this.threadNamePrefix, this.taskDecorator, + append(this.taskExecutorCustomizers, taskExecutorCustomizers)); + } + + /** + * Build a new {@link ThreadPoolTaskExecutor} instance and configure it using this + * builder. + * @return a configured {@link ThreadPoolTaskExecutor} instance. + * @see #build(Class) + * @see #configure(ThreadPoolTaskExecutor) + */ + public ThreadPoolTaskExecutor build() { + return build(ThreadPoolTaskExecutor.class); + } + + /** + * Build a new {@link ThreadPoolTaskExecutor} instance of the specified type and + * configure it using this builder. + * @param the type of task executor + * @param taskExecutorClass the template type to create + * @return a configured {@link ThreadPoolTaskExecutor} instance. + * @see TaskExecutorBuilder#build() + * @see #configure(ThreadPoolTaskExecutor) + */ + public T build(Class taskExecutorClass) { + return configure(BeanUtils.instantiateClass(taskExecutorClass)); + } + + /** + * Configure the provided {@link ThreadPoolTaskExecutor} instance using this builder. + * @param the type of task executor + * @param taskExecutor the {@link ThreadPoolTaskExecutor} to configure + * @return the task executor instance + * @see TaskExecutorBuilder#build() + * @see TaskExecutorBuilder#build(Class) + */ + public T configure(T taskExecutor) { + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(() -> this.queueCapacity).to(taskExecutor::setQueueCapacity); + map.from(() -> this.corePoolSize).to(taskExecutor::setCorePoolSize); + map.from(() -> this.maxPoolSize).to(taskExecutor::setMaxPoolSize); + map.from(() -> this.keepAlive).asInt(Duration::getSeconds) + .to(taskExecutor::setKeepAliveSeconds); + map.from(() -> this.allowCoreThreadTimeOut) + .to(taskExecutor::setAllowCoreThreadTimeOut); + map.from(() -> this.threadNamePrefix).whenHasText() + .to(taskExecutor::setThreadNamePrefix); + map.from(() -> this.taskDecorator).to(taskExecutor::setTaskDecorator); + + if (!CollectionUtils.isEmpty(this.taskExecutorCustomizers)) { + for (TaskExecutorCustomizer customizer : this.taskExecutorCustomizers) { + customizer.customize(taskExecutor); + } + } + return taskExecutor; + } + + private static Set append(Set set, Collection additions) { + Set result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); + result.addAll(additions); + return Collections.unmodifiableSet(result); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorCustomizer.java new file mode 100644 index 000000000000..df5543333c62 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2018 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.task; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +/** + * Callback interface that can be used to customize a {@link ThreadPoolTaskExecutor}. + * + * @author Stephane Nicoll + * @since 2.1.0 + * @see TaskExecutorBuilder + */ +@FunctionalInterface +public interface TaskExecutorCustomizer { + + /** + * Callback to customize a {@link ThreadPoolTaskExecutor} instance. + * @param taskExecutor the task executor to customize + */ + void customize(ThreadPoolTaskExecutor taskExecutor); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java new file mode 100644 index 000000000000..90205e073a58 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Task execution utilities. + * + * @author Stephane Nicoll + */ +package org.springframework.boot.task; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java new file mode 100644 index 000000000000..2f560eb81eed --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java @@ -0,0 +1,159 @@ +/* + * Copyright 2012-2018 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.task; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.core.task.TaskDecorator; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +/** + * Tests for {@link TaskExecutorBuilder}. + * + * @author Stephane Nicoll + */ +public class TaskExecutorBuilderTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private TaskExecutorBuilder builder = new TaskExecutorBuilder(); + + @Test + public void createWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + new TaskExecutorBuilder((TaskExecutorCustomizer[]) null); + } + + @Test + public void poolSettingsShouldApply() { + ThreadPoolTaskExecutor executor = this.builder.allowCoreThreadTimeOut(true) + .queueCapacity(10).corePoolSize(4).maxPoolSize(8) + .allowCoreThreadTimeOut(true).keepAlive(Duration.ofMinutes(1)).build(); + DirectFieldAccessor dfa = new DirectFieldAccessor(executor); + assertThat(dfa.getPropertyValue("queueCapacity")).isEqualTo(10); + assertThat(executor.getCorePoolSize()).isEqualTo(4); + assertThat(executor.getMaxPoolSize()).isEqualTo(8); + assertThat(dfa.getPropertyValue("allowCoreThreadTimeOut")).isEqualTo(true); + assertThat(executor.getKeepAliveSeconds()).isEqualTo(60); + } + + @Test + public void threadNamePrefixShouldApply() { + ThreadPoolTaskExecutor executor = this.builder.threadNamePrefix("test-").build(); + assertThat(executor.getThreadNamePrefix()).isEqualTo("test-"); + } + + @Test + public void taskDecoratorShouldApply() { + TaskDecorator taskDecorator = mock(TaskDecorator.class); + ThreadPoolTaskExecutor executor = this.builder.taskDecorator(taskDecorator) + .build(); + assertThat(ReflectionTestUtils.getField(executor, "taskDecorator")) + .isSameAs(taskDecorator); + } + + @Test + public void customizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.builder.customizers((TaskExecutorCustomizer[]) null); + } + + @Test + public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.builder.customizers((Set) null); + } + + @Test + public void customizersShouldApply() { + TaskExecutorCustomizer customizer = mock(TaskExecutorCustomizer.class); + ThreadPoolTaskExecutor executor = this.builder.customizers(customizer).build(); + verify(customizer).customize(executor); + } + + @Test + public void customizersShouldBeAppliedLast() { + TaskDecorator taskDecorator = mock(TaskDecorator.class); + ThreadPoolTaskExecutor executor = spy(new ThreadPoolTaskExecutor()); + this.builder.allowCoreThreadTimeOut(true).queueCapacity(10).corePoolSize(4) + .maxPoolSize(8).allowCoreThreadTimeOut(true) + .keepAlive(Duration.ofMinutes(1)).threadNamePrefix("test-") + .taskDecorator(taskDecorator).additionalCustomizers((taskExecutor) -> { + verify(taskExecutor).setQueueCapacity(10); + verify(taskExecutor).setCorePoolSize(4); + verify(taskExecutor).setMaxPoolSize(8); + verify(taskExecutor).setAllowCoreThreadTimeOut(true); + verify(taskExecutor).setKeepAliveSeconds(60); + verify(taskExecutor).setThreadNamePrefix("test-"); + verify(taskExecutor).setTaskDecorator(taskDecorator); + }); + this.builder.configure(executor); + } + + @Test + public void customizersShouldReplaceExisting() { + TaskExecutorCustomizer customizer1 = mock(TaskExecutorCustomizer.class); + TaskExecutorCustomizer customizer2 = mock(TaskExecutorCustomizer.class); + ThreadPoolTaskExecutor executor = this.builder.customizers(customizer1) + .customizers(Collections.singleton(customizer2)).build(); + verifyZeroInteractions(customizer1); + verify(customizer2).customize(executor); + } + + @Test + public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.builder.additionalCustomizers((TaskExecutorCustomizer[]) null); + } + + @Test + public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.builder.additionalCustomizers((Set) null); + } + + @Test + public void additionalCustomizersShouldAddToExisting() { + TaskExecutorCustomizer customizer1 = mock(TaskExecutorCustomizer.class); + TaskExecutorCustomizer customizer2 = mock(TaskExecutorCustomizer.class); + ThreadPoolTaskExecutor executor = this.builder.customizers(customizer1) + .additionalCustomizers(customizer2).build(); + verify(customizer1).customize(executor); + verify(customizer2).customize(executor); + } + +} From 1a3f08d7729aef6009e8f29d4ef321ff5a14ddb3 Mon Sep 17 00:00:00 2001 From: artsiom Date: Fri, 3 Aug 2018 00:45:11 +0300 Subject: [PATCH 324/701] Add global support for JMX unique names See gh-13990 --- .../boot/autoconfigure/jmx/JmxAutoConfiguration.java | 6 ++++++ .../META-INF/additional-spring-configuration-metadata.json | 6 ++++++ .../boot/autoconfigure/jmx/JmxAutoConfigurationTests.java | 4 ++++ .../src/main/asciidoc/appendix-application-properties.adoc | 1 + 4 files changed, 17 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java index 7c68d99d5da5..99b31a66d7a5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java @@ -49,6 +49,7 @@ * * @author Christian Dupuis * @author Madhura Bhave + * @author Artsiom Yudovin */ @Configuration @ConditionalOnClass({ MBeanExporter.class }) @@ -93,6 +94,11 @@ public ParentAwareNamingStrategy objectNamingStrategy() { if (StringUtils.hasLength(defaultDomain)) { namingStrategy.setDefaultDomain(defaultDomain); } + + boolean uniqueName = this.environment.getProperty("spring.jmx.unique-names", + Boolean.class, false); + namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueName); + return namingStrategy; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ca4e754d7d03..4bf7b6b74759 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -290,6 +290,12 @@ "description": "MBeanServer bean name.", "defaultValue": "mbeanServer" }, + { + "name": "spring.jmx.unique-names", + "type": "java.lang.Boolean", + "description": "Whether to ensure that ObjectNames are modified in case of conflict.", + "defaultValue": false + }, { "name": "spring.jpa.open-in-view", "defaultValue": true diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java index fd9f3ae83744..a5e7c9670201 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java @@ -42,6 +42,7 @@ * Tests for {@link JmxAutoConfiguration}. * * @author Christian Dupuis + * @author Artsiom Yudovin */ public class JmxAutoConfigurationTests { @@ -92,6 +93,7 @@ public void testDefaultDomainConfiguredOnMBeanExport() { MockEnvironment env = new MockEnvironment(); env.setProperty("spring.jmx.enabled", "true"); env.setProperty("spring.jmx.default-domain", "my-test-domain"); + env.setProperty("spring.jmx.unique-names", "true"); this.context = new AnnotationConfigApplicationContext(); this.context.setEnvironment(env); this.context.register(TestConfiguration.class, JmxAutoConfiguration.class); @@ -102,6 +104,8 @@ public void testDefaultDomainConfiguredOnMBeanExport() { .getField(mBeanExporter, "namingStrategy"); assertThat(ReflectionTestUtils.getField(naming, "defaultDomain")) .isEqualTo("my-test-domain"); + assertThat(ReflectionTestUtils.getField(naming, "ensureUniqueRuntimeObjectNames")) + .isEqualTo(true); } @Test diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 45a611871779..2d2f8d9c28a1 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -100,6 +100,7 @@ content into your application. Rather, pick only the properties that you need. spring.jmx.default-domain= # JMX domain name. spring.jmx.enabled=true # Expose management beans to the JMX domain. spring.jmx.server=mbeanServer # MBeanServer bean name. + spring.jmx.unique-names=false # Set if unique runtime object names should be ensured. # Email ({sc-spring-boot-autoconfigure}/mail/MailProperties.{sc-ext}[MailProperties]) spring.mail.default-encoding=UTF-8 # Default MimeMessage encoding. From e6b44189e0e1a92da165009a4c9ced88d6eb9d73 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 6 Aug 2018 14:32:44 +0200 Subject: [PATCH 325/701] Polish "Add global support for JMX unique names" This commit ensures that the new "spring.jmx.unique-names" property deprecates the Endpoint's specific property as they share the same goal. If both are set with an incompatible value, an exception is thrown inviting the user to update their configuration. Closes gh-13990 --- .../jmx/DefaultEndpointObjectNameFactory.java | 24 ++++++++++++-- .../jmx/JmxEndpointAutoConfiguration.java | 5 +-- .../endpoint/jmx/JmxEndpointProperties.java | 12 ++++--- ...DefaultEndpointObjectNameFactoryTests.java | 32 +++++++++++++++++-- .../jmx/JmxAutoConfiguration.java | 2 -- ...itional-spring-configuration-metadata.json | 2 +- .../appendix-application-properties.adoc | 3 +- .../asciidoc/production-ready-features.adoc | 7 ++-- 8 files changed, 68 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java index c513b4933ef9..7bfff096a0b1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java @@ -22,6 +22,7 @@ import org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; +import org.springframework.core.env.Environment; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -40,11 +41,30 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { private final String contextId; + private final boolean uniqueNames; + DefaultEndpointObjectNameFactory(JmxEndpointProperties properties, - MBeanServer mBeanServer, String contextId) { + Environment environment, MBeanServer mBeanServer, String contextId) { this.properties = properties; this.mBeanServer = mBeanServer; this.contextId = contextId; + this.uniqueNames = determineUniqueNames(environment, properties); + } + + @SuppressWarnings("deprecation") + private static boolean determineUniqueNames(Environment environment, + JmxEndpointProperties properties) { + Boolean uniqueName = environment.getProperty("spring.jmx.unique-names", + Boolean.class); + Boolean endpointUniqueNames = properties.getUniqueNames(); + if (uniqueName == null) { + return (endpointUniqueNames != null) ? endpointUniqueNames : false; + } + else if (endpointUniqueNames != null & !uniqueName.equals(endpointUniqueNames)) { + throw new IllegalArgumentException( + "Configuration mismatch, 'management.endpoints.jmx.unique-names' is deprecated, use only 'spring.jmx.unique-names'"); + } + return uniqueName; } @Override @@ -57,7 +77,7 @@ public ObjectName getObjectName(ExposableJmxEndpoint endpoint) if (this.mBeanServer != null && hasMBean(baseName)) { builder.append(",context=" + this.contextId); } - if (this.properties.isUniqueNames()) { + if (this.uniqueNames) { String identity = ObjectUtils.getIdentityHexString(endpoint); builder.append(",identity=" + identity); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java index df7d5505bd86..54cb45d92be8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java @@ -45,6 +45,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import org.springframework.util.ObjectUtils; /** @@ -84,11 +85,11 @@ public JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer( @Bean @ConditionalOnSingleCandidate(MBeanServer.class) public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, - ObjectProvider objectMapper, + Environment environment, ObjectProvider objectMapper, JmxEndpointsSupplier jmxEndpointsSupplier) { String contextId = ObjectUtils.getIdentityHexString(this.applicationContext); EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory( - this.properties, mBeanServer, contextId); + this.properties, environment, mBeanServer, contextId); JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper( objectMapper.getIfAvailable()); return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointProperties.java index 02faf967d30c..f77cf02b9b63 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointProperties.java @@ -21,6 +21,7 @@ import java.util.Set; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @@ -41,9 +42,9 @@ public class JmxEndpointProperties { private String domain = "org.springframework.boot"; /** - * Whether to ensure that ObjectNames are modified in case of conflict. + * Whether unique runtime object names should be ensured. */ - private boolean uniqueNames = false; + private Boolean uniqueNames; /** * Additional static properties to append to all ObjectNames of MBeans representing @@ -70,11 +71,14 @@ public void setDomain(String domain) { this.domain = domain; } - public boolean isUniqueNames() { + @Deprecated + @DeprecatedConfigurationProperty(replacement = "spring.jmx.unique-names") + public Boolean getUniqueNames() { return this.uniqueNames; } - public void setUniqueNames(boolean uniqueNames) { + @Deprecated + public void setUniqueNames(Boolean uniqueNames) { this.uniqueNames = uniqueNames; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java index 08ebe3e580cc..19522be10664 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java @@ -22,7 +22,9 @@ import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint; import org.springframework.mock.env.MockEnvironment; @@ -39,6 +41,9 @@ */ public class DefaultEndpointObjectNameFactoryTests { + @Rule + public final ExpectedException thrown = ExpectedException.none(); + private final MockEnvironment environment = new MockEnvironment(); private final JmxEndpointProperties properties = new JmxEndpointProperties( @@ -72,7 +77,18 @@ public void generateObjectNameWithCustomDomain() { @Test public void generateObjectNameWithUniqueNames() { + this.environment.setProperty("spring.jmx.unique-names", "true"); + assertUniqueObjectName(); + } + + @Test + @Deprecated + public void generateObjectNameWithUniqueNamesDeprecatedProperty() { this.properties.setUniqueNames(true); + assertUniqueObjectName(); + } + + private void assertUniqueObjectName() { ExposableJmxEndpoint endpoint = endpoint("test"); String id = ObjectUtils.getIdentityHexString(endpoint); ObjectName objectName = generateObjectName(endpoint); @@ -80,6 +96,18 @@ public void generateObjectNameWithUniqueNames() { "org.springframework.boot:type=Endpoint,name=Test,identity=" + id); } + @Test + @Deprecated + public void generateObjectNameWithUniqueNamesDeprecatedPropertyMismatchMainProperty() { + this.environment.setProperty("spring.jmx.unique-names", "false"); + this.properties.setUniqueNames(true); + + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("spring.jmx.unique-names"); + this.thrown.expectMessage("management.endpoints.jmx.unique-names"); + generateObjectName(endpoint("test")); + } + @Test public void generateObjectNameWithStaticNames() { this.properties.getStaticNames().setProperty("counter", "42"); @@ -107,8 +135,8 @@ public void generateObjectNameWithDuplicate() throws MalformedObjectNameExceptio private ObjectName generateObjectName(ExposableJmxEndpoint endpoint) { try { - return new DefaultEndpointObjectNameFactory(this.properties, this.mBeanServer, - this.contextId).getObjectName(endpoint); + return new DefaultEndpointObjectNameFactory(this.properties, this.environment, + this.mBeanServer, this.contextId).getObjectName(endpoint); } catch (MalformedObjectNameException ex) { throw new AssertionError("Invalid object name", ex); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java index 99b31a66d7a5..4bcd4ac82fd2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java @@ -94,11 +94,9 @@ public ParentAwareNamingStrategy objectNamingStrategy() { if (StringUtils.hasLength(defaultDomain)) { namingStrategy.setDefaultDomain(defaultDomain); } - boolean uniqueName = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false); namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueName); - return namingStrategy; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 4bf7b6b74759..e6c5126dc348 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -293,7 +293,7 @@ { "name": "spring.jmx.unique-names", "type": "java.lang.Boolean", - "description": "Whether to ensure that ObjectNames are modified in case of conflict.", + "description": "Whether unique runtime object names should be ensured.", "defaultValue": false }, { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 2d2f8d9c28a1..7343cefff1e1 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -100,7 +100,7 @@ content into your application. Rather, pick only the properties that you need. spring.jmx.default-domain= # JMX domain name. spring.jmx.enabled=true # Expose management beans to the JMX domain. spring.jmx.server=mbeanServer # MBeanServer bean name. - spring.jmx.unique-names=false # Set if unique runtime object names should be ensured. + spring.jmx.unique-names=false # Whether unique runtime object names should be ensured. # Email ({sc-spring-boot-autoconfigure}/mail/MailProperties.{sc-ext}[MailProperties]) spring.mail.default-encoding=UTF-8 # Default MimeMessage encoding. @@ -1214,7 +1214,6 @@ content into your application. Rather, pick only the properties that you need. management.endpoints.jmx.exposure.include=* # Endpoint IDs that should be included or '*' for all. management.endpoints.jmx.exposure.exclude= # Endpoint IDs that should be excluded or '*' for all. management.endpoints.jmx.static-names= # Additional static properties to append to all ObjectNames of MBeans representing Endpoints. - management.endpoints.jmx.unique-names=false # Whether to ensure that ObjectNames are modified in case of conflict. # ENDPOINTS WEB CONFIGURATION ({sc-spring-boot-actuator-autoconfigure}/endpoint/web/WebEndpointProperties.{sc-ext}[WebEndpointProperties]) management.endpoints.web.exposure.include=health,info # Endpoint IDs that should be included or '*' for all. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 96060478828c..3525ab8e8452 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1200,17 +1200,16 @@ The name of the MBean is usually generated from the `id` of the endpoint. For ex `health` endpoint is exposed as `org.springframework.boot:type=Endpoint,name=Health`. If your application contains more than one Spring `ApplicationContext`, you may find that -names clash. To solve this problem, you can set the -`management.endpoints.jmx.unique-names` property to `true` so that MBean names are always -unique. +names clash. To solve this problem, you can set the `spring.jmx.unique-names` property to +`true` so that MBean names are always unique. You can also customize the JMX domain under which endpoints are exposed. The following settings show an example of doing so in `application.properties`: [source,properties,indent=0] ---- + spring.jmx.unique-names=true management.endpoints.jmx.domain=com.example.myapp - management.endpoints.jmx.unique-names=true ---- From 14a9ec8711e4e746410ae9e603b57a2eaba3fdaf Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 6 Aug 2018 14:44:44 +0200 Subject: [PATCH 326/701] Polish --- .../endpoint/jmx/DefaultEndpointObjectNameFactory.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java index 7bfff096a0b1..9476b10244a1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java @@ -72,14 +72,14 @@ public ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException { StringBuilder builder = new StringBuilder(this.properties.getDomain()); builder.append(":type=Endpoint"); - builder.append(",name=" + StringUtils.capitalize(endpoint.getId())); + builder.append(",name=").append(StringUtils.capitalize(endpoint.getId())); String baseName = builder.toString(); if (this.mBeanServer != null && hasMBean(baseName)) { - builder.append(",context=" + this.contextId); + builder.append(",context=").append(this.contextId); } if (this.uniqueNames) { String identity = ObjectUtils.getIdentityHexString(endpoint); - builder.append(",identity=" + identity); + builder.append(",identity=").append(identity); } builder.append(getStaticNames()); return ObjectNameManager.getInstance(builder.toString()); @@ -95,8 +95,8 @@ private String getStaticNames() { return ""; } StringBuilder builder = new StringBuilder(); - this.properties.getStaticNames() - .forEach((name, value) -> builder.append("," + name + "=" + value)); + this.properties.getStaticNames().forEach((name, value) -> builder.append(",") + .append(name).append("=").append(value)); return builder.toString(); } From d6b6a5f81f1f4790f45318522c856e9e78f23510 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 6 Aug 2018 16:29:39 -0700 Subject: [PATCH 327/701] Add auto-config for spring-security-oauth2-resource-server Closes gh-13787 --- .../spring-boot-autoconfigure/pom.xml | 5 + .../OAuth2ResourceServerProperties.java | 69 ++++++++++ .../oauth2/resource/package-info.java | 20 +++ ...OAuth2ResourceServerAutoConfiguration.java | 42 +++++++ .../OAuth2ResourceServerJwkConfiguration.java | 49 ++++++++ ...esourceServerWebSecurityConfiguration.java | 47 +++++++ .../oauth2/resource/servlet/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 1 + ...2ResourceServerAutoConfigurationTests.java | 118 ++++++++++++++++++ .../appendix-application-properties.adoc | 3 + .../main/asciidoc/spring-boot-features.adoc | 20 ++- .../pom.xml | 60 +++++++++ .../oauth2/resource/ExampleController.java | 31 +++++ ...SampleOauth2ResourceServerApplication.java | 28 +++++ .../src/main/resources/application.yml | 8 ++ ...eOauth2ResourceServerApplicationTests.java | 111 ++++++++++++++++ 16 files changed, 629 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java create mode 100644 spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java create mode 100644 spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml create mode 100644 spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index ceb8d168dc17..6140047e779a 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -553,6 +553,11 @@ spring-security-oauth2-client true + + org.springframework.security + spring-security-oauth2-resource-server + true + org.springframework.session spring-session-core diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java new file mode 100644 index 000000000000..3758be17edd7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * OAuth 2.0 resource server properties. + * + * @author Madhura Bhave + */ +@ConfigurationProperties(prefix = "spring.security.oauth2.resource") +public class OAuth2ResourceServerProperties { + + private Jwt jwt = new Jwt(); + + public Jwt getJwt() { + return this.jwt; + } + + public void setJwt(Jwt jwt) { + this.jwt = jwt; + } + + public static class Jwt { + + private Jwk jwk = new Jwk(); + + public Jwk getJwk() { + return this.jwk; + } + + public void setJwk(Jwk jwk) { + this.jwk = jwk; + } + + } + + public static class Jwk { + + /** + * The URI to get verification keys to verify the JWT token. + */ + private String setUri; + + public String getSetUri() { + return this.setUri; + } + + public void setSetUri(String setUri) { + this.setUri = setUri; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java new file mode 100644 index 000000000000..ff8ebd6d0224 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Support for Spring Security's OAuth 2 resource server. + */ +package org.springframework.boot.autoconfigure.security.oauth2.resource; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java new file mode 100644 index 000000000000..d2685b3965fa --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.servlet; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for OAuth resource server support. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore(SecurityAutoConfiguration.class) +@EnableConfigurationProperties(OAuth2ResourceServerProperties.class) +@ConditionalOnClass(JwtAuthenticationToken.class) +@Import({ OAuth2ResourceServerJwkConfiguration.class, + OAuth2ResourceServerWebSecurityConfiguration.class }) +public class OAuth2ResourceServerAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java new file mode 100644 index 000000000000..8180ca140529 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.servlet; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; + +/** + * Configures a {@link JwtDecoder} when a JWK Set URI is available. + * + * @author Madhura Bhave + */ +@Configuration +class OAuth2ResourceServerJwkConfiguration { + + private final OAuth2ResourceServerProperties properties; + + public OAuth2ResourceServerJwkConfiguration( + OAuth2ResourceServerProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri") + @ConditionalOnMissingBean + public JwtDecoder jwtDecoder() { + return new NimbusJwtDecoderJwkSupport( + this.properties.getJwt().getJwk().getSetUri()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java new file mode 100644 index 000000000000..7a6e6f31b520 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.servlet; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.oauth2.jwt.JwtDecoder; + +/** + * {@link WebSecurityConfigurerAdapter} for OAuth2 resource server support. + * + * @author Madhura Bhave + */ +@Configuration +@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +class OAuth2ResourceServerWebSecurityConfiguration { + + @Configuration + @ConditionalOnBean(JwtDecoder.class) + static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().authenticated().and().oauth2() + .resourceServer().jwt(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java new file mode 100644 index 000000000000..bdde81113329 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Security's OAuth 2 resource server. + */ +package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 3b49f16c6f44..c8dd4ff1da81 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -105,6 +105,7 @@ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java new file mode 100644 index 000000000000..78ba79f0feea --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -0,0 +1,118 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.servlet; + +import java.util.List; + +import javax.servlet.Filter; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.BeanIds; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter; +import org.springframework.security.web.FilterChainProxy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link OAuth2ResourceServerAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class OAuth2ResourceServerAutoConfigurationTests { + + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class)) + .withUserConfiguration(TestConfig.class); + + @Test + public void autoConfigurationShouldConfigureResourceServer() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .run((context) -> { + assertThat(context.getBean(JwtDecoder.class)) + .isInstanceOf(NimbusJwtDecoderJwkSupport.class); + assertThat(getBearerTokenFilter(context)).isNotNull(); + }); + } + + @Test + public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { + this.contextRunner + .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); + } + + @Test + public void jwtDecoderBeanIsConditionalOnMissingBean() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .withUserConfiguration(JwtDecoderConfig.class) + .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull()); + } + + @Test + public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .withUserConfiguration(JwtDecoderConfig.class) + .withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class)) + .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); + } + + @SuppressWarnings("unchecked") + private Filter getBearerTokenFilter(AssertableWebApplicationContext context) { + FilterChainProxy filterChain = (FilterChainProxy) context + .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); + List filterChains = filterChain.getFilterChains(); + List filters = (List) ReflectionTestUtils + .getField(filterChains.get(0), "filters"); + return filters.stream() + .filter((f) -> f instanceof BearerTokenAuthenticationFilter).findFirst() + .orElse(null); + } + + @Configuration + @EnableWebSecurity + static class TestConfig { + + } + + @Configuration + @EnableWebSecurity + static class JwtDecoderConfig { + + @Bean + public JwtDecoder decoder() { + return mock(JwtDecoder.class); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 7343cefff1e1..22c461b96da7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -529,6 +529,9 @@ content into your application. Rather, pick only the properties that you need. spring.security.oauth2.client.provider.*= # OAuth provider details. spring.security.oauth2.client.registration.*= # OAuth client registrations. + # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) + spring.security.oauth2.resource.jwt.jwk.set-uri.*= # JWK Set URI + # ---------------------------------------- # DATA PROPERTIES # ---------------------------------------- diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index fb243687d3e7..e0284ba337c9 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3276,12 +3276,26 @@ Provider can be configured with the `issuer-uri`: [[boot-features-security-oauth2-server]] -==== Server +==== Resource Server +If you have `spring-security-oauth2-resource-server` on your classpath, you can take advantage of +some auto-configuration to make it easy to set up an OAuth2 Resource Server. This configuration +makes use of the properties under `OAuth2ResourceServerProperties`. + +For the OAuth2 Resource Server auto-configuration to kick in, you can +provide a bean of type `JwtDecoder` yourself or configure a JWK Set URI as follows: + +[source,properties,indent=0] +---- + spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys +---- + + +==== Authorization Server Currently, Spring Security does not provide support for implementing an OAuth 2.0 -Authorization Server or Resource Server. However, this functionality is available from +Authorization Server. However, this functionality is available from the https://projects.spring.io/spring-security-oauth/[Spring Security OAuth] project, which will eventually be superseded by Spring Security completely. Until then, you can -use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 server; +use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 authorization server; see its https://docs.spring.io/spring-security-oauth2-boot[documentation] for instructions. diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml new file mode 100644 index 000000000000..649d19b77de0 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + ${revision} + + spring-boot-sample-oauth2-resource-server + Spring Boot Sample OAuth2 Resource Server + Spring Boot Sample Resource Server + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-resource-server + + + org.springframework.security + spring-security-oauth2-jose + + + + com.squareup.okhttp3 + mockwebserver + 3.9.0 + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java new file mode 100644 index 000000000000..00a7be974334 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ExampleController { + + @GetMapping("/") + public String index(@AuthenticationPrincipal Jwt jwt) { + return String.format("Hello, %s!", jwt.getSubject()); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java new file mode 100644 index 000000000000..f80400458e46 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleOauth2ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleOauth2ResourceServerApplication.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml new file mode 100644 index 000000000000..2599bf40916c --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml @@ -0,0 +1,8 @@ +spring: + security: + oauth2: + resource: + jwt: + jwk: + # To run the application, replace this with a valid JWK Set URI + set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java new file mode 100644 index 000000000000..062bf013f186 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import java.io.IOException; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class SampleOauth2ResourceServerApplicationTests { + + private static MockWebServer server = new MockWebServer(); + + private static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi" + + "LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU" + + "OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN" + + "afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql" + + "R44vmRqS5ncrF-1R0EGcPX49U6A"; + + @Autowired + private TestRestTemplate restTemplate; + + @BeforeClass + public static void setup() throws Exception { + server.start(); + String url = server.url("/.well-known/jwks.json").toString(); + server.enqueue(mockResponse()); + System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url); + } + + @AfterClass + public static void shutdown() throws IOException { + server.shutdown(); + System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri"); + } + + @Test + public void withValidBearerTokenShouldAllowAccess() { + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(VALID_TOKEN); + HttpEntity request = new HttpEntity(headers); + ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET, + request, String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + } + + @Test + public void withNoBearerTokenShouldNotAllowAccess() { + HttpHeaders headers = new HttpHeaders(); + HttpEntity request = new HttpEntity(headers); + ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET, + request, String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); + } + + private static MockResponse mockResponse() { + String body = "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw" + + "DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\"" + + ",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO" + + "1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\"" + + ":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7" + + "VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0" + + "851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo" + + "3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK4" + + "8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o" + + "XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ" + + "PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8" + + "M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF" + + "k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn" + + "uYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs" + + "V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5" + + "8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq" + + "D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}"; + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .setResponseCode(200).setBody(body); + } + +} \ No newline at end of file From 5bf9d31d91a6e45bed5cf0e878431004765c9b86 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 6 Aug 2018 17:10:30 -0700 Subject: [PATCH 328/701] Fix checkstyle --- .../resource/servlet/OAuth2ResourceServerJwkConfiguration.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java index 8180ca140529..f6deea3ce5e3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java @@ -33,8 +33,7 @@ class OAuth2ResourceServerJwkConfiguration { private final OAuth2ResourceServerProperties properties; - public OAuth2ResourceServerJwkConfiguration( - OAuth2ResourceServerProperties properties) { + OAuth2ResourceServerJwkConfiguration(OAuth2ResourceServerProperties properties) { this.properties = properties; } From ace242db7ac8ef4e76bf870ae9568786bf1718d0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 7 Aug 2018 08:54:14 +0200 Subject: [PATCH 329/701] Fix javadoc generation on Java 9/10 --- spring-boot-project/spring-boot-docs/pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 36753aea6c2b..d21eb8d3da56 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -732,6 +732,11 @@ spring-security-config true + + org.springframework.security + spring-security-oauth2-client + true + org.springframework.security spring-security-oauth2-jose @@ -739,7 +744,7 @@ org.springframework.security - spring-security-oauth2-client + spring-security-oauth2-resource-server true From 60d8c7979fd5e21ff2682cf7b9ee408e641fed10 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 7 Aug 2018 09:28:21 +0200 Subject: [PATCH 330/701] Polish --- .../spring-boot-autoconfigure/pom.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 6140047e779a..4b8e2020eb47 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -530,17 +530,17 @@ org.springframework.security - spring-security-web + spring-security-config true org.springframework.security - spring-security-config + spring-security-data true org.springframework.security - spring-security-data + spring-security-oauth2-client true @@ -550,12 +550,12 @@ org.springframework.security - spring-security-oauth2-client + spring-security-oauth2-resource-server true - org.springframework.security - spring-security-oauth2-resource-server + org.springframework.security + spring-security-web true From 5cfe8dbee950dbf3a8de3ece2f6f3363f13d904a Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 7 Aug 2018 17:52:47 +0200 Subject: [PATCH 331/701] Polish --- .../resource/OAuth2ResourceServerProperties.java | 15 ++++----------- .../asciidoc/appendix-application-properties.adoc | 2 +- .../src/main/asciidoc/spring-boot-features.adoc | 12 ++++++------ spring-boot-samples/README.adoc | 3 +++ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java index 3758be17edd7..bf02b208f595 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -21,38 +21,31 @@ * OAuth 2.0 resource server properties. * * @author Madhura Bhave + * @since 2.1.0 */ @ConfigurationProperties(prefix = "spring.security.oauth2.resource") public class OAuth2ResourceServerProperties { - private Jwt jwt = new Jwt(); + private final Jwt jwt = new Jwt(); public Jwt getJwt() { return this.jwt; } - public void setJwt(Jwt jwt) { - this.jwt = jwt; - } - public static class Jwt { - private Jwk jwk = new Jwk(); + private final Jwk jwk = new Jwk(); public Jwk getJwk() { return this.jwk; } - public void setJwk(Jwk jwk) { - this.jwk = jwk; - } - } public static class Jwk { /** - * The URI to get verification keys to verify the JWT token. + * JSON Web Key URI to use to verify the JWT token. */ private String setUri; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 22c461b96da7..6f14d951f2d9 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -530,7 +530,7 @@ content into your application. Rather, pick only the properties that you need. spring.security.oauth2.client.registration.*= # OAuth client registrations. # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) - spring.security.oauth2.resource.jwt.jwk.set-uri.*= # JWK Set URI + spring.security.oauth2.resource.jwt.jwk.set-uri= # JSON Web Key URI to use to verify the JWT token. # ---------------------------------------- # DATA PROPERTIES diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index e0284ba337c9..130cedd55ebe 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3277,18 +3277,18 @@ Provider can be configured with the `issuer-uri`: [[boot-features-security-oauth2-server]] ==== Resource Server -If you have `spring-security-oauth2-resource-server` on your classpath, you can take advantage of -some auto-configuration to make it easy to set up an OAuth2 Resource Server. This configuration -makes use of the properties under `OAuth2ResourceServerProperties`. - -For the OAuth2 Resource Server auto-configuration to kick in, you can -provide a bean of type `JwtDecoder` yourself or configure a JWK Set URI as follows: +If you have `spring-security-oauth2-resource-server` on your classpath, Spring Boot can +set up an OAuth2 Resource Server as long as a JWK Set URI is specified, as shown in the +following example: [source,properties,indent=0] ---- spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys ---- +Alternatively, you can define your own `JwtDecoder` bean. + + ==== Authorization Server Currently, Spring Security does not provide support for implementing an OAuth 2.0 diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc index 7e71a3c53f5e..8a7378508c6a 100644 --- a/spring-boot-samples/README.adoc +++ b/spring-boot-samples/README.adoc @@ -134,6 +134,9 @@ The following sample applications are provided: | link:spring-boot-sample-metrics-redis[spring-boot-sample-metrics-redis] | Exports metrics to Redis +| link:spring-boot-sample-oauth2-resource-server[spring-boot-sample-oauth2-resource-server] +| Configure an OAuth2 resource server + | link:spring-boot-sample-parent-context[spring-boot-sample-parent-context] | Application that uses an `ApplicationContext` with a parent From 319fec4be4263f21c3b4c30cfade449d0acf7efd Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 7 Aug 2018 14:48:16 -0700 Subject: [PATCH 332/701] Polish --- .../autoconfigure/security/oauth2/resource/package-info.java | 2 +- .../resource/servlet/OAuth2ResourceServerAutoConfiguration.java | 2 ++ .../servlet/OAuth2ResourceServerWebSecurityConfiguration.java | 2 -- .../security/oauth2/resource/servlet/package-info.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java index ff8ebd6d0224..b660f1110573 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java @@ -15,6 +15,6 @@ */ /** - * Support for Spring Security's OAuth 2 resource server. + * Support for Spring Security's OAuth2 resource server. */ package org.springframework.boot.autoconfigure.security.oauth2.resource; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java index d2685b3965fa..c42ead6d8a04 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java @@ -18,6 +18,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -35,6 +36,7 @@ @AutoConfigureBefore(SecurityAutoConfiguration.class) @EnableConfigurationProperties(OAuth2ResourceServerProperties.class) @ConditionalOnClass(JwtAuthenticationToken.class) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @Import({ OAuth2ResourceServerJwkConfiguration.class, OAuth2ResourceServerWebSecurityConfiguration.class }) public class OAuth2ResourceServerAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java index 7a6e6f31b520..60ec434c1eac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java @@ -17,7 +17,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @@ -30,7 +29,6 @@ */ @Configuration @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) -@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) class OAuth2ResourceServerWebSecurityConfiguration { @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java index bdde81113329..fcb6d52f2e4d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for Spring Security's OAuth 2 resource server. + * Auto-configuration for Spring Security's OAuth2 resource server. */ package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet; From bc6e4e6e55dff742868ab51eac92727e8e9dbb5f Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 7 Aug 2018 15:09:33 -0700 Subject: [PATCH 333/701] Add auto-config for reactive OAuth2 Resource Server Closes gh-13948 --- ...OAuth2ResourceServerAutoConfiguration.java | 46 ++++++ ...eOAuth2ResourceServerJwkConfiguration.java | 49 ++++++ ...esourceServerWebSecurityConfiguration.java | 50 ++++++ .../resource/reactive/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 1 + ...2ResourceServerAutoConfigurationTests.java | 156 ++++++++++++++++++ .../spring-boot-dependencies/pom.xml | 2 +- .../main/asciidoc/spring-boot-features.adoc | 5 +- spring-boot-samples/README.adoc | 3 + .../pom.xml | 60 +++++++ .../oauth2/resource/ExampleController.java | 32 ++++ ...activeOAuth2ResourceServerApplication.java | 29 ++++ .../src/main/resources/application.yml | 8 + ...eOAuth2ResourceServerApplicationTests.java | 99 +++++++++++ 14 files changed, 558 insertions(+), 2 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java new file mode 100644 index 000000000000..72cfb654de12 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.reactive; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Reactive OAuth2 resource server + * support. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) +@EnableConfigurationProperties(OAuth2ResourceServerProperties.class) +@ConditionalOnClass({ EnableWebFluxSecurity.class, BearerTokenAuthenticationToken.class }) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@Import({ ReactiveOAuth2ResourceServerJwkConfiguration.class, + ReactiveOAuth2ResourceServerWebSecurityConfiguration.class }) +public class ReactiveOAuth2ResourceServerAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java new file mode 100644 index 000000000000..e9977b27c708 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; + +/** + * Configures a {@link ReactiveJwtDecoder} when a JWK Set URI is available. + * + * @author Madhura Bhave + */ +@Configuration +class ReactiveOAuth2ResourceServerJwkConfiguration { + + private final OAuth2ResourceServerProperties properties; + + ReactiveOAuth2ResourceServerJwkConfiguration( + OAuth2ResourceServerProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri") + @ConditionalOnMissingBean + public ReactiveJwtDecoder jwtDecoder() { + return new NimbusReactiveJwtDecoder( + this.properties.getJwt().getJwk().getSetUri()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java new file mode 100644 index 000000000000..c481fdeabfe3 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.security.web.server.SecurityWebFilterChain; + +/** + * Configures a {@link SecurityWebFilterChain} for Reactive OAuth2 resource server support + * if a {@link ReactiveJwtDecoder} bean is present. + * + * @author Madhura Bhave + */ +@Configuration +@ConditionalOnBean(ReactiveJwtDecoder.class) +class ReactiveOAuth2ResourceServerWebSecurityConfiguration { + + private final ReactiveJwtDecoder jwtDecoder; + + ReactiveOAuth2ResourceServerWebSecurityConfiguration(ReactiveJwtDecoder jwtDecoder) { + this.jwtDecoder = jwtDecoder; + } + + @Bean + @ConditionalOnMissingBean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange().anyExchange().authenticated().and().oauth2() + .resourceServer().jwt().jwtDecoder(this.jwtDecoder); + return http.build(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/package-info.java new file mode 100644 index 000000000000..586542b41603 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Security's Reactive OAuth2 resource server. + */ +package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index c8dd4ff1da81..023f9d6b4d2e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -106,6 +106,7 @@ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java new file mode 100644 index 000000000000..fd0095a44549 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -0,0 +1,156 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource.reactive; + +import java.util.List; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.config.BeanIds; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager; +import org.springframework.security.web.server.MatcherSecurityWebFilterChain; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.authentication.AuthenticationWebFilter; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.server.WebFilter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link ReactiveOAuth2ResourceServerAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2ResourceServerAutoConfigurationTests { + + private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(ReactiveOAuth2ResourceServerAutoConfiguration.class)) + .withUserConfiguration(TestConfig.class); + + @Test + public void autoConfigurationShouldConfigureResourceServer() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .run((context) -> { + assertThat(context.getBean(ReactiveJwtDecoder.class)) + .isInstanceOf(NimbusReactiveJwtDecoder.class); + assertFilterConfiguredWithJwtAuthenticationManager(context); + }); + } + + @Test + public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); + } + + @Test + public void jwtDecoderBeanIsConditionalOnMissingBean() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .withUserConfiguration(JwtDecoderConfig.class) + .run((this::assertFilterConfiguredWithJwtAuthenticationManager)); + } + + @Test + public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClass() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .withUserConfiguration(JwtDecoderConfig.class) + .withClassLoader( + new FilteredClassLoader(BearerTokenAuthenticationToken.class)) + .run((context) -> assertThat(context) + .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); + } + + @Test + public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + .withUserConfiguration(SecurityWebFilterChainConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(SecurityWebFilterChain.class); + assertThat(context).hasBean("testSpringSecurityFilterChain"); + }); + } + + @SuppressWarnings("unchecked") + private void assertFilterConfiguredWithJwtAuthenticationManager( + AssertableReactiveWebApplicationContext context) { + MatcherSecurityWebFilterChain filterChain = (MatcherSecurityWebFilterChain) context + .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); + List filters = (List) ReflectionTestUtils + .getField(filterChain, "filters"); + AuthenticationWebFilter webFilter = (AuthenticationWebFilter) filters.stream() + .filter((f) -> f instanceof AuthenticationWebFilter).findFirst() + .orElse(null); + ReactiveAuthenticationManager authenticationManager = (ReactiveAuthenticationManager) ReflectionTestUtils + .getField(webFilter, "authenticationManager"); + assertThat(authenticationManager) + .isInstanceOf(JwtReactiveAuthenticationManager.class); + + } + + @EnableWebFluxSecurity + static class TestConfig { + + @Bean + public MapReactiveUserDetailsService userDetailsService() { + return mock(MapReactiveUserDetailsService.class); + } + + } + + @Configuration + static class JwtDecoderConfig { + + @Bean + public ReactiveJwtDecoder decoder() { + return mock(ReactiveJwtDecoder.class); + } + + } + + @Configuration + static class SecurityWebFilterChainConfig { + + @Bean + SecurityWebFilterChain testSpringSecurityFilterChain(ServerHttpSecurity http, + ReactiveJwtDecoder decoder) { + http.authorizeExchange().pathMatchers("/message/**").hasRole("ADMIN") + .anyExchange().authenticated().and().oauth2().resourceServer().jwt() + .jwtDecoder(decoder); + return http.build(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 667bb98133fc..ad9c82f988f0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.M2 + 5.1.0.BUILD-SNAPSHOT Bean-M1 3.0.3.RELEASE 3.23.1 diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 130cedd55ebe..e5116f40e478 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3286,7 +3286,10 @@ following example: spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys ---- -Alternatively, you can define your own `JwtDecoder` bean. +The same properties are applicable for both servlet and reactive applications. + +Alternatively, you can define your own `JwtDecoder` bean for servlet applications +or a `ReactiveJwtDecoder` for reactive applications. diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc index 8a7378508c6a..95df246b2f2d 100644 --- a/spring-boot-samples/README.adoc +++ b/spring-boot-samples/README.adoc @@ -137,6 +137,9 @@ The following sample applications are provided: | link:spring-boot-sample-oauth2-resource-server[spring-boot-sample-oauth2-resource-server] | Configure an OAuth2 resource server +| link:spring-boot-sample-reactive-oauth2-resource-server[spring-boot-sample-reactive-oauth2-resource-server] +| Configure a Reactive OAuth2 resource server + | link:spring-boot-sample-parent-context[spring-boot-sample-parent-context] | Application that uses an `ApplicationContext` with a parent diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/pom.xml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/pom.xml new file mode 100644 index 000000000000..26cecedf7912 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + ${revision} + + spring-boot-sample-reactive-oauth2-resource-server + Spring Boot Sample Reactive OAuth2 Resource Server + Spring Boot Sample Reactive Resource Server + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-jose + + + org.springframework.security + spring-security-oauth2-resource-server + + + + com.squareup.okhttp3 + mockwebserver + 3.9.0 + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java new file mode 100644 index 000000000000..a5cabdd72efa --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ExampleController { + + @GetMapping("/") + public String index(@AuthenticationPrincipal Jwt jwt) { + return String.format("Hello, %s!", jwt.getSubject()); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplication.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplication.java new file mode 100644 index 000000000000..46e3db827925 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleReactiveOAuth2ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleReactiveOAuth2ResourceServerApplication.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml new file mode 100644 index 000000000000..2599bf40916c --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml @@ -0,0 +1,8 @@ +spring: + security: + oauth2: + resource: + jwt: + jwk: + # To run the application, replace this with a valid JWK Set URI + set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java new file mode 100644 index 000000000000..7660b0c793e8 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2018 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 sample.oauth2.resource; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class SampleReactiveOAuth2ResourceServerApplicationTests { + + @Autowired + private WebTestClient webTestClient; + + private static MockWebServer server = new MockWebServer(); + + private static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi" + + "LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU" + + "OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN" + + "afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql" + + "R44vmRqS5ncrF-1R0EGcPX49U6A"; + + @BeforeClass + public static void setup() throws Exception { + server.start(); + String url = server.url("/.well-known/jwks.json").toString(); + server.enqueue(mockResponse()); + System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url); + } + + @AfterClass + public static void shutdown() throws Exception { + server.shutdown(); + System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri"); + } + + @Test + public void getWhenValidTokenShouldBeOk() { + this.webTestClient.get().uri("/") + .headers(headers -> headers.setBearerAuth(VALID_TOKEN)).exchange() + .expectStatus().isOk().expectBody(String.class) + .isEqualTo("Hello, subject!"); + } + + @Test + public void getWhenNoTokenShouldBeUnauthorized() { + this.webTestClient.get().uri("/").exchange().expectStatus().isUnauthorized() + .expectHeader().valueEquals(HttpHeaders.WWW_AUTHENTICATE, "Bearer"); + } + + private static MockResponse mockResponse() { + String body = "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw" + + "DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\"" + + ",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO" + + "1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\"" + + ":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7" + + "VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0" + + "851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo" + + "3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK4" + + "8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o" + + "XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ" + + "PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8" + + "M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF" + + "k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn" + + "uYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs" + + "V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5" + + "8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq" + + "D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}"; + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .setResponseCode(200).setBody(body); + } + +} From 6512406a1300a038b8b276bddfe864d1bd5e9bac Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 7 Aug 2018 21:05:15 -0700 Subject: [PATCH 334/701] Add missing samples to pom and README --- spring-boot-samples/README.adoc | 6 ++++++ spring-boot-samples/pom.xml | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc index 95df246b2f2d..381826df8011 100644 --- a/spring-boot-samples/README.adoc +++ b/spring-boot-samples/README.adoc @@ -134,6 +134,12 @@ The following sample applications are provided: | link:spring-boot-sample-metrics-redis[spring-boot-sample-metrics-redis] | Exports metrics to Redis +| link:spring-boot-sample-oauth2-client[spring-boot-sample-oauth2-client] +| Configure an OAuth2 login client + +| link:spring-boot-sample-reactive-oauth2-client[spring-boot-sample-reactive-oauth2-client] +| Configure a Reactive OAuth2 login client + | link:spring-boot-sample-oauth2-resource-server[spring-boot-sample-oauth2-resource-server] | Configure an OAuth2 resource server diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index b78960f50b76..649f9988dc75 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -61,10 +61,13 @@ spring-boot-sample-liquibase spring-boot-sample-logback spring-boot-sample-oauth2-client - spring-boot-sample-parent-context + spring-boot-sample-oauth2-client + spring-boot-sample-oauth2-resource-server spring-boot-sample-profile spring-boot-sample-property-validation spring-boot-sample-quartz + spring-boot-sample-reactive-oauth2-client + spring-boot-sample-reactive-oauth2-resource-server spring-boot-sample-secure spring-boot-sample-secure-webflux spring-boot-sample-servlet From c69a1f208f6f041009119e60ab88c11c89d947f4 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 7 Aug 2018 23:43:58 -0700 Subject: [PATCH 335/701] Remove duplicate sample from modules --- spring-boot-samples/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 649f9988dc75..1d3351a13709 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -61,7 +61,6 @@ spring-boot-sample-liquibase spring-boot-sample-logback spring-boot-sample-oauth2-client - spring-boot-sample-oauth2-client spring-boot-sample-oauth2-resource-server spring-boot-sample-profile spring-boot-sample-property-validation From aa0739e3b76a40d9a5a2dc34c93784045103a4b0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 8 Aug 2018 10:33:34 +0200 Subject: [PATCH 336/701] Fix checkstyle rule --- .../resource/SampleOauth2ResourceServerApplicationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java index 062bf013f186..d1bc8491fcea 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java @@ -108,4 +108,4 @@ private static MockResponse mockResponse() { .setResponseCode(200).setBody(body); } -} \ No newline at end of file +} From 48d365aba4ef7c0bb319023f56cc3f9c0bae8423 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 8 Aug 2018 13:04:08 +0200 Subject: [PATCH 337/701] Fix checkstyle rule --- .../SampleReactiveOAuth2ResourceServerApplicationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java index 7660b0c793e8..ed1188f3aba3 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java @@ -62,7 +62,7 @@ public static void shutdown() throws Exception { @Test public void getWhenValidTokenShouldBeOk() { this.webTestClient.get().uri("/") - .headers(headers -> headers.setBearerAuth(VALID_TOKEN)).exchange() + .headers((headers) -> headers.setBearerAuth(VALID_TOKEN)).exchange() .expectStatus().isOk().expectBody(String.class) .isEqualTo("Hello, subject!"); } From 101cc59b7df2e22bc4fe104ea1f6944758bdae3b Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 9 Aug 2018 09:38:55 +0900 Subject: [PATCH 338/701] Polish Closes gh-14023 --- .../endpoint/jmx/DefaultEndpointObjectNameFactory.java | 8 ++++---- .../autoconfigure/flyway/FlywayAutoConfiguration.java | 4 ++-- .../boot/autoconfigure/jmx/JmxAutoConfiguration.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java index 9476b10244a1..5726a41d9a32 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java @@ -54,17 +54,17 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory { @SuppressWarnings("deprecation") private static boolean determineUniqueNames(Environment environment, JmxEndpointProperties properties) { - Boolean uniqueName = environment.getProperty("spring.jmx.unique-names", + Boolean uniqueNames = environment.getProperty("spring.jmx.unique-names", Boolean.class); Boolean endpointUniqueNames = properties.getUniqueNames(); - if (uniqueName == null) { + if (uniqueNames == null) { return (endpointUniqueNames != null) ? endpointUniqueNames : false; } - else if (endpointUniqueNames != null & !uniqueName.equals(endpointUniqueNames)) { + if (endpointUniqueNames != null & !uniqueNames.equals(endpointUniqueNames)) { throw new IllegalArgumentException( "Configuration mismatch, 'management.endpoints.jmx.unique-names' is deprecated, use only 'spring.jmx.unique-names'"); } - return uniqueName; + return uniqueNames; } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index da93e098cf0d..bd66b057a797 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -180,9 +180,9 @@ private String getProperty(Supplier property, } private void checkLocationExists(Flyway flyway) { - String[] locations = new LocationResolver(flyway.getDataSource()) - .resolveLocations(this.properties.getLocations()); if (this.properties.isCheckLocation()) { + String[] locations = new LocationResolver(flyway.getDataSource()) + .resolveLocations(this.properties.getLocations()); Assert.state(locations.length != 0, "Migration script locations not configured"); boolean exists = hasAtLeastOneLocation(locations); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java index 4bcd4ac82fd2..7ad04ac7663c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java @@ -94,9 +94,9 @@ public ParentAwareNamingStrategy objectNamingStrategy() { if (StringUtils.hasLength(defaultDomain)) { namingStrategy.setDefaultDomain(defaultDomain); } - boolean uniqueName = this.environment.getProperty("spring.jmx.unique-names", + boolean uniqueNames = this.environment.getProperty("spring.jmx.unique-names", Boolean.class, false); - namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueName); + namingStrategy.setEnsureUniqueRuntimeObjectNames(uniqueNames); return namingStrategy; } From 05a7d2130592f47893b7ce155bde004fa016af0d Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 9 Aug 2018 12:54:20 +0900 Subject: [PATCH 339/701] Polish ItemMetadata.buildName() Closes gh-14024 --- .../metadata/ItemMetadata.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadata.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadata.java index 88eb70334a17..8871d60b9da7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadata.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadata.java @@ -58,14 +58,17 @@ public final class ItemMetadata implements Comparable { } private String buildName(String prefix, String name) { - while (prefix != null && prefix.endsWith(".")) { - prefix = prefix.substring(0, prefix.length() - 1); - } - StringBuilder fullName = new StringBuilder((prefix != null) ? prefix : ""); - if (fullName.length() > 0 && name != null) { - fullName.append('.'); + StringBuilder fullName = new StringBuilder(); + if (prefix != null) { + if (prefix.endsWith(".")) { + prefix = prefix.substring(0, prefix.length() - 1); + } + fullName.append(prefix); } if (name != null) { + if (fullName.length() > 0) { + fullName.append('.'); + } fullName.append(ConfigurationMetadata.toDashedCase(name)); } return fullName.toString(); From b90113ac3332e8435d1cf14c486b6af6099ddfea Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 9 Aug 2018 15:34:06 +0900 Subject: [PATCH 340/701] Align server.tomcat.max-swallow-size with Tomcat's default value Closes gh-14025 --- .../boot/autoconfigure/web/ServerProperties.java | 2 +- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 68bc334d47fc..c872465e4705 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -332,7 +332,7 @@ public static class Tomcat { /** * Maximum amount of request body bytes to swallow. */ - private int maxSwallowSize = 4096; + private int maxSwallowSize = 2097152; /** * Whether requests to the context root should be redirected by appending a / to diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 53e2dc76f4e8..bfa76439a635 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -260,7 +260,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time. server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content. - server.tomcat.max-swallow-size=4096 # Maximum amount of request body bytes to swallow. + server.tomcat.max-swallow-size=2097152 # Maximum amount of request body bytes to swallow. server.tomcat.max-threads=0 # Maximum number of worker threads. server.tomcat.min-spare-threads=0 # Minimum number of worker threads. server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value. From 295995829f41fae715b7a2f2195e4d14f2f96b6d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 9 Aug 2018 13:33:03 +0200 Subject: [PATCH 341/701] Remove outdated Java10 profile --- spring-boot-project/spring-boot-parent/pom.xml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index ef998b85768d..87f934060f57 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -737,16 +737,5 @@ - - java10 - - 10 - - - 2.21.0 - 3.7 - 2.21.0 - - From 0ca8f1083a4a7cfb2b604f4c483b69eb01773a5f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 09:48:22 +0200 Subject: [PATCH 342/701] Fix ClassCastException message detection on Java 11 This commit also fixes the detection of a ClassCastException that can be safely ignored on the module path with Java 9 Closes gh-14033 --- .../org/springframework/boot/util/LambdaSafe.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java index d8476c2f9ba1..78267f85525f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java @@ -188,9 +188,22 @@ private boolean startsWithArgumentClassName(String message, Object argument) { return false; } Class argumentType = argument.getClass(); + // On Java 8, the message starts with the class name: "java.lang.String cannot + // be cast..." if (message.startsWith(argumentType.getName())) { return true; } + // On Java 11, the message starts with "class ..." a.k.a. Class.toString() + if (message.startsWith(argumentType.toString())) { + return true; + } + // On Java 9, the message used to contain the module name: + // "java.base/java.lang.String cannot be cast..." + int moduleSeparatorIndex = message.indexOf('/'); + if (moduleSeparatorIndex != -1 && message.startsWith(argumentType.getName(), + moduleSeparatorIndex + 1)) { + return true; + } if (CLASS_GET_MODULE != null) { Object module = ReflectionUtils.invokeMethod(CLASS_GET_MODULE, argumentType); From 817a8a830278715a93f8f2455bf0efc64342eb41 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 09:48:57 +0200 Subject: [PATCH 343/701] Polish --- .../main/java/org/springframework/boot/util/LambdaSafe.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java index 78267f85525f..018153a77dd5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java @@ -187,7 +187,7 @@ private boolean startsWithArgumentClassName(String message, Object argument) { if (argument == null) { return false; } - Class argumentType = argument.getClass(); + Class argumentType = argument.getClass(); // On Java 8, the message starts with the class name: "java.lang.String cannot // be cast..." if (message.startsWith(argumentType.getName())) { @@ -208,9 +208,7 @@ private boolean startsWithArgumentClassName(String message, Object argument) { Object module = ReflectionUtils.invokeMethod(CLASS_GET_MODULE, argumentType); Object moduleName = ReflectionUtils.invokeMethod(MODULE_GET_NAME, module); - if (message.startsWith(moduleName + "/" + argumentType.getName())) { - return true; - } + return message.startsWith(moduleName + "/" + argumentType.getName()); } return false; } From ca8bdc8a72728198eb7eaf11a66556fbf2756fbf Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 09:53:10 +0200 Subject: [PATCH 344/701] Resume building against Spring Framework snapshots See gh-14038 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index ad9c82f988f0..429c4a7f94c5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -153,7 +153,7 @@ 1.7.25 1.21 7.4.0 - 5.1.0.RC1 + 5.1.0.BUILD-SNAPSHOT 2.1.0.M1 4.1.0.M2 2.0.2.RELEASE From 9d40df9a2a610b340f5d84627a699a6c920ed54e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 09:55:09 +0200 Subject: [PATCH 345/701] Upgrade to Mockito 2.21.0 Closes gh-14039 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 429c4a7f94c5..c14e948e9fb5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -124,7 +124,7 @@ 1.18.0 2.2.6 1.0.6 - 2.19.1 + 2.21.0 1.9.0 3.8.0 6.4.0.jre8 From 0d04d7adf81845d487f5b5624712b4af5b6071ae Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 12:52:14 +0200 Subject: [PATCH 346/701] Migrate @EventListener to ApplicationListener Closes gh-14041 --- .../LocalDevToolsAutoConfiguration.java | 47 ++++++++++++++----- .../client/RemoteClientConfiguration.java | 9 ++-- ...SpringApplicationAdminMXBeanRegistrar.java | 46 +++++++++++++++--- 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index 4f6f1f915c3d..6ae982153a01 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -35,10 +35,14 @@ import org.springframework.boot.devtools.restart.ConditionalOnInitializedRestarter; import org.springframework.boot.devtools.restart.RestartScope; import org.springframework.boot.devtools.restart.Restarter; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; +import org.springframework.context.event.GenericApplicationListener; +import org.springframework.core.ResolvableType; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -94,7 +98,8 @@ public LiveReloadServerEventListener liveReloadServerEventListener( */ @Configuration @ConditionalOnProperty(prefix = "spring.devtools.restart", name = "enabled", matchIfMissing = true) - static class RestartConfiguration { + static class RestartConfiguration + implements ApplicationListener { private final DevToolsProperties properties; @@ -102,8 +107,8 @@ static class RestartConfiguration { this.properties = properties; } - @EventListener - public void onClassPathChanged(ClassPathChangedEvent event) { + @Override + public void onApplicationEvent(ClassPathChangedEvent event) { if (event.isRestartRequired()) { Restarter.getInstance().restart( new FileWatchingFailureHandler(fileSystemWatcherFactory())); @@ -161,7 +166,7 @@ private FileSystemWatcher newFileSystemWatcher() { } - static class LiveReloadServerEventListener { + static class LiveReloadServerEventListener implements GenericApplicationListener { private final OptionalLiveReloadServer liveReloadServer; @@ -169,16 +174,36 @@ static class LiveReloadServerEventListener { this.liveReloadServer = liveReloadServer; } - @EventListener - public void onContextRefreshed(ContextRefreshedEvent event) { - this.liveReloadServer.triggerReload(); + @Override + public boolean supportsEventType(ResolvableType eventType) { + Class type = eventType.getRawClass(); + if (type == null) { + return false; + } + return ContextRefreshedEvent.class.isAssignableFrom(type) + || ClassPathChangedEvent.class.isAssignableFrom(type); + } + + @Override + public boolean supportsSourceType(@Nullable Class sourceType) { + return true; } - @EventListener - public void onClassPathChanged(ClassPathChangedEvent event) { - if (!event.isRestartRequired()) { + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ContextRefreshedEvent) { this.liveReloadServer.triggerReload(); } + if (event instanceof ClassPathChangedEvent) { + if (!((ClassPathChangedEvent) event).isRestartRequired()) { + this.liveReloadServer.triggerReload(); + } + } + } + + @Override + public int getOrder() { + return 0; } } diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java index ada9daf3ca2b..4e1acd6a5dfb 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java @@ -49,9 +49,9 @@ import org.springframework.boot.devtools.restart.DefaultRestartInitializer; import org.springframework.boot.devtools.restart.RestartScope; import org.springframework.boot.devtools.restart.Restarter; +import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.EventListener; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; @@ -131,7 +131,8 @@ private void logWarnings() { */ @Configuration @ConditionalOnProperty(prefix = "spring.devtools.livereload", name = "enabled", matchIfMissing = true) - static class LiveReloadConfiguration { + static class LiveReloadConfiguration + implements ApplicationListener { @Autowired private DevToolsProperties properties; @@ -155,8 +156,8 @@ public LiveReloadServer liveReloadServer() { Restarter.getInstance().getThreadFactory()); } - @EventListener - public void onClassPathChanged(ClassPathChangedEvent event) { + @Override + public void onApplicationEvent(ClassPathChangedEvent event) { String url = this.remoteUrl + this.properties.getRemote().getContextPath(); this.executor.execute(new DelayedLiveReloadTrigger(optionalLiveReloadServer(), this.clientHttpRequestFactory, url)); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java index 98c04a0d70da..732b454ba4a3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,11 +32,15 @@ import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.EnvironmentAware; -import org.springframework.context.event.EventListener; +import org.springframework.context.event.GenericApplicationListener; +import org.springframework.core.Ordered; +import org.springframework.core.ResolvableType; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -48,7 +52,7 @@ * @since 1.3.0 */ public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContextAware, - EnvironmentAware, InitializingBean, DisposableBean { + GenericApplicationListener, EnvironmentAware, InitializingBean, DisposableBean { private static final Log logger = LogFactory.getLog(SpringApplicationAdmin.class); @@ -80,15 +84,43 @@ public void setEnvironment(Environment environment) { this.environment = environment; } - @EventListener - public void onApplicationReadyEvent(ApplicationReadyEvent event) { + @Override + public boolean supportsEventType(ResolvableType eventType) { + Class type = eventType.getRawClass(); + if (type == null) { + return false; + } + return ApplicationReadyEvent.class.isAssignableFrom(type) + || WebServerInitializedEvent.class.isAssignableFrom(type); + } + + @Override + public boolean supportsSourceType(@Nullable Class sourceType) { + return true; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ApplicationReadyEvent) { + onApplicationReadyEvent((ApplicationReadyEvent) event); + } + if (event instanceof WebServerInitializedEvent) { + onWebServerInitializedEvent((WebServerInitializedEvent) event); + } + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + void onApplicationReadyEvent(ApplicationReadyEvent event) { if (this.applicationContext.equals(event.getApplicationContext())) { this.ready = true; } } - @EventListener - public void onWebServerInitializedEvent(WebServerInitializedEvent event) { + void onWebServerInitializedEvent(WebServerInitializedEvent event) { if (this.applicationContext.equals(event.getApplicationContext())) { this.embeddedWebApplication = true; } From bfd616ac7a461f0fb37edfa2891ee9ac024cdb03 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 13:46:39 +0200 Subject: [PATCH 347/701] Prevent JavaFX to be added to the classpath with Java 11 See https://hibernate.atlassian.net/browse/HV-1644 --- spring-boot-project/spring-boot-dependencies/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c14e948e9fb5..03bb598a39a2 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1919,6 +1919,13 @@ org.hibernate.validator hibernate-validator ${hibernate-validator.version} + + + + org.openjfx + javafx.base + + org.hibernate.validator From c9bdc989358d464bf9cfadc2d46eed06d406c4e4 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Fri, 10 Aug 2018 18:00:58 +0200 Subject: [PATCH 348/701] Add missing @Override Closes gh-14043 --- .../servlet/OAuth2ResourceServerWebSecurityConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java index 60ec434c1eac..14e51b04d2ba 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java @@ -35,6 +35,7 @@ class OAuth2ResourceServerWebSecurityConfiguration { @ConditionalOnBean(JwtDecoder.class) static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().oauth2() .resourceServer().jwt(); From 94013aaba62c7674b2a5d01b7f65ccd93ec79483 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Aug 2018 14:58:11 +0200 Subject: [PATCH 349/701] Add support for DataSize This commit adds support for Spring Framework's `DataSize` allowing to express a size in bytes and other convenient units. Similar to the `Duration` support introduced previously, this commit adds transparent binding support as well as detection of default values in `@ConfigurationProperties`-annotated object. Closes gh-13974 --- .../main/asciidoc/spring-boot-features.adoc | 39 ++++++ .../properties/bind/AppIoProperties.java | 55 ++++++++ .../javac/JavaCompilerFieldValuesParser.java | 37 ++++- .../AbstractFieldValuesProcessorTests.java | 8 +- .../fieldvalues/FieldValues.java | 15 +- .../convert/ApplicationConversionService.java | 1 + .../boot/convert/DataSizeUnit.java | 46 +++++++ .../convert/StringToDataSizeConverter.java | 61 +++++++++ .../ConfigurationPropertiesTests.java | 38 ++++++ .../convert/MockDataSizeTypeDescriptor.java | 53 +++++++ .../StringToDataSizeConverterTests.java | 129 ++++++++++++++++++ 11 files changed, 476 insertions(+), 6 deletions(-) create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/DataSizeUnit.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToDataSizeConverter.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1e225ca07dab..8d39881548d5 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1308,6 +1308,45 @@ while supporting a much richer format. +[[boot-features-external-config-conversion-datasize]] +===== Converting Data Sizes +Spring Framework has a `DataSize` value type that allows to express size in bytes. If you +expose a `DataSize` property, the following formats in application properties are +available: + +* A regular `long` representation (using bytes as the default unit unless a +`@DataSizeUnit` has been specified) +* A more readable format where the value and the unit are coupled (e.g. `10MB` means 10 +megabytes) + +Consider the following example: + +[source,java,indent=0] +---- +include::{code-examples}/context/properties/bind/AppIoProperties.java[tag=example] +---- + +To specify a buffer size of 10 megabytes, `10` and `10MB` are equivalent. A size threshold +of 256 bytes can be specified as `256` or `256B`. + +You can also use any of the supported unit. These are: + +* `B` for bytes +* `KB` for kilobytes +* `MB` for megabytes +* `GB` for gigabytes +* `TB` for terabytes + +The default unit is bytes and can be overridden using `@DataSizeUnit` as illustrated +in the sample above. + +TIP: If you are upgrading from a previous version that is simply using `Long` to express +the size, make sure to define the unit (using `@DataSizeUnit`) if it isn't bytes alongside +the switch to `DataSize`. Doing so gives a transparent upgrade path while supporting a +much richer format. + + + [[boot-features-external-config-validation]] ==== @ConfigurationProperties Validation Spring Boot attempts to validate `@ConfigurationProperties` classes whenever they are diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java new file mode 100644 index 000000000000..3b7f3fec228a --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.docs.context.properties.bind; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.convert.DataSizeUnit; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +/** + * A {@link ConfigurationProperties} example that uses {@link DataSize}. + * + * @author Stephane Nicoll + */ +// tag::example[] +@ConfigurationProperties("app.io") +public class AppIoProperties { + + @DataSizeUnit(DataUnit.MEGABYTES) + private DataSize bufferSize = DataSize.ofMegaBytes(2); + + private DataSize sizeThreshold = DataSize.ofBytes(512); + + public DataSize getBufferSize() { + return this.bufferSize; + } + + public void setBufferSize(DataSize bufferSize) { + this.bufferSize = bufferSize; + } + + public DataSize getSizeThreshold() { + return this.sizeThreshold; + } + + public void setSizeThreshold(DataSize sizeThreshold) { + this.sizeThreshold = sizeThreshold; + } + +} +// end::example[] diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java index a56ce83b5c59..bb0a061ba903 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java @@ -116,6 +116,20 @@ private static class FieldCollector implements TreeVisitor { DURATION_SUFFIX = Collections.unmodifiableMap(values); } + private static final String DATA_SIZE_OF = "DataSize.of"; + + private static final Map DATA_SIZE_SUFFIX; + + static { + Map values = new HashMap<>(); + values.put("Bytes", "B"); + values.put("KiloBytes", "KB"); + values.put("MegaBytes", "MB"); + values.put("GigaBytes", "GB"); + values.put("TeraBytes", "TB"); + DATA_SIZE_SUFFIX = Collections.unmodifiableMap(values); + } + private final Map fieldValues = new HashMap<>(); private final Map staticFinals = new HashMap<>(); @@ -173,14 +187,29 @@ private Object getValue(ExpressionTree expression, Object defaultValue) } private Object getFactoryValue(ExpressionTree expression, Object factoryValue) { + Object durationValue = getFactoryValue(expression, factoryValue, DURATION_OF, + DURATION_SUFFIX); + if (durationValue != null) { + return durationValue; + } + Object dataSizeValue = getFactoryValue(expression, factoryValue, DATA_SIZE_OF, + DATA_SIZE_SUFFIX); + if (dataSizeValue != null) { + return dataSizeValue; + } + return factoryValue; + } + + private Object getFactoryValue(ExpressionTree expression, Object factoryValue, + String prefix, Map suffixMapping) { Object instance = expression.getInstance(); - if (instance != null && instance.toString().startsWith(DURATION_OF)) { + if (instance != null && instance.toString().startsWith(prefix)) { String type = instance.toString(); - type = type.substring(DURATION_OF.length(), type.indexOf('(')); - String suffix = DURATION_SUFFIX.get(type); + type = type.substring(prefix.length(), type.indexOf('(')); + String suffix = suffixMapping.get(type); return (suffix != null) ? factoryValue + suffix : null; } - return factoryValue; + return null; } public Map getFieldValues() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java index 02e66206c43a..3031a93f5c70 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -95,6 +95,12 @@ public void getFieldValues() throws Exception { assertThat(values.get("durationMinutes")).isEqualTo("30m"); assertThat(values.get("durationHours")).isEqualTo("40h"); assertThat(values.get("durationDays")).isEqualTo("50d"); + assertThat(values.get("dataSizeNone")).isNull(); + assertThat(values.get("dataSizeBytes")).isEqualTo("5B"); + assertThat(values.get("dataSizeKiloBytes")).isEqualTo("10KB"); + assertThat(values.get("dataSizeMegaBytes")).isEqualTo("20MB"); + assertThat(values.get("dataSizeGigaBytes")).isEqualTo("30GB"); + assertThat(values.get("dataSizeTeraBytes")).isEqualTo("40TB"); } @SupportedAnnotationTypes({ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java index 94d46e1d8032..493bc7185f8b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -22,6 +22,7 @@ import org.springframework.boot.configurationsample.ConfigurationProperties; import org.springframework.util.MimeType; +import org.springframework.util.unit.DataSize; /** * Sample object containing fields with initial values. @@ -123,4 +124,16 @@ public class FieldValues { private Duration durationDays = Duration.ofDays(50); + private DataSize dataSizeNone; + + private DataSize dataSizeBytes = DataSize.ofBytes(5); + + private DataSize dataSizeKiloBytes = DataSize.ofKiloBytes(10); + + private DataSize dataSizeMegaBytes = DataSize.ofMegaBytes(20); + + private DataSize dataSizeGigaBytes = DataSize.ofGigaBytes(30); + + private DataSize dataSizeTeraBytes = DataSize.ofTeraBytes(40); + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java index a5470427d90b..89b18c956a34 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java @@ -99,6 +99,7 @@ public static void addApplicationConverters(ConverterRegistry registry) { registry.addConverter(new DurationToStringConverter()); registry.addConverter(new NumberToDurationConverter()); registry.addConverter(new DurationToNumberConverter()); + registry.addConverter(new StringToDataSizeConverter()); registry.addConverterFactory(new StringToEnumIgnoringCaseConverterFactory()); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/DataSizeUnit.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/DataSizeUnit.java new file mode 100644 index 000000000000..e4cb225fe3f5 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/DataSizeUnit.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2018 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.convert; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +/** + * Annotation that can be used to change the default unit used when converting a + * {@link DataSize}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataSizeUnit { + + /** + * The {@link DataUnit} to use if one is not specified. + * @return the data unit + */ + DataUnit value(); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToDataSizeConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToDataSizeConverter.java new file mode 100644 index 000000000000..3198fd2b5d9b --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/StringToDataSizeConverter.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2018 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.convert; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.util.ObjectUtils; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +/** + * {@link Converter} to convert from a {@link String} to a {@link DataSize}. Supports + * {@link DataSize#parse(CharSequence)}. + * + * @author Stephane Nicoll + * @see DataSizeUnit + */ +final class StringToDataSizeConverter implements GenericConverter { + + @Override + public Set getConvertibleTypes() { + return Collections.singleton(new ConvertiblePair(String.class, DataSize.class)); + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, + TypeDescriptor targetType) { + if (ObjectUtils.isEmpty(source)) { + return null; + } + return convert(source.toString(), getDataUnit(targetType)); + } + + private DataUnit getDataUnit(TypeDescriptor targetType) { + DataSizeUnit annotation = targetType.getAnnotation(DataSizeUnit.class); + return (annotation != null) ? annotation.value() : null; + } + + private DataSize convert(String source, DataUnit unit) { + return DataSize.parse(source, unit); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java index dab87db0f916..7ea030a1a3db 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java @@ -49,6 +49,7 @@ import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.boot.context.properties.bind.BindException; import org.springframework.boot.context.properties.bind.validation.BindValidationException; +import org.springframework.boot.convert.DataSizeUnit; import org.springframework.boot.testsupport.rule.OutputCapture; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -72,6 +73,8 @@ import org.springframework.stereotype.Component; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.util.StringUtils; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; @@ -767,6 +770,14 @@ public void loadWhenBindingCurrentDirectoryToFileShouldBind() { assertThat(bean.getFile()).isEqualTo(new File(".")); } + @Test + public void loadWhenBindingToDataSizeShouldBind() { + load(DataSizeProperties.class, "test.size=10GB", "test.another-size=5"); + DataSizeProperties bean = this.context.getBean(DataSizeProperties.class); + assertThat(bean.getSize()).isEqualTo(DataSize.ofGigaBytes(10)); + assertThat(bean.getAnotherSize()).isEqualTo(DataSize.ofKiloBytes(5)); + } + @Test public void loadWhenTopLevelConverterNotFoundExceptionShouldNotFail() { load(PersonProperties.class, "test=boot"); @@ -1692,6 +1703,33 @@ public void setFile(File file) { } + @EnableConfigurationProperties + @ConfigurationProperties(prefix = "test") + static class DataSizeProperties { + + private DataSize size; + + @DataSizeUnit(DataUnit.KILOBYTES) + private DataSize anotherSize; + + public DataSize getSize() { + return this.size; + } + + public void setSize(DataSize size) { + this.size = size; + } + + public DataSize getAnotherSize() { + return this.anotherSize; + } + + public void setAnotherSize(DataSize anotherSize) { + this.anotherSize = anotherSize; + } + + } + static class CustomPropertiesValidator implements Validator { @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java new file mode 100644 index 000000000000..97c64a56378c --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2018 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.convert; + +import java.util.Collections; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Create a mock {@link TypeDescriptor} with optional {@link DataUnit} annotation. + * + * @author Stephane Nicoll + */ +public final class MockDataSizeTypeDescriptor { + + private MockDataSizeTypeDescriptor() { + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static TypeDescriptor get(DataUnit unit) { + TypeDescriptor descriptor = mock(TypeDescriptor.class); + if (unit != null) { + DataSizeUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation( + Collections.singletonMap("value", unit), DataSizeUnit.class, null); + given(descriptor.getAnnotation(DataSizeUnit.class)) + .willReturn(unitAnnotation); + } + given(descriptor.getType()).willReturn((Class) DataSize.class); + given(descriptor.getObjectType()).willReturn((Class) DataSize.class); + return descriptor; + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java new file mode 100644 index 000000000000..a97bc4604aa7 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2018 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.convert; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link StringToDataSizeConverter}. + * + * @author Stephane Nicoll + */ +@RunWith(Parameterized.class) +public class StringToDataSizeConverterTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private final ConversionService conversionService; + + public StringToDataSizeConverterTests(String name, + ConversionService conversionService) { + this.conversionService = conversionService; + } + + @Test + public void convertWhenSimpleBytesShouldReturnDataSize() { + assertThat(convert("10B")).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert("+10B")).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert("-10B")).isEqualTo(DataSize.ofBytes(-10)); + } + + @Test + public void convertWhenSimpleKiloBytesShouldReturnDataSize() { + assertThat(convert("10KB")).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert("+10KB")).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert("-10KB")).isEqualTo(DataSize.ofKiloBytes(-10)); + } + + @Test + public void convertWhenSimpleMegaBytesShouldReturnDataSize() { + assertThat(convert("10MB")).isEqualTo(DataSize.ofMegaBytes(10)); + assertThat(convert("+10MB")).isEqualTo(DataSize.ofMegaBytes(10)); + assertThat(convert("-10MB")).isEqualTo(DataSize.ofMegaBytes(-10)); + } + + @Test + public void convertWhenSimpleGigaBytesShouldReturnDataSize() { + assertThat(convert("10GB")).isEqualTo(DataSize.ofGigaBytes(10)); + assertThat(convert("+10GB")).isEqualTo(DataSize.ofGigaBytes(10)); + assertThat(convert("-10GB")).isEqualTo(DataSize.ofGigaBytes(-10)); + } + + @Test + public void convertWhenSimpleTeraBytesShouldReturnDataSize() { + assertThat(convert("10TB")).isEqualTo(DataSize.ofTeraBytes(10)); + assertThat(convert("+10TB")).isEqualTo(DataSize.ofTeraBytes(10)); + assertThat(convert("-10TB")).isEqualTo(DataSize.ofTeraBytes(-10)); + } + + @Test + public void convertWhenSimpleWithoutSuffixShouldReturnDataSize() { + assertThat(convert("10")).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert("+10")).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert("-10")).isEqualTo(DataSize.ofBytes(-10)); + } + + @Test + public void convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize() { + assertThat(convert("10", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert("+10", DataUnit.KILOBYTES)) + .isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert("-10", DataUnit.KILOBYTES)) + .isEqualTo(DataSize.ofKiloBytes(-10)); + } + + @Test + public void convertWhenBadFormatShouldThrowException() { + this.thrown.expect(ConversionFailedException.class); + this.thrown.expectMessage("'10WB' is not a valid data size"); + convert("10WB"); + } + + @Test + public void convertWhenEmptyShouldReturnNull() { + assertThat(convert("")).isNull(); + } + + private DataSize convert(String source) { + return this.conversionService.convert(source, DataSize.class); + } + + private DataSize convert(String source, DataUnit unit) { + return (DataSize) this.conversionService.convert(source, + TypeDescriptor.forObject(source), MockDataSizeTypeDescriptor.get(unit)); + } + + @Parameters(name = "{0}") + public static Iterable conversionServices() { + return new ConversionServiceParameters(new StringToDataSizeConverter()); + } + +} From 6734e1122201ba7bf8698a73c7fec3f9e0f9a834 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 12 Aug 2018 09:31:08 +0200 Subject: [PATCH 350/701] Adapt MultipartConfig to use DataSize support See gh-13974 --- .../web/servlet/MultipartProperties.java | 56 +++++----- ...spatcherServletAutoConfigurationTests.java | 5 +- .../appendix-application-properties.adoc | 6 +- .../web/servlet/MultipartConfigFactory.java | 104 +++++++++++------- .../servlet/MultipartConfigFactoryTests.java | 35 +++++- 5 files changed, 130 insertions(+), 76 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java index e7b1649249e4..8331ff0bf662 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +19,11 @@ import javax.servlet.MultipartConfigElement; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.boot.convert.DataSizeUnit; import org.springframework.boot.web.servlet.MultipartConfigFactory; -import org.springframework.util.StringUtils; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; /** * Properties to be used in configuring a {@link MultipartConfigElement}. @@ -37,10 +40,11 @@ *

* These properties are ultimately passed to {@link MultipartConfigFactory} which means * you may specify numeric values using {@literal long} values or using more readable - * {@literal String} variants that accept {@literal KB} or {@literal MB} suffixes. + * {@link DataSize} variants. * * @author Josh Long * @author Toshiaki Maki + * @author Stephane Nicoll * @since 1.1.0 */ @ConfigurationProperties(prefix = "spring.servlet.multipart", ignoreUnknownFields = false) @@ -57,22 +61,21 @@ public class MultipartProperties { private String location; /** - * Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or - * kilobytes, respectively. + * Max file size. */ - private String maxFileSize = "1MB"; + @DataSizeUnit(DataUnit.MEGABYTES) + private DataSize maxFileSize = DataSize.ofMegaBytes(1); /** - * Max request size. Values can use the suffixes "MB" or "KB" to indicate megabytes or - * kilobytes, respectively. + * Max request size. */ - private String maxRequestSize = "10MB"; + @DataSizeUnit(DataUnit.MEGABYTES) + private DataSize maxRequestSize = DataSize.ofMegaBytes(10); /** - * Threshold after which files are written to disk. Values can use the suffixes "MB" - * or "KB" to indicate megabytes or kilobytes, respectively. + * Threshold after which files are written to disk. */ - private String fileSizeThreshold = "0"; + private DataSize fileSizeThreshold = DataSize.ofBytes(0); /** * Whether to resolve the multipart request lazily at the time of file or parameter @@ -96,27 +99,27 @@ public void setLocation(String location) { this.location = location; } - public String getMaxFileSize() { + public DataSize getMaxFileSize() { return this.maxFileSize; } - public void setMaxFileSize(String maxFileSize) { + public void setMaxFileSize(DataSize maxFileSize) { this.maxFileSize = maxFileSize; } - public String getMaxRequestSize() { + public DataSize getMaxRequestSize() { return this.maxRequestSize; } - public void setMaxRequestSize(String maxRequestSize) { + public void setMaxRequestSize(DataSize maxRequestSize) { this.maxRequestSize = maxRequestSize; } - public String getFileSizeThreshold() { + public DataSize getFileSizeThreshold() { return this.fileSizeThreshold; } - public void setFileSizeThreshold(String fileSizeThreshold) { + public void setFileSizeThreshold(DataSize fileSizeThreshold) { this.fileSizeThreshold = fileSizeThreshold; } @@ -134,18 +137,11 @@ public void setResolveLazily(boolean resolveLazily) { */ public MultipartConfigElement createMultipartConfig() { MultipartConfigFactory factory = new MultipartConfigFactory(); - if (StringUtils.hasText(this.fileSizeThreshold)) { - factory.setFileSizeThreshold(this.fileSizeThreshold); - } - if (StringUtils.hasText(this.location)) { - factory.setLocation(this.location); - } - if (StringUtils.hasText(this.maxRequestSize)) { - factory.setMaxRequestSize(this.maxRequestSize); - } - if (StringUtils.hasText(this.maxFileSize)) { - factory.setMaxFileSize(this.maxFileSize); - } + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(() -> this.fileSizeThreshold).to(factory::setFileSizeThreshold); + map.from(() -> this.location).whenHasText().to(factory::setLocation); + map.from(() -> this.maxRequestSize).to(factory::setMaxRequestSize); + map.from(() -> this.maxFileSize).to(factory::setMaxFileSize); return factory.createMultipartConfig(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java index 9ad1d122031e..a36a5c9ed676 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java @@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.util.unit.DataSize; import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartResolver; @@ -210,8 +211,8 @@ protected static class MultipartConfiguration { @Bean public MultipartConfigElement multipartConfig() { MultipartConfigFactory factory = new MultipartConfigFactory(); - factory.setMaxFileSize("128KB"); - factory.setMaxRequestSize("128KB"); + factory.setMaxFileSize(DataSize.ofKiloBytes(128)); + factory.setMaxRequestSize(DataSize.ofKiloBytes(128)); return factory.createMultipartConfig(); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index bfa76439a635..e19e1b98239f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -338,10 +338,10 @@ content into your application. Rather, pick only the properties that you need. # MULTIPART ({sc-spring-boot-autoconfigure}/web/servlet/MultipartProperties.{sc-ext}[MultipartProperties]) spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads. - spring.servlet.multipart.file-size-threshold=0 # Threshold after which files are written to disk. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively. + spring.servlet.multipart.file-size-threshold=0 # Threshold after which files are written to disk. spring.servlet.multipart.location= # Intermediate location of uploaded files. - spring.servlet.multipart.max-file-size=1MB # Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively. - spring.servlet.multipart.max-request-size=10MB # Max request size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively. + spring.servlet.multipart.max-file-size=1MB # Max file size. + spring.servlet.multipart.max-request-size=10MB # Max request size. spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access. # JACKSON ({sc-spring-boot-autoconfigure}/jackson/JacksonProperties.{sc-ext}[JacksonProperties]) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/MultipartConfigFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/MultipartConfigFactory.java index 28476c0734ea..d9adc2576456 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/MultipartConfigFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/MultipartConfigFactory.java @@ -16,21 +16,14 @@ package org.springframework.boot.web.servlet; -import java.util.Locale; - import javax.servlet.MultipartConfigElement; -import org.springframework.util.Assert; +import org.springframework.util.unit.DataSize; /** * Factory that can be used to create a {@link MultipartConfigElement}. Size values can be * set using traditional {@literal long} values which are set in bytes or using more - * readable {@literal String} variants that accept KB or MB suffixes, for example: - * - *

- * factory.setMaxFileSize("10MB");
- * factory.setMaxRequestSize("100KB");
- * 
+ * convenient {@link DataSize} variants. * * @author Phillip Webb * @since 1.4.0 @@ -39,11 +32,11 @@ public class MultipartConfigFactory { private String location; - private long maxFileSize = -1; + private DataSize maxFileSize; - private long maxRequestSize = -1; + private DataSize maxRequestSize; - private int fileSizeThreshold = 0; + private DataSize fileSizeThreshold; /** * Sets the directory location where files will be stored. @@ -53,73 +46,91 @@ public void setLocation(String location) { this.location = location; } + /** + * Sets the maximum {@link DataSize size} allowed for uploaded files. + * @param maxFileSize the maximum file size + */ + public void setMaxFileSize(DataSize maxFileSize) { + this.maxFileSize = maxFileSize; + } + /** * Sets the maximum size in bytes allowed for uploaded files. * @param maxFileSize the maximum file size - * @see #setMaxFileSize(String) + * @deprecated since 2.1.0 in favour of {@link #setMaxFileSize(DataSize)} */ + @Deprecated public void setMaxFileSize(long maxFileSize) { - this.maxFileSize = maxFileSize; + setMaxFileSize(DataSize.ofBytes(maxFileSize)); } /** * Sets the maximum size allowed for uploaded files. Values can use the suffixed "MB" * or "KB" to indicate a Megabyte or Kilobyte size. * @param maxFileSize the maximum file size - * @see #setMaxFileSize(long) + * @deprecated since 2.1.0 in favour of {@link #setMaxFileSize(DataSize)} */ + @Deprecated public void setMaxFileSize(String maxFileSize) { - this.maxFileSize = parseSize(maxFileSize); + setMaxFileSize(DataSize.parse(maxFileSize)); + } + + /** + * Sets the maximum {@link DataSize} allowed for multipart/form-data requests. + * @param maxRequestSize the maximum request size + */ + public void setMaxRequestSize(DataSize maxRequestSize) { + this.maxRequestSize = maxRequestSize; } /** * Sets the maximum size allowed in bytes for multipart/form-data requests. * @param maxRequestSize the maximum request size - * @see #setMaxRequestSize(String) + * @deprecated since 2.1.0 in favour of {@link #setMaxRequestSize(DataSize)} */ + @Deprecated public void setMaxRequestSize(long maxRequestSize) { - this.maxRequestSize = maxRequestSize; + setMaxRequestSize(DataSize.ofBytes(maxRequestSize)); } /** * Sets the maximum size allowed for multipart/form-data requests. Values can use the * suffixed "MB" or "KB" to indicate a Megabyte or Kilobyte size. * @param maxRequestSize the maximum request size - * @see #setMaxRequestSize(long) + * @deprecated since 2.1.0 in favour of {@link #setMaxRequestSize(DataSize)} */ + @Deprecated public void setMaxRequestSize(String maxRequestSize) { - this.maxRequestSize = parseSize(maxRequestSize); + setMaxRequestSize(DataSize.parse(maxRequestSize)); + } + + /** + * Sets the {@link DataSize size} threshold after which files will be written to disk. + * @param fileSizeThreshold the file size threshold + */ + public void setFileSizeThreshold(DataSize fileSizeThreshold) { + this.fileSizeThreshold = fileSizeThreshold; } /** * Sets the size threshold in bytes after which files will be written to disk. * @param fileSizeThreshold the file size threshold - * @see #setFileSizeThreshold(String) + * @deprecated since 2.1.0 in favour of {@link #setFileSizeThreshold(DataSize)} */ + @Deprecated public void setFileSizeThreshold(int fileSizeThreshold) { - this.fileSizeThreshold = fileSizeThreshold; + setFileSizeThreshold(DataSize.ofBytes(fileSizeThreshold)); } /** * Sets the size threshold after which files will be written to disk. Values can use * the suffixed "MB" or "KB" to indicate a Megabyte or Kilobyte size. * @param fileSizeThreshold the file size threshold - * @see #setFileSizeThreshold(int) + * @deprecated since 2.1.0 in favour of {@link #setFileSizeThreshold(DataSize)} */ + @Deprecated public void setFileSizeThreshold(String fileSizeThreshold) { - this.fileSizeThreshold = (int) parseSize(fileSizeThreshold); - } - - private long parseSize(String size) { - Assert.hasLength(size, "Size must not be empty"); - size = size.toUpperCase(Locale.ENGLISH); - if (size.endsWith("KB")) { - return Long.valueOf(size.substring(0, size.length() - 2)) * 1024; - } - if (size.endsWith("MB")) { - return Long.valueOf(size.substring(0, size.length() - 2)) * 1024 * 1024; - } - return Long.valueOf(size); + setFileSizeThreshold(DataSize.parse(fileSizeThreshold)); } /** @@ -127,8 +138,25 @@ private long parseSize(String size) { * @return the multipart config element */ public MultipartConfigElement createMultipartConfig() { - return new MultipartConfigElement(this.location, this.maxFileSize, - this.maxRequestSize, this.fileSizeThreshold); + long maxFileSizeBytes = convertToBytes(this.maxFileSize, -1); + long maxRequestSizeBytes = convertToBytes(this.maxRequestSize, -1); + long fileSizeThresholdBytes = convertToBytes(this.fileSizeThreshold, 0); + return new MultipartConfigElement(this.location, maxFileSizeBytes, + maxRequestSizeBytes, (int) fileSizeThresholdBytes); + } + + /** + * Return the amount of bytes from the specified {@link DataSize size}. If the size is + * {@code null} or negative, returns {@code defaultValue}. + * @param size the data size to handle + * @param defaultValue the default value if the size is {@code null} or negative + * @return the amount of bytes to use + */ + private long convertToBytes(DataSize size, int defaultValue) { + if (size != null && !size.isNegative()) { + return size.toBytes(); + } + return defaultValue; } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java index 4b1c07bed483..fbad220d1531 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -20,12 +20,15 @@ import org.junit.Test; +import org.springframework.util.unit.DataSize; + import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link MultipartConfigFactory}. * * @author Phillip Webb + * @author Stephane Nicoll */ public class MultipartConfigFactoryTests { @@ -40,6 +43,7 @@ public void sensibleDefaults() { } @Test + @Deprecated public void create() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setLocation("loc"); @@ -54,15 +58,40 @@ public void create() { } @Test + @Deprecated public void createWithStringSizes() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize("1"); - factory.setMaxRequestSize("2kB"); - factory.setFileSizeThreshold("3Mb"); + factory.setMaxRequestSize("2KB"); + factory.setFileSizeThreshold("3MB"); + MultipartConfigElement config = factory.createMultipartConfig(); + assertThat(config.getMaxFileSize()).isEqualTo(1L); + assertThat(config.getMaxRequestSize()).isEqualTo(2 * 1024L); + assertThat(config.getFileSizeThreshold()).isEqualTo(3 * 1024 * 1024); + } + + @Test + public void createWithDataSizes() { + MultipartConfigFactory factory = new MultipartConfigFactory(); + factory.setMaxFileSize(DataSize.ofBytes(1)); + factory.setMaxRequestSize(DataSize.ofKiloBytes(2)); + factory.setFileSizeThreshold(DataSize.ofMegaBytes(3)); MultipartConfigElement config = factory.createMultipartConfig(); assertThat(config.getMaxFileSize()).isEqualTo(1L); assertThat(config.getMaxRequestSize()).isEqualTo(2 * 1024L); assertThat(config.getFileSizeThreshold()).isEqualTo(3 * 1024 * 1024); } + @Test + public void createWithNegativeDataSizes() { + MultipartConfigFactory factory = new MultipartConfigFactory(); + factory.setMaxFileSize(DataSize.ofBytes(-1)); + factory.setMaxRequestSize(DataSize.ofKiloBytes(-2)); + factory.setFileSizeThreshold(DataSize.ofMegaBytes(-3)); + MultipartConfigElement config = factory.createMultipartConfig(); + assertThat(config.getMaxFileSize()).isEqualTo(-1L); + assertThat(config.getMaxRequestSize()).isEqualTo(-1); + assertThat(config.getFileSizeThreshold()).isEqualTo(0); + } + } From e7b5d956816a77f57d22b57c2058bcbfda90217c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 12 Aug 2018 13:21:29 +0200 Subject: [PATCH 351/701] Adapt ServerProperties with a default size to DataSize See gh-13974 --- .../boot/autoconfigure/web/ServerProperties.java | 9 +++++---- .../web/embedded/TomcatWebServerFactoryCustomizer.java | 4 +++- .../TomcatWebServerFactoryCustomizerTests.java | 10 ++++++---- .../main/asciidoc/appendix-application-properties.adoc | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index c872465e4705..4a344584a028 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -37,6 +37,7 @@ import org.springframework.boot.web.servlet.server.Jsp; import org.springframework.boot.web.servlet.server.Session; import org.springframework.util.StringUtils; +import org.springframework.util.unit.DataSize; /** * {@link ConfigurationProperties} for a web server (e.g. port and path settings). @@ -330,9 +331,9 @@ public static class Tomcat { private int maxHttpHeaderSize = 0; /** - * Maximum amount of request body bytes to swallow. + * Maximum amount of request body to swallow. */ - private int maxSwallowSize = 2097152; + private DataSize maxSwallowSize = DataSize.ofMegaBytes(2); /** * Whether requests to the context root should be redirected by appending a / to @@ -496,11 +497,11 @@ public int getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } - public int getMaxSwallowSize() { + public DataSize getMaxSwallowSize() { return this.maxSwallowSize; } - public void setMaxSwallowSize(int maxSwallowSize) { + public void setMaxSwallowSize(DataSize maxSwallowSize) { this.maxSwallowSize = maxSwallowSize; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index b2f70db2f624..356369611222 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -37,6 +37,7 @@ import org.springframework.core.Ordered; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; +import org.springframework.util.unit.DataSize; /** * Customization for Tomcat-specific features common for both Servlet and Reactive @@ -86,7 +87,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); - propertyMapper.from(tomcatProperties::getMaxSwallowSize) + propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); propertyMapper.from(tomcatProperties::getMaxHttpPostSize) .when((maxHttpPostSize) -> maxHttpPostSize != 0) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index d5b58abaefc8..165f99f3e888 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -41,6 +41,7 @@ import org.springframework.mock.env.MockEnvironment; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.unit.DataSize; import static org.assertj.core.api.Assertions.assertThat; @@ -74,8 +75,9 @@ public void setup() { public void defaultsAreConsistent() { customizeAndRunServer((server) -> { assertThat(((AbstractHttp11Protocol) server.getTomcat().getConnector() - .getProtocolHandler()).getMaxSwallowSize()).isEqualTo( - this.serverProperties.getTomcat().getMaxSwallowSize()); + .getProtocolHandler()).getMaxSwallowSize()) + .isEqualTo(this.serverProperties.getTomcat() + .getMaxSwallowSize().toBytes()); }); } @@ -121,10 +123,10 @@ public void customMaxHttpPostSize() { @Test public void customMaxSwallowSize() { - bind("server.tomcat.max-swallow-size=10"); + bind("server.tomcat.max-swallow-size=10MB"); customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server .getTomcat().getConnector().getProtocolHandler()).getMaxSwallowSize()) - .isEqualTo(10)); + .isEqualTo(DataSize.ofMegaBytes(10).toBytes())); } @Test diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e19e1b98239f..e6aa62eb3337 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -260,7 +260,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time. server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content. - server.tomcat.max-swallow-size=2097152 # Maximum amount of request body bytes to swallow. + server.tomcat.max-swallow-size=2MB # Maximum amount of request body to swallow. server.tomcat.max-threads=0 # Maximum number of worker threads. server.tomcat.min-spare-threads=0 # Minimum number of worker threads. server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value. From 04215e665144af2c365d7bbb34a256123586b09b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 13 Aug 2018 15:59:17 +0100 Subject: [PATCH 352/701] Polish --- .../data/redis/LettuceConnectionConfiguration.java | 6 +++--- .../boot/web/servlet/ServletContextInitializerBeans.java | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index 6cce147194ba..7adbc364bde6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -154,8 +154,8 @@ public LettuceClientConfigurationBuilder createBuilder(Pool properties) { .poolConfig(getPoolConfig(properties)); } - private GenericObjectPoolConfig getPoolConfig(Pool properties) { - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + private GenericObjectPoolConfig getPoolConfig(Pool properties) { + GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); config.setMaxTotal(properties.getMaxActive()); config.setMaxIdle(properties.getMaxIdle()); config.setMinIdle(properties.getMinIdle()); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index 6a2bf32f5661..8f4c4e65548c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -78,6 +78,7 @@ public class ServletContextInitializerBeans private List sortedList; + @SafeVarargs public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); @@ -260,6 +261,7 @@ public int size() { * * @param the type of the Bean to adapt */ + @FunctionalInterface protected interface RegistrationBeanAdapter { RegistrationBean createRegistrationBean(String name, T source, From 9032e5b470fb41ce40aef7e769edaf9aba2a5d94 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 10 Aug 2018 18:03:56 +0100 Subject: [PATCH 353/701] Update SSL tests and certs for Java 11 and TLSv1.3 See gh-14028 --- .../AbstractServletWebServerFactoryTests.java | 7 ++++--- .../src/test/resources/restricted.jks | Bin 0 -> 4464 bytes .../spring-boot/src/test/resources/test.jks | Bin 4464 -> 1276 bytes 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/resources/restricted.jks diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index ee07ede7c05f..0992609a3be2 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -426,7 +426,7 @@ public void sslKeyAlias() throws Exception { this.webServer = factory.getWebServer(registration); this.webServer.start(); TrustStrategy trustStrategy = new SerialNumberValidatingTrustSelfSignedStrategy( - "77e7c302"); + "3a3aaec8"); SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, trustStrategy).build(); HttpClient httpClient = HttpClients.custom() @@ -558,7 +558,8 @@ public void sslWantsClientAuthenticationSucceedsWithClientCertificate() throws Exception { AbstractServletWebServerFactory factory = getFactory(); addTestTxtFile(factory); - factory.setSsl(getSsl(ClientAuth.WANT, "password", "classpath:test.jks")); + factory.setSsl(getSsl(ClientAuth.WANT, "password", "classpath:test.jks", null, + new String[] { "TLSv1.2" }, null)); this.webServer = factory.getWebServer(); this.webServer.start(); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -692,7 +693,7 @@ private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyAlias, protected void testRestrictedSSLProtocolsAndCipherSuites(String[] protocols, String[] ciphers) throws Exception { AbstractServletWebServerFactory factory = getFactory(); - factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks", null, + factory.setSsl(getSsl(null, "password", "src/test/resources/restricted.jks", null, protocols, ciphers)); this.webServer = factory.getWebServer( new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); diff --git a/spring-boot-project/spring-boot/src/test/resources/restricted.jks b/spring-boot-project/spring-boot/src/test/resources/restricted.jks new file mode 100644 index 0000000000000000000000000000000000000000..1bce90bba66f697b2051dc839377de1f016a563d GIT binary patch literal 4464 zcmeH}XH-*rm&VgbCh{iXciaQlwArJNKQr?|9dmPc!r7e%R}r{d_oUujlOl@BbVu9xMU?01%_V zi~<6nH%adHwl^8C7q1-;u>b&=Ko|<-0K*Ptm4pHzKnc)MAdm?Fp+M%C-upfh)ig4F zk2bYO)$;1B`%75OLb$$2HP`<%SXBaZKo!5}*(whI7G^b7fiQX0ZEFcAyV55V&{n7* z)N#Kd?%G5-AH+ddk0nWL9{E z2h5ylj3uqD%lU(kF5nR19Ju@NL!fV8@PqpkPde|)WrP)Ja;z+^eqirct7L>@L|9@&m#H7JCS>bmZ) zJOy^2{M7xBuZopUjnkz}^bn6aRu=E3Hg;lO&;hgPv;Y-Uh@qoH>(u3pSV7t=VeL1W z`cejVD?6_t7gLzA!rdrLK~CB={K$_JEr!(P^g3*qPQEn1ajnDEU=x0XV5 zH=xA`0lB8y`!S+VqVgjboiW^f#D^S;U0KgR+G=R)z9Gw1sLCZ>6mag*D~4f^de@q7vO5#C+8iH3Nkg$+qG%6Z7+yQQrlc_vDYh*#+x2Z zx6+=5Cw4wu(z*z}teq5-<13ndAzmOyE?q^lI$fZMd1o!^DPnCva&X|J;y7J5>%iSu zAP!a7k-NG*qin9C5%xA;-GNE!8lEOESJLQpOvo$Vvl4R0x2l>-c=@r;(d^TDWM@F2 zJ5c9|T8(<3{h5p89etKfRGob*;kcLO4OAYVaABA6{Po7w$hDGIsz(q_GwZ4)x5Pt> z=+c2TF&cT>XSe6civdM&@y^(&Xo_pGM^xsvS1ghw^ZQ%>IyEnU-Sr z5G9wD4av5A;v`q32eD(hXpVUPXyH7nt3_bPl_>C9ue=MC3&3kQj@w5@UO7FM7I45e z{rH@<6F+mpOy3LtCs{E=z?@yfl*@%?y&-2D7YaECcXhIvZGNC|-0Zo7TPGCzW>{mZ z<%|56jVsim6`}O|mUA*=H_JNInMvx4sxE=_rJ)V|#4*aV7=pN4;pu4c{ZC38#F`V0 z(10rw9|pGZ!p}P1?hG_3o9S-i{oW?rL=-r_a=t`>TA@b`d3^$Ss~ zG6<>vAS08xj66n(!O36@1?-QZfb5@uK|l})Vjh!C!@!{|5)p)mEjSR!#st84U^yAc z1e-vhTrd+4R}Yf!e=5wsD6n4?)?XC1|5A=&IDh{#n2W`YWN+(sjpTh3gF?cwau`LN z92Sek%gbB--eNI0+#l`#`8*V$;GZpF+!$aAkOP3B09ip4AQ13y6CG?&Ipx&a9JqW7 zcgH22yOMKr`9xCb#gy)oc?I2=Z&+a0P|^n^bxbk*?CrZFs)@4-Q5na$)Pvar1g)MM zqsw^FSCM;@A-mx~GE{G!U|yha<5=aM<9FN@8U^1ce%D^n*A*liqKH>Umg;7i62NSz zAJ}L&QK_m)waA)eZL#yKQE0CF?2#qBD=Mn39lJ*YG-B_Z+p<-4Qs>HjkZ7%I^VN%rMZ=b%`YaP4A&nlSsfg-kn zzRk9LKE*GCJ_0Cs`w`%zt`3LO9dwJxOrz3TY&{}+&IKSa5CF_Mjp4_fV*JZf><}IZ zf?A7@om+j^-z$Xo_xBBe8fvtJ|Jg*wUNKAr0^;IX&U{$f{2bnLLCANOps-Z6oSm@& zQ!`XibtykDi@8BpJ-*dK`jSAzXBSTCya-m>JWX}vb<)IjI^%X`3k=m4W?lC}990B^ zkzP&Hdj?k>la9=rJc{1yF&##-f!cM3*k4@!Ij!*SYM@H5!WnGnoK(!-*Hm6)kj8Cy zgOLlh$Ubu)Vu@5yyw`~aOME%`vqbp&#HY?t4nY$^G`~6{TxSJurci;UHIsJ|xxF<9 zVDyGn@w4Gpocv6SRJ4Fycbg|b2pR(U?L6}9JA909tcAl}ttJyG+k?CN7v5bLzD$~I z8%ljM^e5v}{v~9kNDIf*NFhN%+;O)id5AG26+)Eagan2Z0?I*2MM+n~qXL z=!MY=?+UzOk-u=F0{I}JrdfQLRx^ikLrKb))OyojuX}P zeO$o%GwqnDLxdtJT4ib$QKOK|rJcN%|AvqVEP7r(k*icnCE#g~OA*}}bxJW843x6w zX5>@okNE)=2RJ$Ek6U(#K6J5ge`bD=%NI@fc>VOgX*6?8k+MPZ)6Z&_)EcYddV%C~ znk7EYru$;;waVMo{6Afcg2Q$B3qNjIDz%-BQGLv!iEtd2f43o_Wn6T_z7FquL2=wh zW5l6V>umC}=6?J36jdtCUR)Aj@EGx~kt1@bidL4D5-Bqv^K63#yP+;(`^ZT3 zTushWK^f(qnDpSe=;1KaMUBbPyQ8#qks1EmGbw>s-aAQkHqp0+G;gHTaYoL);)&Rn=L17GVcH$vm1~zYF|9~6x zPjLIE#{3r=>@PIdztGtJLi+`viWpfe28)+f`VW9AViYj=KidDt$tXZ7W2>e9X%mpq z@Po)?z<%%*@+qHV;+MyDGGrE}zil3+URGJw1T>)3Lf#pPT-UNbFKD!Dp&DbpQ$ydV z#B8>wo45^;l|xR+k=C4SsIF;-&!1&weTVpS3f3FYUJe~loA`bzn|*7_%jM>P?1pak z(NPT`d1Ee1o_O4*&yPY$+aZbNH9;_MW)A__4B`f)*cd+GMzeLiO{kz`&xf(Cn4jGE zeYCB~C*gzXs$=a{1^=c{ZdT!!SVY@7J4e|z(_>SGQJjq|%wjA1EevKnVVvZUQX-Eh z`n#SO4;QtI1sC0tJE_8RC(1Y=Mrl5#h6U?@ATHbDT*X|BbNV((LYIUAb z+`YWe@kz_CS82i`WSGiKPL*; z?653ALWG<8a#xpD&ho-{58dd?T{VXquZ$o&`EzZsoZ}*Q*@DNV*Fw!|+qyDFy7=?$ zx=?Lp|BdfI_2P;X3H_gz@x<(2DL{ItbI9?3S${AFfRP3vEbbJZA86MFPj%7XU|C=R zFIm#5472YJSR$?0MWFH4-Y>3=po`dfw(S__3j|i%F1? zk(GfZ`?F{4vBFug6<%MmmXJ+)mEgQoslXV6!5_H^yana6V1?kw1w zbE0Bi&GHlLHzfosgjrwL)qKcc5I;l0LF?W2lpQg%-cHp$l(#o)?Jkath1@gQN{hG8 zig@wKv#0R7vd_QC=JG%%Ffy=4=$RT=0v*d`(8R=M(8RcU0W%XL6BCP-)w&Y~JZv0V zZ64=rS(uqv84M~6g$xAPm_u3EggJBalM{0?@{3DgVjNh+*s+LlVG-lTBF2m)W*{fd zYiMC$VQ64zW@K(?5e4L0B5?=MWswHLZ0z7LVq$~_7BeF|vl9agPmO-znfkD()@R+bGrT$(AXmN24#zv*XRX z#$UNu(Lmln78u;Jd@N!tBKmU@J0!OJc3G%!N>OO@P1n+F-CorAVRmOQaA8six!iWP z)M3lXpnJ*TI=kIlH(Yxia-ls?xvctEx&P5B6()tKm`>%bo~@fX9{j%TtMU1G!|pw& zZ6BRjIqQ^`bIxR@OmMno&8^H%tpq36Esh&T(+MJ_la+#pV>+3scS%h{iXciaQlwArJNKQr?|9dmPc!r7e%R}r{d_oUujlOl@BbVu9xMU?01%_V zi~<6nH%adHwl^8C7q1-;u>b&=Ko|<-0K*Ptm4pHzKnc)MAdm?Fp+M%C-upfh)ig4F zk2bYO)$;1B`%75OLb$$2HP`<%SXBaZKo!5}*(whI7G^b7fiQX0ZEFcAyV55V&{n7* z)N#Kd?%G5-AH+ddk0nWL9{E z2h5ylj3uqD%lU(kF5nR19Ju@NL!fV8@PqpkPde|)WrP)Ja;z+^eqirct7L>@L|9@&m#H7JCS>bmZ) zJOy^2{M7xBuZopUjnkz}^bn6aRu=E3Hg;lO&;hgPv;Y-Uh@qoH>(u3pSV7t=VeL1W z`cejVD?6_t7gLzA!rdrLK~CB={K$_JEr!(P^g3*qPQEn1ajnDEU=x0XV5 zH=xA`0lB8y`!S+VqVgjboiW^f#D^S;U0KgR+G=R)z9Gw1sLCZ>6mag*D~4f^de@q7vO5#C+8iH3Nkg$+qG%6Z7+yQQrlc_vDYh*#+x2Z zx6+=5Cw4wu(z*z}teq5-<13ndAzmOyE?q^lI$fZMd1o!^DPnCva&X|J;y7J5>%iSu zAP!a7k-NG*qin9C5%xA;-GNE!8lEOESJLQpOvo$Vvl4R0x2l>-c=@r;(d^TDWM@F2 zJ5c9|T8(<3{h5p89etKfRGob*;kcLO4OAYVaABA6{Po7w$hDGIsz(q_GwZ4)x5Pt> z=+c2TF&cT>XSe6civdM&@y^(&Xo_pGM^xsvS1ghw^ZQ%>IyEnU-Sr z5G9wD4av5A;v`q32eD(hXpVUPXyH7nt3_bPl_>C9ue=MC3&3kQj@w5@UO7FM7I45e z{rH@<6F+mpOy3LtCs{E=z?@yfl*@%?y&-2D7YaECcXhIvZGNC|-0Zo7TPGCzW>{mZ z<%|56jVsim6`}O|mUA*=H_JNInMvx4sxE=_rJ)V|#4*aV7=pN4;pu4c{ZC38#F`V0 z(10rw9|pGZ!p}P1?hG_3o9S-i{oW?rL=-r_a=t`>TA@b`d3^$Ss~ zG6<>vAS08xj66n(!O36@1?-QZfb5@uK|l})Vjh!C!@!{|5)p)mEjSR!#st84U^yAc z1e-vhTrd+4R}Yf!e=5wsD6n4?)?XC1|5A=&IDh{#n2W`YWN+(sjpTh3gF?cwau`LN z92Sek%gbB--eNI0+#l`#`8*V$;GZpF+!$aAkOP3B09ip4AQ13y6CG?&Ipx&a9JqW7 zcgH22yOMKr`9xCb#gy)oc?I2=Z&+a0P|^n^bxbk*?CrZFs)@4-Q5na$)Pvar1g)MM zqsw^FSCM;@A-mx~GE{G!U|yha<5=aM<9FN@8U^1ce%D^n*A*liqKH>Umg;7i62NSz zAJ}L&QK_m)waA)eZL#yKQE0CF?2#qBD=Mn39lJ*YG-B_Z+p<-4Qs>HjkZ7%I^VN%rMZ=b%`YaP4A&nlSsfg-kn zzRk9LKE*GCJ_0Cs`w`%zt`3LO9dwJxOrz3TY&{}+&IKSa5CF_Mjp4_fV*JZf><}IZ zf?A7@om+j^-z$Xo_xBBe8fvtJ|Jg*wUNKAr0^;IX&U{$f{2bnLLCANOps-Z6oSm@& zQ!`XibtykDi@8BpJ-*dK`jSAzXBSTCya-m>JWX}vb<)IjI^%X`3k=m4W?lC}990B^ zkzP&Hdj?k>la9=rJc{1yF&##-f!cM3*k4@!Ij!*SYM@H5!WnGnoK(!-*Hm6)kj8Cy zgOLlh$Ubu)Vu@5yyw`~aOME%`vqbp&#HY?t4nY$^G`~6{TxSJurci;UHIsJ|xxF<9 zVDyGn@w4Gpocv6SRJ4Fycbg|b2pR(U?L6}9JA909tcAl}ttJyG+k?CN7v5bLzD$~I z8%ljM^e5v}{v~9kNDIf*NFhN%+;O)id5AG26+)Eagan2Z0?I*2MM+n~qXL z=!MY=?+UzOk-u=F0{I}JrdfQLRx^ikLrKb))OyojuX}P zeO$o%GwqnDLxdtJT4ib$QKOK|rJcN%|AvqVEP7r(k*icnCE#g~OA*}}bxJW843x6w zX5>@okNE)=2RJ$Ek6U(#K6J5ge`bD=%NI@fc>VOgX*6?8k+MPZ)6Z&_)EcYddV%C~ znk7EYru$;;waVMo{6Afcg2Q$B3qNjIDz%-BQGLv!iEtd2f43o_Wn6T_z7FquL2=wh zW5l6V>umC}=6?J36jdtCUR)Aj@EGx~kt1@bidL4D5-Bqv^K63#yP+;(`^ZT3 zTushWK^f(qnDpSe=;1KaMUBbPyQ8#qks1EmGbw>s-aAQkHqp0+G;gHTaYoL);)&Rn=L17GVcH$vm1~zYF|9~6x zPjLIE#{3r=>@PIdztGtJLi+`viWpfe28)+f`VW9AViYj=KidDt$tXZ7W2>e9X%mpq z@Po)?z<%%*@+qHV;+MyDGGrE}zil3+URGJw1T>)3Lf#pPT-UNbFKD!Dp&DbpQ$ydV z#B8>wo45^;l|xR+k=C4SsIF;-&!1&weTVpS3f3FYUJe~loA`bzn|*7_%jM>P?1pak z(NPT`d1Ee1o_O4*&yPY$+aZbNH9;_MW)A__4B`f)*cd+GMzeLiO{kz`&xf(Cn4jGE zeYCB~C*gzXs$=a{1^=c{ZdT!!SVY@7J4e|z(_>SGQJjq|%wjA1EevKnVVvZUQX-Eh z`n#SO4;QtI1sC0tJE_8RC(1Y=Mrl5#h6U?@ATHbDT*X|BbNV((LYIUAb z+`YWe@kz_CS82i`WSGiKPL*; z?653ALWG<8a#xpD&ho-{58dd?T{VXquZ$o&`EzZsoZ}*Q*@DNV*Fw!|+qyDFy7=?$ zx=?Lp|BdfI_2P;X3H_gz@x<(2DL{ItbI9?3S${AFfRP3vEbbJZA86MFPj%7XU|C=R zFIm#5472YJSR$?0MWFH4-Y>3=po`dfw(S__3j| Date: Tue, 14 Aug 2018 11:00:20 +0300 Subject: [PATCH 354/701] Polish --- spring-boot-project/spring-boot-dependencies/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0beee8114219..50d9150eac19 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1919,13 +1919,6 @@ org.hibernate.validator hibernate-validator ${hibernate-validator.version} - - - - org.openjfx - javafx.base - -
org.hibernate.validator From 8427341480839163437fb40d774a7354a05f24bf Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Tue, 14 Aug 2018 12:10:02 -0400 Subject: [PATCH 355/701] Exclude protobuf-java from mysql-connector-java Closes gh-14062 --- spring-boot-project/spring-boot-dependencies/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 50d9150eac19..58e0ecc2bf5f 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1097,6 +1097,12 @@ mysql mysql-connector-java ${mysql.version} + + + com.google.protobuf + protobuf-java + + net.bytebuddy From e34723efd23ccf4026b31d506a0dccbdb8108589 Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Tue, 14 Aug 2018 13:04:50 -0600 Subject: [PATCH 356/701] Update OIDC config following Spring Security changes The location changed for the class that provides a ClientRegistration via an issuer URL, and this updates Spring Boot accordingly. --- .../client/OAuth2ClientPropertiesRegistrationAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index f01e6539405c..47414e85c56a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -25,9 +25,9 @@ import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.core.convert.ConversionException; import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; -import org.springframework.security.config.oauth2.client.oidc.OidcConfigurationProvider; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.client.registration.ClientRegistrations; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.util.StringUtils; @@ -85,7 +85,7 @@ private static Builder getBuilderFromIssuerIfPossible(String registrationId, String issuer = provider.getIssuerUri(); if (issuer != null) { String cleanedIssuer = cleanIssuerPath(issuer); - Builder builder = OidcConfigurationProvider.issuer(cleanedIssuer) + Builder builder = ClientRegistrations.fromOidcIssuerLocation(cleanedIssuer) .registrationId(registrationId); return getBuilder(builder, provider); } From baaf8c95ffecc37f1856cbc07984e06ca5bf1660 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 14 Aug 2018 15:30:19 -0700 Subject: [PATCH 357/701] Polish "Update OIDC configuration" Closes gh-14065 --- .../client/OAuth2ClientPropertiesRegistrationAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index 47414e85c56a..e8454add7902 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -85,7 +85,8 @@ private static Builder getBuilderFromIssuerIfPossible(String registrationId, String issuer = provider.getIssuerUri(); if (issuer != null) { String cleanedIssuer = cleanIssuerPath(issuer); - Builder builder = ClientRegistrations.fromOidcIssuerLocation(cleanedIssuer) + Builder builder = ClientRegistrations + .fromOidcIssuerLocation(cleanedIssuer) .registrationId(registrationId); return getBuilder(builder, provider); } From e0d67ae7033ee595f7f4985830c18759afc13d5e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 14 Aug 2018 13:29:46 +0100 Subject: [PATCH 358/701] Avoid Atmosphere using a null URL to create a URLClassLoader Unlike Java 8, 9, and 10, Java 11 does not tolerate a null URL being used to create a URLClassLoader. The Atmosphere sample looks for a resource named /WEB-INF/classes which only exists in a packaged war application. In all other cases the resulting URL is null. Atmosphere uses this to create a URLClassLoader which fails on Java 11. This commit updates the sample to customize the handlers path. There are other web application-specific assumptions in Atmosphere, such as the scanning of WEB-INF/lib by default. This change appears to get the sample going, but we should, perhaps, consider removing it in the longer term, particularly as Boot itself has no Atmosphere integration. See gh-14028 --- .../java/sample/atmosphere/SampleAtmosphereApplication.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spring-boot-samples/spring-boot-sample-atmosphere/src/main/java/sample/atmosphere/SampleAtmosphereApplication.java b/spring-boot-samples/spring-boot-sample-atmosphere/src/main/java/sample/atmosphere/SampleAtmosphereApplication.java index 4f6800bef0ec..9af08d0c5517 100644 --- a/spring-boot-samples/spring-boot-sample-atmosphere/src/main/java/sample/atmosphere/SampleAtmosphereApplication.java +++ b/spring-boot-samples/spring-boot-sample-atmosphere/src/main/java/sample/atmosphere/SampleAtmosphereApplication.java @@ -48,8 +48,10 @@ public EmbeddedAtmosphereInitializer atmosphereInitializer() { public ServletRegistrationBean atmosphereServlet() { // Dispatcher servlet is mapped to '/home' to allow the AtmosphereServlet // to be mapped to '/chat' + AtmosphereServlet atmosphereServlet = new AtmosphereServlet(); + atmosphereServlet.framework().setHandlersPath("/"); ServletRegistrationBean registration = new ServletRegistrationBean<>( - new AtmosphereServlet(), "/chat/*"); + atmosphereServlet, "/chat/*"); registration.addInitParameter("org.atmosphere.cpr.packages", "sample"); registration.addInitParameter("org.atmosphere.interceptor.HeartbeatInterceptor" + ".clientHeartbeatFrequencyInSeconds", "10"); From d5eaaf6e2a92f235b2bca87839e4284bebbf7740 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Mon, 13 Aug 2018 22:47:04 +0900 Subject: [PATCH 359/701] Polish Closes gh-14049 --- .../task/TaskExecutorAutoConfiguration.java | 17 ++++++----------- .../boot/autoconfigure/task/TaskProperties.java | 4 ++-- .../TaskExecutorAutoConfigurationTests.java | 14 +++++++------- .../appendix-application-properties.adoc | 2 +- .../src/main/asciidoc/spring-boot-features.adoc | 8 ++++---- .../boot/json/JsonParserFactory.java | 2 +- .../boot/task/TaskExecutorBuilder.java | 10 +++++----- ...nDefinitionOverrideFailureAnalyzerTests.java | 2 +- .../boot/task/TaskExecutorBuilderTests.java | 14 +++++++------- .../web/client/RestTemplateBuilderTests.java | 8 +++----- .../kafka/SampleKafkaApplicationTests.java | 3 +-- 11 files changed, 38 insertions(+), 46 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java index b3be0b377e35..a5c93e413f64 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java @@ -65,20 +65,15 @@ public TaskExecutorAutoConfiguration(TaskProperties properties, @Bean @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder() { - TaskExecutorBuilder builder = new TaskExecutorBuilder(); TaskProperties.Pool pool = this.properties.getPool(); - builder = builder.queueCapacity(pool.getQueueCapacity()) + return new TaskExecutorBuilder().queueCapacity(pool.getQueueCapacity()) .corePoolSize(pool.getCoreSize()).maxPoolSize(pool.getMaxSize()) .allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()) - .keepAlive(pool.getKeepAlive()); - builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix()); - builder = builder.customizers( - this.taskExecutorCustomizers.stream().collect(Collectors.toList())); - TaskDecorator taskDecorator = this.taskDecorator.getIfUnique(); - if (taskDecorator != null) { - builder = builder.taskDecorator(taskDecorator); - } - return builder; + .keepAlive(pool.getKeepAlive()) + .threadNamePrefix(this.properties.getThreadNamePrefix()) + .customizers(this.taskExecutorCustomizers.stream() + .collect(Collectors.toList())) + .taskDecorator(this.taskDecorator.getIfUnique()); } @Bean(name = APPLICATION_TASK_EXECUTOR_BEAN_NAME) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java index add12aa19674..84e38a369e8e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java @@ -50,8 +50,8 @@ public void setThreadNamePrefix(String threadNamePrefix) { public static class Pool { /** - * Queue capacity. A unbounded capacity does not increase the pool and therefore - * ignores the "max-size" parameter. + * Queue capacity. An unbounded capacity does not increase the pool and therefore + * ignores the "max-size" property. */ private int queueCapacity = Integer.MAX_VALUE; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java index 93c15cb108cc..be3a7c9bbbe3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java @@ -109,19 +109,19 @@ public void taskExecutorAutoConfigured() { } @Test - public void taskExecutorWhenHasCustomTaskExecutorShouldBAckOff() { + public void taskExecutorWhenHasCustomTaskExecutorShouldBackOff() { this.contextRunner.withUserConfiguration(CustomTaskExecutorConfig.class) .run((context) -> { assertThat(context).hasSingleBean(Executor.class); assertThat(context.getBean(Executor.class)) - .isSameAs(context.getBean("customTaskExecutorBuilder")); + .isSameAs(context.getBean("customTaskExecutor")); }); } @Test public void taskExecutorBuilderShouldApplyCustomizer() { - this.contextRunner.withUserConfiguration(CustomTaskExecutorConfig.class, - TaskExecutorCustomizerConfig.class).run((context) -> { + this.contextRunner.withUserConfiguration(TaskExecutorCustomizerConfig.class) + .run((context) -> { TaskExecutorCustomizer customizer = context .getBean(TaskExecutorCustomizer.class); ThreadPoolTaskExecutor executor = context @@ -138,8 +138,8 @@ public void enableAsyncUsesAutoConfiguredOneByDefault() { .run((context) -> { assertThat(context).hasSingleBean(TaskExecutor.class); TestBean bean = context.getBean(TestBean.class); - String text = bean.echo("test").get(); - assertThat(text).contains("executor-test-").contains("test"); + String text = bean.echo("something").get(); + assertThat(text).contains("executor-test-").contains("something"); }); } @@ -188,7 +188,7 @@ public TaskDecorator mockTaskDecorator() { static class CustomTaskExecutorConfig { @Bean - public Executor customTaskExecutorBuilder() { + public Executor customTaskExecutor() { return new SyncTaskExecutor(); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e6aa62eb3337..2bbd68963b3a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -166,7 +166,7 @@ content into your application. Rather, pick only the properties that you need. spring.task.pool.core-size=8 # Core number of threads. spring.task.pool.keep-alive=60s # Time limit for which threads may remain idle before being terminated. spring.task.pool.max-size= # Maximum allowed number of threads. If tasks are filling up the queue, the pool can expand up to that size to accommodate the load. Ignored if the queue is unbounded. - spring.task.pool.queue-capacity= # Queue capacity. A unbounded capacity does not increase the pool and therefore ignores the "max-size" parameter. + spring.task.pool.queue-capacity= # Queue capacity. An unbounded capacity does not increase the pool and therefore ignores the "max-size" property. spring.task.thread-name-prefix=executor- # Prefix to use for the names of newly created threads. # ---------------------------------------- diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 8d39881548d5..3788b7230bf6 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4638,7 +4638,7 @@ URLs of your server in your application.properties, as shown in the following ex If you need to customize connection settings, you can use the `spring.ldap.base` and `spring.ldap.base-environment` properties. -A `LdapContextSource` is auto-configured based on these settings. If you need to customize +An `LdapContextSource` is auto-configured based on these settings. If you need to customize it, for instance to use a `PooledContextSource`, you can still inject the auto-configured `LdapContextSource`. Make sure to flag your customized `ContextSource` as `@Primary` so that the auto-configured `LdapTemplate` uses it. @@ -6156,7 +6156,7 @@ following example: This changes the thread pool to use a bounded queue so that when the queue is full (100 tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool is more -aggressive as well as threads are reclaimed when they are idle for 10 seconds (rather than +aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default). @@ -6334,8 +6334,8 @@ web application. * `RANDOM_PORT`: Loads a `WebServerApplicationContext` and provides a real web environment. Embedded servers are started and listen on a random port. * `DEFINED_PORT`: Loads a `WebServerApplicationContext` and provides a real web -environment. Embedded servers are started and listen on a defined port (from your -`application.properties` or on the default port of `8080`). +environment. Embedded servers are started and listen on a defined port (from your +`application.properties`) or on the default port of `8080`. * `NONE`: Loads an `ApplicationContext` by using `SpringApplication` but does not provide _any_ web environment (mock or otherwise). diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java index 737af957ef98..208ea227a5d4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java @@ -31,7 +31,7 @@ public abstract class JsonParserFactory { /** * Static factory for the "best" JSON parser available on the classpath. Tries - * Jackson, then Gson, Snake YAML,and then falls back to the {@link BasicJsonParser}. + * Jackson, then Gson, Snake YAML, and then falls back to the {@link BasicJsonParser}. * @return a {@link JsonParser} */ public static JsonParser getJsonParser() { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java index 5c3c7e7b3e2a..ca11bb530c11 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java @@ -90,7 +90,7 @@ public TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, } /** - * Set the capacity of the queue. A unbounded capacity does not increase the pool and + * Set the capacity of the queue. An unbounded capacity does not increase the pool and * therefore ignores {@link #maxPoolSize(int) maxPoolSize}. * @param queueCapacity the queue capacity to set * @return a new builder instance @@ -134,7 +134,7 @@ public TaskExecutorBuilder maxPoolSize(int maxPoolSize) { /** * Set whether core threads are allow to time out. When enabled, this enables dynamic * growing and shrinking of the pool. - * @param allowCoreThreadTimeOut if core thread are allowed to time out + * @param allowCoreThreadTimeOut if core threads are allowed to time out * @return a new builder instance */ public TaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { @@ -262,7 +262,7 @@ public ThreadPoolTaskExecutor build() { * @param the type of task executor * @param taskExecutorClass the template type to create * @return a configured {@link ThreadPoolTaskExecutor} instance. - * @see TaskExecutorBuilder#build() + * @see #build() * @see #configure(ThreadPoolTaskExecutor) */ public T build(Class taskExecutorClass) { @@ -274,8 +274,8 @@ public T build(Class taskExecutorClass) { * @param the type of task executor * @param taskExecutor the {@link ThreadPoolTaskExecutor} to configure * @return the task executor instance - * @see TaskExecutorBuilder#build() - * @see TaskExecutorBuilder#build(Class) + * @see #build() + * @see #build(Class) */ public T configure(T taskExecutor) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java index 861e52159df8..3b55197f0566 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java @@ -35,7 +35,7 @@ public class BeanDefinitionOverrideFailureAnalyzerTests { @Test - public void bindExceptionWithFieldErrorsDueToValidationFailure() { + public void analyzeBeanDefinitionOverrideException() { FailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class); String description = analysis.getDescription(); assertThat(description).contains("The bean 'testBean', defined in " diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java index 2f560eb81eed..506fcaa7eb41 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java @@ -56,9 +56,9 @@ public void createWhenCustomizersAreNullShouldThrowException() { @Test public void poolSettingsShouldApply() { - ThreadPoolTaskExecutor executor = this.builder.allowCoreThreadTimeOut(true) - .queueCapacity(10).corePoolSize(4).maxPoolSize(8) - .allowCoreThreadTimeOut(true).keepAlive(Duration.ofMinutes(1)).build(); + ThreadPoolTaskExecutor executor = this.builder.queueCapacity(10).corePoolSize(4) + .maxPoolSize(8).allowCoreThreadTimeOut(true) + .keepAlive(Duration.ofMinutes(1)).build(); DirectFieldAccessor dfa = new DirectFieldAccessor(executor); assertThat(dfa.getPropertyValue("queueCapacity")).isEqualTo(10); assertThat(executor.getCorePoolSize()).isEqualTo(4); @@ -107,10 +107,10 @@ public void customizersShouldApply() { public void customizersShouldBeAppliedLast() { TaskDecorator taskDecorator = mock(TaskDecorator.class); ThreadPoolTaskExecutor executor = spy(new ThreadPoolTaskExecutor()); - this.builder.allowCoreThreadTimeOut(true).queueCapacity(10).corePoolSize(4) - .maxPoolSize(8).allowCoreThreadTimeOut(true) - .keepAlive(Duration.ofMinutes(1)).threadNamePrefix("test-") - .taskDecorator(taskDecorator).additionalCustomizers((taskExecutor) -> { + this.builder.queueCapacity(10).corePoolSize(4).maxPoolSize(8) + .allowCoreThreadTimeOut(true).keepAlive(Duration.ofMinutes(1)) + .threadNamePrefix("test-").taskDecorator(taskDecorator) + .additionalCustomizers((taskExecutor) -> { verify(taskExecutor).setQueueCapacity(10); verify(taskExecutor).setCorePoolSize(4); verify(taskExecutor).setMaxPoolSize(8); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java index 7972841fa219..5e0f08f8f884 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java @@ -440,8 +440,7 @@ public void configureShouldApply() { public void connectTimeoutCanBeNullToUseDefault() { ClientHttpRequestFactory requestFactory = this.builder .requestFactory(SimpleClientHttpRequestFactory.class) - .setConnectTimeout(Duration.ofSeconds(5)).setConnectTimeout(null).build() - .getRequestFactory(); + .setConnectTimeout(null).build().getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) .isEqualTo(-1); } @@ -449,9 +448,8 @@ public void connectTimeoutCanBeNullToUseDefault() { @Test public void readTimeoutCanBeNullToUseDefault() { ClientHttpRequestFactory requestFactory = this.builder - .requestFactory(SimpleClientHttpRequestFactory.class) - .setReadTimeout(Duration.ofSeconds(5)).setReadTimeout(null).build() - .getRequestFactory(); + .requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(null) + .build().getRequestFactory(); assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) .isEqualTo(-1); } diff --git a/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java b/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java index 7123c19a30c7..72399feefa50 100644 --- a/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-kafka/src/test/java/sample/kafka/SampleKafkaApplicationTests.java @@ -48,8 +48,7 @@ public void testVanillaExchange() throws Exception { && System.currentTimeMillis() < end) { Thread.sleep(250); } - assertThat(this.outputCapture.toString().contains("A simple test message")) - .isTrue(); + assertThat(this.outputCapture.toString()).contains("A simple test message"); } } From 0ba6d8da4af88fde2469ac64f21a604b090a6639 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 15 Aug 2018 14:21:22 +0100 Subject: [PATCH 360/701] Switch to Yahoo for OIDC as Google's cert is not yet trusted by Java 11 Until the fix for JDK-8209506 [1] is available in Java 11 builds, SSL connections to services using Google's SSL certificate do not work due to a lack of trust. This affects both our OAuth2 client samples which were using https://accounts.google.com as an OpenID Connect provider. This commit switches the two samples to use Yahoo in place of Google. See gh-14028 [1] https://bugs.openjdk.java.net/browse/JDK-8209506 --- .../src/main/resources/application.yml | 10 +++++----- .../client/SampleOAuth2ClientApplicationTests.java | 6 +++--- .../src/main/resources/application.yml | 10 +++++----- .../SampleReactiveOAuth2ClientApplicationTests.java | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml index e0a70da4e018..1a7bd711b3d5 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml @@ -17,9 +17,9 @@ spring: provider: github scope: user:email redirect-uri-template: http://localhost:8080/login/oauth2/code/github - google-oidc: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + yahoo-oidc: + client-id: ${YAHOO-CLIENT-ID} + client-secret: ${YAHOO-CLIENT-SECRET} provider: - google-oidc: - issuer-uri: https://accounts.google.com \ No newline at end of file + yahoo-oidc: + issuer-uri: https://api.login.yahoo.com/ \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java index f286cddbac17..0c04fabb2f70 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java @@ -34,8 +34,8 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret", - "GOOGLE-CLIENT-ID=my-google-client-id", - "GOOGLE-CLIENT-SECRET=my-google-client-secret" }) + "YAHOO-CLIENT-ID=my-yahoo-client-id", + "YAHOO-CLIENT-SECRET=my-yahooo-client-secret" }) public class SampleOAuth2ClientApplicationTests { @LocalServerPort @@ -57,7 +57,7 @@ public void loginShouldHaveBothOAuthClientsToChooseFrom() { ResponseEntity entity = this.restTemplate.getForEntity("/login", String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).contains("/oauth2/authorization/google"); + assertThat(entity.getBody()).contains("/oauth2/authorization/yahoo"); assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-1"); assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); } diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml index e0a70da4e018..1a7bd711b3d5 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -17,9 +17,9 @@ spring: provider: github scope: user:email redirect-uri-template: http://localhost:8080/login/oauth2/code/github - google-oidc: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + yahoo-oidc: + client-id: ${YAHOO-CLIENT-ID} + client-secret: ${YAHOO-CLIENT-SECRET} provider: - google-oidc: - issuer-uri: https://accounts.google.com \ No newline at end of file + yahoo-oidc: + issuer-uri: https://api.login.yahoo.com/ \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java index 66fce8a191cd..506f3d093774 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java @@ -29,8 +29,8 @@ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret", - "GOOGLE-CLIENT-ID=my-google-client-id", - "GOOGLE-CLIENT-SECRET=my-google-client-secret" }) + "YAHOO-CLIENT-ID=my-google-client-id", + "YAHOO-CLIENT-SECRET=my-google-client-secret" }) public class SampleReactiveOAuth2ClientApplicationTests { @Autowired @@ -47,7 +47,7 @@ public void loginShouldHaveBothOAuthClientsToChooseFrom() { byte[] body = this.webTestClient.get().uri("/login").exchange().expectStatus() .isOk().returnResult(String.class).getResponseBodyContent(); String bodyString = new String(body); - assertThat(bodyString).contains("/oauth2/authorization/google"); + assertThat(bodyString).contains("/oauth2/authorization/yahoo"); assertThat(bodyString).contains("/oauth2/authorization/github-client-1"); assertThat(bodyString).contains("/oauth2/authorization/github-client-2"); } From 5ae4b438778770e10a47f54424fcb8f71d2a3af7 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 15 Aug 2018 19:30:43 +0200 Subject: [PATCH 361/701] Upgrade to Assertj 3.11.0 Closes gh-14073 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 58e0ecc2bf5f..79b824033fc0 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -38,7 +38,7 @@ 1.9.64 2.6.2 1.9.1 - 3.10.0 + 3.11.0 4.0.6 2.1.4 1.8.13 From 9201db320098b6a87578f95ea5b3061824eab89b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 09:32:35 +0200 Subject: [PATCH 362/701] Upgrade to Reactor Californium-M2 Closes gh-14077 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 79b824033fc0..4203bdb35ede 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -140,7 +140,7 @@ 2.3.0 4.2.1 5.3.0 - Californium-M1 + Californium-M2 3.1.0 1.0.2 1.3.8 From 31a93035c1e2078547388438e2dbb124b33b5641 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 16 Aug 2018 10:27:55 +0200 Subject: [PATCH 363/701] Remove workaround for Netty resources cleanup Closes gh-9146 --- .../boot/web/embedded/netty/NettyWebServer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index ac09e2db4262..2f921372bf4d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -22,7 +22,6 @@ import org.apache.commons.logging.LogFactory; import reactor.netty.ChannelBindException; import reactor.netty.DisposableServer; -import reactor.netty.http.HttpResources; import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.server.PortInUseException; @@ -122,8 +121,6 @@ public void stop() throws WebServerException { else { this.disposableServer.disposeNow(); } - // temporary fix for gh-9146 - HttpResources.shutdown(); this.disposableServer = null; } } From 40d8726d47ab4573a81d13ffbdf36eae75d6601a Mon Sep 17 00:00:00 2001 From: Jan Groot Date: Thu, 16 Aug 2018 09:55:15 +0200 Subject: [PATCH 364/701] Remove redundant spring-boot-starter dependencies from starters Closes gh-14078 --- .../spring-boot-starters/spring-boot-starter-batch/pom.xml | 4 ---- .../spring-boot-starters/spring-boot-starter-data-jpa/pom.xml | 4 ---- .../spring-boot-starter-data-rest/pom.xml | 4 ---- .../spring-boot-starter-groovy-templates/pom.xml | 4 ---- .../spring-boot-starter-integration/pom.xml | 4 ---- .../spring-boot-starters/spring-boot-starter-jersey/pom.xml | 4 ---- .../spring-boot-starters/spring-boot-starter-jooq/pom.xml | 4 ---- .../spring-boot-starter-web-services/pom.xml | 4 ---- .../spring-boot-starters/spring-boot-starter-web/pom.xml | 4 ---- .../spring-boot-starters/spring-boot-starter-webflux/pom.xml | 4 ---- .../spring-boot-starter-websocket/pom.xml | 4 ---- 11 files changed, 44 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/pom.xml index 0b6a8a232871..12ab2a51803e 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-batch/pom.xml @@ -14,10 +14,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-jdbc diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml index 134d54560cdf..2e7ad504c597 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml @@ -14,10 +14,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-aop diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/pom.xml index 47a23097bdfe..6c371a301b12 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-rest/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-json diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml index aaa98bfbeb86..942a4f417f7f 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-groovy-templates/pom.xml @@ -14,10 +14,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-web diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/pom.xml index 21f70b87539b..f4c683bcce49 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-integration/pom.xml @@ -14,10 +14,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-aop diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml index 0c858d9b0c73..b4d0ff0fce8e 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-jersey/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-json diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/pom.xml index f96dbe7f38dc..c8b7324bcc1b 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-jooq/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-jdbc diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml index 0bbfd9e860f6..9d14391a1220 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-web-services/pom.xml @@ -22,10 +22,6 @@ javax.xml.ws jaxws-api - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-web diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-web/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-web/pom.xml index 86318fe01dcd..4ef754c71e9a 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-web/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-web/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-json diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/pom.xml index 947b4dac0fc0..49d7ae6705e5 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-webflux/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-json diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/pom.xml index 97e595695916..419bc0098018 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-websocket/pom.xml @@ -15,10 +15,6 @@ ${basedir}/../../.. - - org.springframework.boot - spring-boot-starter - org.springframework.boot spring-boot-starter-web From 6ac6d363953ac0561fca3d7833de4aa00acd50dd Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 10:43:28 +0200 Subject: [PATCH 365/701] Polish --- .../boot/context/config/ConfigFileApplicationListener.java | 5 ----- .../context/logging/ClasspathLoggingApplicationListener.java | 5 ----- 2 files changed, 10 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 093fd983008c..4222748029f6 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -155,11 +155,6 @@ public boolean supportsEventType(Class eventType) { || ApplicationPreparedEvent.class.isAssignableFrom(eventType); } - @Override - public boolean supportsSourceType(Class aClass) { - return true; - } - @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/ClasspathLoggingApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/ClasspathLoggingApplicationListener.java index 32756eb7671f..3963cdf0021f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/ClasspathLoggingApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/ClasspathLoggingApplicationListener.java @@ -74,11 +74,6 @@ public boolean supportsEventType(ResolvableType resolvableType) { || ApplicationFailedEvent.class.isAssignableFrom(type); } - @Override - public boolean supportsSourceType(Class sourceType) { - return true; - } - private String getClasspath() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader instanceof URLClassLoader) { From 4d310f0d5a9bfe3159af7a3fe80d5931353d00b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Sat, 16 Jun 2018 06:42:32 -0500 Subject: [PATCH 366/701] Add support for multiple REST Docs configuration customizers This commit introduces support for multiple configuration customizers for REST Docs with MockMvc, WebTestClient, and REST Assured. Closes gh-13498 --- .../restdocs/RestDocsAutoConfiguration.java | 32 +++--- ...AdvancedConfigurationIntegrationTests.java | 15 +++ ...AdvancedConfigurationIntegrationTests.java | 15 +++ ...AdvancedConfigurationIntegrationTests.java | 99 +++++++++++++++++++ 4 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java index f74227a696fa..03ff7808e604 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.test.autoconfigure.restdocs; +import java.util.List; + import io.restassured.builder.RequestSpecBuilder; import io.restassured.specification.RequestSpecification; @@ -58,14 +60,16 @@ static class RestDocsMockMvcConfiguration { @Bean @ConditionalOnMissingBean public MockMvcRestDocumentationConfigurer restDocsMockMvcConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { MockMvcRestDocumentationConfigurer configurer = MockMvcRestDocumentation .documentationConfiguration(contextProvider); - RestDocsMockMvcConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return configurer; } @@ -90,14 +94,16 @@ static class RestDocsRestAssuredConfiguration { @Bean @ConditionalOnMissingBean public RequestSpecification restDocsRestAssuredConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { RestAssuredRestDocumentationConfigurer configurer = RestAssuredRestDocumentation .documentationConfiguration(contextProvider); - RestDocsRestAssuredConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return new RequestSpecBuilder().addFilter(configurer).build(); } @@ -119,14 +125,16 @@ static class RestDocsWebTestClientConfiguration { @Bean @ConditionalOnMissingBean public WebTestClientRestDocumentationConfigurer restDocsWebTestClientConfigurer( - ObjectProvider configurationCustomizerProvider, + ObjectProvider> configurationCustomizerProvider, RestDocumentationContextProvider contextProvider) { WebTestClientRestDocumentationConfigurer configurer = WebTestClientRestDocumentation .documentationConfiguration(contextProvider); - RestDocsWebTestClientConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider + List configurationCustomizers = configurationCustomizerProvider .getIfAvailable(); - if (configurationCustomizer != null) { - configurationCustomizer.customize(configurer); + if (configurationCustomizers != null) { + configurationCustomizers + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); } return configurer; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 6c34911ccdb9..35522678a224 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -38,6 +38,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; /** @@ -72,6 +74,7 @@ public void snippetGeneration() throws Exception { assertThat(new File(defaultSnippetsDir, "curl-request.md")) .has(contentContaining("'http://localhost:8080/'")); assertThat(new File(defaultSnippetsDir, "links.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); } private Condition contentContaining(String toContain) { @@ -94,4 +97,16 @@ public void customize(MockMvcRestDocumentationConfigurer configurer) { } + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsMockMvcConfigurationCustomizer { + + @Override + public void customize(MockMvcRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index a23ab806e257..ec197cf88978 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -39,6 +39,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document; /** @@ -77,6 +79,7 @@ public void snippetGeneration() { assertThat(new File(defaultSnippetsDir, "http-request.md")) .has(contentContaining("api.example.com")); assertThat(new File(defaultSnippetsDir, "http-response.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); } private Condition contentContaining(String toContain) { @@ -94,4 +97,16 @@ public void customize(RestAssuredRestDocumentationConfigurer configurer) { } + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsRestAssuredConfigurationCustomizer { + + @Override + public void customize(RestAssuredRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java new file mode 100644 index 000000000000..68cd9cb96161 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.restdocs; + +import java.io.File; + +import org.assertj.core.api.Condition; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.restdocs.templates.TemplateFormats; +import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.util.FileSystemUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document; + +/** + * Integration tests for {@link RestDocsAutoConfiguration} with {@link WebTestClient}. + * + * @author Eddú Meléndez + */ +@RunWith(SpringRunner.class) +@WebFluxTest +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443) +public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests { + + @Before + public void deleteSnippets() { + FileSystemUtils.deleteRecursively(new File("target/generated-snippets")); + } + + @Autowired + private WebTestClient webTestClient; + + @Test + public void defaultSnippetsAreWritten() throws Exception { + this.webTestClient.get().uri("/").exchange().expectBody() + .consumeWith(document("default-snippets")); + File defaultSnippetsDir = new File("target/generated-snippets/default-snippets"); + assertThat(defaultSnippetsDir).exists(); + assertThat(new File(defaultSnippetsDir, "curl-request.md")) + .has(contentContaining("'https://api.example.com/'")); + assertThat(new File(defaultSnippetsDir, "http-request.md")) + .has(contentContaining("api.example.com")); + assertThat(new File(defaultSnippetsDir, "http-response.md")).isFile(); + assertThat(new File(defaultSnippetsDir, "response-fields.md")).isFile(); + } + + private Condition contentContaining(String toContain) { + return new ContentContainingCondition(toContain); + } + + @TestConfiguration + public static class CustomizationConfiguration + implements RestDocsWebTestClientConfigurationCustomizer { + + @Override + public void customize(WebTestClientRestDocumentationConfigurer configurer) { + configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + } + + } + + @TestConfiguration + public static class CustomizationConfiguration2 + implements RestDocsWebTestClientConfigurationCustomizer { + + @Override + public void customize(WebTestClientRestDocumentationConfigurer configurer) { + configurer.snippets().withAdditionalDefaults( + responseFields(fieldWithPath("_links.self").description("Main URL"))); + } + + } + +} From f10377bdb7a8209edd289f6472487efaadf72b50 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Aug 2018 09:46:04 +0100 Subject: [PATCH 367/701] Polish "Add support for multiple REST Docs configuration customizers" Closes gh-13498 --- ...AdvancedConfigurationIntegrationTests.java | 26 +++++++---------- ...AdvancedConfigurationIntegrationTests.java | 29 ++++++++++--------- ...AdvancedConfigurationIntegrationTests.java | 29 ++++++++++--------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 35522678a224..315111744a40 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -28,7 +28,6 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; import org.springframework.test.context.junit4.SpringRunner; @@ -47,6 +46,7 @@ * MVC. * * @author Andy Wilkinson + * @author Eddú Meléndez */ @RunWith(SpringRunner.class) @WebMvcTest(controllers = RestDocsTestController.class, secure = false) @@ -82,28 +82,22 @@ private Condition contentContaining(String toContain) { } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsMockMvcConfigurationCustomizer { + public static class CustomizationConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } - @Override - public void customize(MockMvcRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocsMockMvcConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); } - } - - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsMockMvcConfigurationCustomizer { - - @Override - public void customize(MockMvcRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsMockMvcConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index ec197cf88978..c4f1dd846f25 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/RestAssuredRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -29,7 +29,9 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.restdocs.restassured3.RestAssuredRestDocumentationConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.FileSystemUtils; @@ -87,23 +89,22 @@ private Condition contentContaining(String toContain) { } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsRestAssuredConfigurationCustomizer { + public static class CustomizationConfiguration { - @Override - public void customize(RestAssuredRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocumentationResultHandler restDocumentation() { + return MockMvcRestDocumentation.document("{method-name}"); } - } - - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsRestAssuredConfigurationCustomizer { + @Bean + public RestDocsRestAssuredConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); + } - @Override - public void customize(RestAssuredRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsRestAssuredConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 68cd9cb96161..8dbe16ae673c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -26,8 +26,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; -import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.FileSystemUtils; @@ -74,23 +76,22 @@ private Condition contentContaining(String toContain) { } @TestConfiguration - public static class CustomizationConfiguration - implements RestDocsWebTestClientConfigurationCustomizer { + public static class CustomizationConfiguration { - @Override - public void customize(WebTestClientRestDocumentationConfigurer configurer) { - configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); + @Bean + public RestDocumentationResultHandler restDocumentation() { + return MockMvcRestDocumentation.document("{method-name}"); } - } - - @TestConfiguration - public static class CustomizationConfiguration2 - implements RestDocsWebTestClientConfigurationCustomizer { + @Bean + public RestDocsWebTestClientConfigurationCustomizer templateFormatCustomizer() { + return (configurer) -> configurer.snippets() + .withTemplateFormat(TemplateFormats.markdown()); + } - @Override - public void customize(WebTestClientRestDocumentationConfigurer configurer) { - configurer.snippets().withAdditionalDefaults( + @Bean + public RestDocsWebTestClientConfigurationCustomizer defaultSnippetsCustomizer() { + return (configurer) -> configurer.snippets().withAdditionalDefaults( responseFields(fieldWithPath("_links.self").description("Main URL"))); } From 91e3856947d89dec6c2580e79d6f9741efa37623 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 10:52:09 +0200 Subject: [PATCH 368/701] Polish --- .../boot/autoconfigure/task/TaskProperties.java | 2 +- .../task/TaskExecutorAutoConfigurationTests.java | 5 ++--- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java index 84e38a369e8e..d06b0e4e8ce3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java @@ -33,7 +33,7 @@ public class TaskProperties { /** * Prefix to use for the names of newly created threads. */ - private String threadNamePrefix = "executor-"; + private String threadNamePrefix = "task-"; public Pool getPool() { return this.pool; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java index be3a7c9bbbe3..dc23f532e110 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java @@ -132,14 +132,13 @@ public void taskExecutorBuilderShouldApplyCustomizer() { @Test public void enableAsyncUsesAutoConfiguredOneByDefault() { - this.contextRunner - .withPropertyValues("spring.task.thread-name-prefix=executor-test-") + this.contextRunner.withPropertyValues("spring.task.thread-name-prefix=task-test-") .withUserConfiguration(AsyncConfiguration.class, TestBean.class) .run((context) -> { assertThat(context).hasSingleBean(TaskExecutor.class); TestBean bean = context.getBean(TestBean.class); String text = bean.echo("something").get(); - assertThat(text).contains("executor-test-").contains("something"); + assertThat(text).contains("task-test-").contains("something"); }); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 2bbd68963b3a..54a561bdaa21 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -167,7 +167,7 @@ content into your application. Rather, pick only the properties that you need. spring.task.pool.keep-alive=60s # Time limit for which threads may remain idle before being terminated. spring.task.pool.max-size= # Maximum allowed number of threads. If tasks are filling up the queue, the pool can expand up to that size to accommodate the load. Ignored if the queue is unbounded. spring.task.pool.queue-capacity= # Queue capacity. An unbounded capacity does not increase the pool and therefore ignores the "max-size" property. - spring.task.thread-name-prefix=executor- # Prefix to use for the names of newly created threads. + spring.task.thread-name-prefix=task # Prefix to use for the names of newly created threads. # ---------------------------------------- # WEB PROPERTIES From 5c47719e50dde9255fb46fe6de0480897389c53f Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 10 Aug 2018 17:09:25 +0900 Subject: [PATCH 369/701] Add "With an Immediate Pull Request" This commit also reorganises the "Please DO NOT Raise an Issue" cases. Closes gh-14035 --- .github/ISSUE_TEMPLATE.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f1163e8854cc..f6a5cb821955 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,9 +2,16 @@ Thanks for raising a Spring Boot issue. Please take the time to review the following categories as some of them do not apply here. -❓Question +🙅 "Please DO NOT Raise an Issue" Cases +- Question STOP!! Please ask questions about how to use something, or to understand why something isn't working as you expect it to, on Stack Overflow using the spring-boot tag. +- Security Vulnerability +STOP!! Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly. +- Managed Dependency Upgrade +You DO NOT need to raise an issue for a managed dependency version upgrade as there's a semi-automatic process for checking managed dependencies for new versions before a release. BUT pull requests for upgrades that are more involved than just a version property change are still most welcome. +- With an Immediate Pull Request +An issue will be closed as a duplicate of the immediate pull request, so you don't have to raise an issue if you plan to create a pull request immediately. 🐞 Bug report Please provide details of the problem, including the version of Spring Boot that you @@ -12,13 +19,7 @@ are using. If possible, please provide a test case or sample application that re the problem. This makes it much easier for us to diagnose the problem and to verify that we have fixed it. -🚨 Security Vulnerability -STOP!! Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly. - 🎁 Enhancement Please start by describing the problem that you are trying to solve. There may already be a solution, or there may be a way to solve it that you hadn't considered. - -🙅 Managed dependency upgrade -You DO NOT need to raise an issue for a managed dependency version upgrade as there's a semi-automatic process for checking managed dependencies for new versions before a release. But pull requests for upgrades that are more involved than just a version property change are still most welcome. --> From 0cf1749e8583d42af92d57d9cf9736f8db40b840 Mon Sep 17 00:00:00 2001 From: artsiom Date: Sun, 12 Aug 2018 15:53:05 +0300 Subject: [PATCH 370/701] Allow properties to be configured using slice test annotations See gh-14052 --- .../autoconfigure/data/ldap/DataLdapTest.java | 12 +++- .../ldap/DataLdapTestContextBootstrapper.java | 40 +++++++++++ .../data/mongo/DataMongoTest.java | 12 +++- .../DataMongoTestContextBootstrapper.java | 40 +++++++++++ .../data/neo4j/DataNeo4jTest.java | 12 +++- .../DataNeo4jTestContextBootstrapper.java | 40 +++++++++++ .../data/redis/DataRedisTest.java | 12 +++- .../DataRedisTestContextBootstrapper.java | 40 +++++++++++ .../test/autoconfigure/jdbc/JdbcTest.java | 12 +++- .../jdbc/JdbcTestContextBootstrapper.java | 40 +++++++++++ .../test/autoconfigure/jooq/JooqTest.java | 12 +++- .../jooq/JooqTestContextBootstrapper.java | 40 +++++++++++ .../test/autoconfigure/json/JsonTest.java | 11 ++- .../json/JsonTestContextBootstrapper.java | 40 +++++++++++ .../autoconfigure/orm/jpa/DataJpaTest.java | 12 +++- .../jpa/DataJpaTestContextBootstrapper.java | 40 +++++++++++ .../web/client/RestClientTest.java | 12 +++- .../RestClientTestContextBootstrapper.java | 40 +++++++++++ .../web/reactive/WebFluxTest.java | 9 +++ .../WebFluxTestContextBootstrapper.java | 14 +++- .../autoconfigure/web/servlet/WebMvcTest.java | 9 +++ .../WebMvcTestContextBootstrapper.java | 14 +++- ...ataLdapTestEnvironmentPropertiesTests.java | 46 +++++++++++++ ...taMongoTestEnvironmentPropertiesTests.java | 46 +++++++++++++ ...taNeo4jTestEnvironmentPropertiesTests.java | 69 +++++++++++++++++++ ...taRedisTestEnvironmentPropertiesTests.java | 68 ++++++++++++++++++ .../JdbcTestEnvironmentPropertiesTests.java | 46 +++++++++++++ .../JooqTestEnvironmentPropertiesTests.java | 46 +++++++++++++ .../JsonTestEnvironmentPropertiesTests.java | 46 +++++++++++++ ...DataJpaTestEnvironmentPropertiesTests.java | 46 +++++++++++++ ...tClientTestEnvironmentPropertiesTests.java | 46 +++++++++++++ ...WebFluxTestEnvironmentPropertiesTests.java | 46 +++++++++++++ .../WebMvcTestEnvironmentPropertiesTests.java | 46 +++++++++++++ 33 files changed, 1044 insertions(+), 20 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java index 1f1d3d349e19..d891d2f3c8a7 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java @@ -30,9 +30,9 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -48,13 +48,14 @@ * LDAP process (if available). * * @author Eddú Meléndez + * @author Artsiom Yudovin * @since 2.0.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(DataLdapTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataLdapTypeExcludeFilter.class) @@ -63,6 +64,13 @@ @ImportAutoConfiguration public @interface DataLdapTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java new file mode 100644 index 000000000000..dd42e90d4749 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.ldap; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataLdapTest @DataLdapTest} support. + * + * @author Artsiom Yudovin + */ +public class DataLdapTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataLdapTest annotation = getDataLdapTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private DataLdapTest getDataLdapTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, DataLdapTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java index 8e2d7603f31f..df9033ebbbec 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java @@ -30,9 +30,9 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -49,13 +49,14 @@ * * @author Michael Simons * @author Stephane Nicoll + * @author Artsiom Yudovin * @since 1.5.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(DataMongoTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataMongoTypeExcludeFilter.class) @@ -64,6 +65,13 @@ @ImportAutoConfiguration public @interface DataMongoTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java new file mode 100644 index 000000000000..2078a307f673 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.mongo; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataMongoTest @DataMongoTest} support. + * + * @author Artsiom Yudovin + */ +public class DataMongoTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataMongoTest annotation = getDataMongoTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private DataMongoTest getDataMongoTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, DataMongoTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java index c31164d431b3..1a5cf582d644 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java @@ -30,9 +30,9 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; @@ -51,13 +51,14 @@ * * @author Eddú Meléndez * @author Stephane Nicoll + * @author Artsiom Yudovin * @since 2.0.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(DataNeo4jTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataNeo4jTypeExcludeFilter.class) @@ -67,6 +68,13 @@ @ImportAutoConfiguration public @interface DataNeo4jTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java new file mode 100644 index 000000000000..ff6e1bfda61e --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.neo4j; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataNeo4jTest @DataNeo4jTest} support. + * + * @author Artsiom Yudovin + */ +public class DataNeo4jTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataNeo4jTest annotation = getDataNeo4jTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private DataNeo4jTest getDataNeo4jTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, DataNeo4jTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java index 2fa21a901048..fe2c06a65b18 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java @@ -30,9 +30,9 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -45,13 +45,14 @@ * configuration relevant to Redis tests. * * @author Jayaram Pradhan + * @author Artsiom Yudovin * @since 2.0.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(DataRedisTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataRedisTypeExcludeFilter.class) @@ -60,6 +61,13 @@ @ImportAutoConfiguration public @interface DataRedisTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java new file mode 100644 index 000000000000..9a102ba36c2a --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.redis; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataRedisTest @DataRedisTest} support. + * + * @author Artsiom Yudovin + */ +public class DataRedisTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataRedisTest annotation = getDataRedisTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private DataRedisTest getDataRedisTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, DataRedisTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java index 39b0747fae4c..d5d876f0eeee 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java @@ -31,9 +31,9 @@ import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; @@ -57,6 +57,7 @@ * annotation. * * @author Stephane Nicoll + * @author Artsiom Yudovin * @see AutoConfigureJdbc * @see AutoConfigureTestDatabase * @see AutoConfigureCache @@ -65,7 +66,7 @@ @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(JdbcTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(JdbcTypeExcludeFilter.class) @@ -76,6 +77,13 @@ @ImportAutoConfiguration public @interface JdbcTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java new file mode 100644 index 000000000000..35fbf276e888 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.jdbc; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link JdbcTest @JdbcTest} support. + * + * @author Artsiom Yudovin + */ +public class JdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + JdbcTest annotation = getJdbcAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private JdbcTest getJdbcAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, JdbcTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java index 5821db890a0e..41d6e289e773 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java @@ -30,9 +30,9 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; @@ -52,13 +52,14 @@ * * @author Michael Simons * @author Stephane Nicoll + * @author Artsiom Yudovin * @since 2.0.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(JooqTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(JooqTypeExcludeFilter.class) @@ -67,6 +68,13 @@ @ImportAutoConfiguration public @interface JooqTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java new file mode 100644 index 000000000000..46f1767524e7 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.jooq; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link JooqTest @JooqTest} support. + * + * @author Artsiom Yudovin + */ +public class JooqTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + JooqTest annotation = getJooqTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private JooqTest getJooqTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, JooqTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java index d1eb9048fb42..ebeebc51fb0c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java @@ -28,12 +28,12 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.boot.test.json.GsonTester; import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.json.JsonbTester; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; /** @@ -60,7 +60,7 @@ @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(JsonTestContextBootstrapper.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(JsonExcludeFilter.class) @AutoConfigureCache @@ -69,6 +69,13 @@ @ImportAutoConfiguration public @interface JsonTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default only diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java new file mode 100644 index 000000000000..72f885beb7de --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.json; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link JsonTest @JsonTest} support. + * + * @author Artsiom Yudovin + */ +public class JsonTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + JsonTest annotation = getJsonTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private JsonTest getJsonTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, JsonTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java index c3f935f286af..f7a24b379792 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java @@ -33,9 +33,9 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; @@ -59,6 +59,7 @@ * annotation. * * @author Phillip Webb + * @author Artsiom Yudovin * @see AutoConfigureDataJpa * @see AutoConfigureTestDatabase * @see AutoConfigureTestEntityManager @@ -68,7 +69,7 @@ @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(DataJpaTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(DataJpaTypeExcludeFilter.class) @@ -80,6 +81,13 @@ @ImportAutoConfiguration public @interface DataJpaTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * If SQL output should be logged. * @return if SQL is logged diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java new file mode 100644 index 000000000000..49727fc87d60 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.orm.jpa; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataJpaTest @DataJpaTest} support. + * + * @author Artsiom Yudovin + */ +public class DataJpaTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataJpaTest annotation = getDataJpaAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private DataJpaTest getDataJpaAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, DataJpaTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java index 853b44fc4b0b..2d21bb4e7235 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java @@ -30,10 +30,10 @@ import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; -import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.ComponentScan; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -60,13 +60,14 @@ * * @author Stephane Nicoll * @author Phillip Webb + * @author Artsiom Yudovin * @since 1.4.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@BootstrapWith(SpringBootTestContextBootstrapper.class) +@BootstrapWith(RestClientTestContextBootstrapper.class) @ExtendWith(SpringExtension.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(RestClientExcludeFilter.class) @@ -76,6 +77,13 @@ @ImportAutoConfiguration public @interface RestClientTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Specifies the components to test. This is an alias of {@link #components()} which * can be used for brevity if no other attributes are defined. See diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java new file mode 100644 index 000000000000..f9c55c5f9b42 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.web.client; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link RestClientTest @RestClientTest} support. + * + * @author Artsiom Yudovin + */ +public class RestClientTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + RestClientTest annotation = getRestClientAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private RestClientTest getRestClientAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, RestClientTest.class); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java index bcc1be8a6ba6..d339b2cdc140 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java @@ -35,6 +35,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.reactive.server.WebTestClient; @@ -64,6 +65,7 @@ * annotation. * * @author Stephane Nicoll + * @author Artsiom Yudovin * @since 2.0.0 * @see AutoConfigureWebFlux * @see AutoConfigureWebTestClient @@ -82,6 +84,13 @@ @ImportAutoConfiguration public @interface WebFluxTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Specifies the controllers to test. This is an alias of {@link #controllers()} which * can be used for brevity if no other attributes are defined. See diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java index 95f44f5877ee..e423c0b77ee9 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java @@ -18,6 +18,7 @@ import org.springframework.boot.test.context.ReactiveWebMergedContextConfiguration; import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.TestContextBootstrapper; @@ -25,8 +26,9 @@ * {@link TestContextBootstrapper} for {@link WebFluxTest @WebFluxTest} support. * * @author Stephane Nicoll + * @author Artsiom Yudovin */ -class WebFluxTestContextBootstrapper extends SpringBootTestContextBootstrapper { +public class WebFluxTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected MergedContextConfiguration processMergedContextConfiguration( @@ -35,4 +37,14 @@ protected MergedContextConfiguration processMergedContextConfiguration( super.processMergedContextConfiguration(mergedConfig)); } + @Override + protected String[] getProperties(Class testClass) { + WebFluxTest annotation = getWebFluxTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private WebFluxTest getWebFluxTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, WebFluxTest.class); + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java index f00702adc61e..dcca84531a89 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java @@ -35,6 +35,7 @@ import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; @@ -65,6 +66,7 @@ * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} rather than this annotation. * * @author Phillip Webb + * @author Artsiom Yudovin * @see AutoConfigureWebMvc * @see AutoConfigureMockMvc * @see AutoConfigureCache @@ -84,6 +86,13 @@ @ImportAutoConfiguration public @interface WebMvcTest { + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + /** * Specifies the controllers to test. This is an alias of {@link #controllers()} which * can be used for brevity if no other attributes are defined. See diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java index cac57002a67e..6ca7e383b82a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java @@ -17,6 +17,7 @@ package org.springframework.boot.test.autoconfigure.web.servlet; import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.TestContextBootstrapper; import org.springframework.test.context.web.WebMergedContextConfiguration; @@ -25,8 +26,9 @@ * {@link TestContextBootstrapper} for {@link WebMvcTest @WebMvcTest} support. * * @author Phillip Webb + * @author Artsiom Yudovin */ -class WebMvcTestContextBootstrapper extends SpringBootTestContextBootstrapper { +public class WebMvcTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected MergedContextConfiguration processMergedContextConfiguration( @@ -35,4 +37,14 @@ protected MergedContextConfiguration processMergedContextConfiguration( super.processMergedContextConfiguration(mergedConfig), ""); } + @Override + protected String[] getProperties(Class testClass) { + WebMvcTest annotation = getWebMvcTestAnnotation(testClass); + return (annotation != null) ? annotation.properties() : null; + } + + private WebMvcTest getWebMvcTestAnnotation(Class testClass) { + return AnnotatedElementUtils.getMergedAnnotation(testClass, WebMvcTest.class); + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..cef246846e74 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.ldap; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link DataLdapTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@DataLdapTest(properties = "spring.profiles.active=test") +public class DataLdapTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..59814b6ff73b --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.mongo; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link DataMongoTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@DataMongoTest(properties = "spring.profiles.active=test") +public class DataMongoTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..1a7130e49b71 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.neo4j; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.boot.testsupport.testcontainers.Neo4jContainer; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link DataNeo4jTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(initializers = DataNeo4jTestEnvironmentPropertiesTests.Initializer.class) +@DataNeo4jTest(properties = "spring.profiles.active=test") +public class DataNeo4jTestEnvironmentPropertiesTests { + + @ClassRule + public static Neo4jContainer neo4j = new Neo4jContainer(); + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + + static class Initializer + implements ApplicationContextInitializer { + + @Override + public void initialize( + ConfigurableApplicationContext configurableApplicationContext) { + TestPropertyValues + .of("spring.data.neo4j.uri=bolt://localhost:" + neo4j.getMappedPort()) + .applyTo(configurableApplicationContext.getEnvironment()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..e06d837bdb3b --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.data.redis; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.boot.testsupport.testcontainers.RedisContainer; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link DataRedisTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(initializers = DataRedisTestEnvironmentPropertiesTests.Initializer.class) +@DataRedisTest(properties = "spring.profiles.active=test") +public class DataRedisTestEnvironmentPropertiesTests { + + @ClassRule + public static RedisContainer redis = new RedisContainer(); + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + + static class Initializer + implements ApplicationContextInitializer { + + @Override + public void initialize( + ConfigurableApplicationContext configurableApplicationContext) { + TestPropertyValues.of("spring.redis.port=" + redis.getMappedPort()) + .applyTo(configurableApplicationContext.getEnvironment()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..98546a9de0bb --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.jdbc; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link JdbcTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@JdbcTest(properties = "spring.profiles.active=test") +public class JdbcTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..8fca87a66246 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.jooq; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link JooqTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@JooqTest(properties = "spring.profiles.active=test") +public class JooqTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..42426e01d9ee --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.json; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link JsonTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@JsonTest(properties = "spring.profiles.active=test") +public class JsonTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..12e6dcb2c40a --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.orm.jpa; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link DataJpaTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@DataJpaTest(properties = "spring.profiles.active=test") +public class DataJpaTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..b839e61cfeec --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.web.client; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link RestClientTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@RestClientTest(properties = "spring.profiles.active=test") +public class RestClientTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..7cb4133ace22 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.web.reactive; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link WebFluxTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@WebFluxTest(properties = "spring.profiles.active=test") +public class WebFluxTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java new file mode 100644 index 000000000000..136b178e26e5 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 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.test.autoconfigure.web.servlet; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Add properties to {@link Environment} via {@link WebMvcTest}. + * + * @author Artsiom Yudovin + */ +@RunWith(SpringRunner.class) +@WebMvcTest(properties = "spring.profiles.active=test") +public class WebMvcTestEnvironmentPropertiesTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWitNewProfile() { + String profile = this.environment.getActiveProfiles()[0]; + assertThat(profile).isEqualTo("test"); + } + +} From 075a745e32af7d2928289cac16dadacca0a9b41a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Aug 2018 11:27:09 +0100 Subject: [PATCH 371/701] Polish "Allow properties to be configured using slice test annotations" Closes gh-14052 --- .../src/main/asciidoc/spring-boot-features.adoc | 6 ++++-- .../test/autoconfigure/data/ldap/DataLdapTest.java | 1 + .../data/ldap/DataLdapTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/data/mongo/DataMongoTest.java | 1 + .../data/mongo/DataMongoTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/data/neo4j/DataNeo4jTest.java | 1 + .../data/neo4j/DataNeo4jTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/data/redis/DataRedisTest.java | 1 + .../data/redis/DataRedisTestContextBootstrapper.java | 11 ++++------- .../boot/test/autoconfigure/jdbc/JdbcTest.java | 1 + .../jdbc/JdbcTestContextBootstrapper.java | 11 ++++------- .../boot/test/autoconfigure/jooq/JooqTest.java | 1 + .../jooq/JooqTestContextBootstrapper.java | 11 ++++------- .../boot/test/autoconfigure/json/JsonTest.java | 4 +++- .../json/JsonTestContextBootstrapper.java | 11 ++++------- .../boot/test/autoconfigure/orm/jpa/DataJpaTest.java | 1 + .../orm/jpa/DataJpaTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/web/client/RestClientTest.java | 1 + .../web/client/RestClientTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/web/reactive/WebFluxTest.java | 1 + .../web/reactive/WebFluxTestContextBootstrapper.java | 11 ++++------- .../test/autoconfigure/web/servlet/WebMvcTest.java | 1 + .../web/servlet/WebMvcTestContextBootstrapper.java | 11 ++++------- ...va => DataLdapTestPropertiesIntegrationTests.java} | 7 ++++--- ...a => DataMongoTestPropertiesIntegrationTests.java} | 7 ++++--- ...a => DataNeo4jTestPropertiesIntegrationTests.java} | 9 +++++---- ...a => DataRedisTestPropertiesIntegrationTests.java} | 9 +++++---- ...s.java => JdbcTestPropertiesIntegrationTests.java} | 7 ++++--- ...s.java => JooqTestPropertiesIntegrationTests.java} | 7 ++++--- ...s.java => JsonTestPropertiesIntegrationTests.java} | 7 ++++--- ...ava => DataJpaTestPropertiesIntegrationTests.java} | 7 ++++--- ... => RestClientTestPropertiesIntegrationTests.java} | 7 ++++--- ...ava => WebFluxTestPropertiesIntegrationTests.java} | 7 ++++--- ...java => WebMvcTestPropertiesIntegrationTests.java} | 7 ++++--- 34 files changed, 107 insertions(+), 115 deletions(-) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/{DataLdapTestEnvironmentPropertiesTests.java => DataLdapTestPropertiesIntegrationTests.java} (84%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/{DataMongoTestEnvironmentPropertiesTests.java => DataMongoTestPropertiesIntegrationTests.java} (84%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/{DataNeo4jTestEnvironmentPropertiesTests.java => DataNeo4jTestPropertiesIntegrationTests.java} (86%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/{DataRedisTestEnvironmentPropertiesTests.java => DataRedisTestPropertiesIntegrationTests.java} (86%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/{JdbcTestEnvironmentPropertiesTests.java => JdbcTestPropertiesIntegrationTests.java} (85%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/{JooqTestEnvironmentPropertiesTests.java => JooqTestPropertiesIntegrationTests.java} (85%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/{JsonTestEnvironmentPropertiesTests.java => JsonTestPropertiesIntegrationTests.java} (85%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/{DataJpaTestEnvironmentPropertiesTests.java => DataJpaTestPropertiesIntegrationTests.java} (85%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/{RestClientTestEnvironmentPropertiesTests.java => RestClientTestPropertiesIntegrationTests.java} (84%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/{WebFluxTestEnvironmentPropertiesTests.java => WebFluxTestPropertiesIntegrationTests.java} (85%) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/{WebMvcTestEnvironmentPropertiesTests.java => WebMvcTestPropertiesIntegrationTests.java} (85%) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 3788b7230bf6..0fbe182686f4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -403,8 +403,10 @@ sensible overriding of values. Properties are considered in the following order: on your home directory (`~/.spring-boot-devtools.properties` when devtools is active). . {spring-javadoc}/test/context/TestPropertySource.{dc-ext}[`@TestPropertySource`] annotations on your tests. -. {dc-spring-boot-test}/context/SpringBootTest.{dc-ext}[`@SpringBootTest#properties`] -annotation attribute on your tests. +. `properties` attribute on your tests. Available on +{dc-spring-boot-test}/context/SpringBootTest.{dc-ext}[`@SpringBootTest`] and the +<>. . Command line arguments. . Properties from `SPRING_APPLICATION_JSON` (inline JSON embedded in an environment variable or system property). diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java index d891d2f3c8a7..97fc11958164 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTest.java @@ -68,6 +68,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java index dd42e90d4749..f73a8648ba94 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class DataLdapTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class DataLdapTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - DataLdapTest annotation = getDataLdapTestAnnotation(testClass); + DataLdapTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataLdapTest.class); return (annotation != null) ? annotation.properties() : null; } - private DataLdapTest getDataLdapTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, DataLdapTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java index df9033ebbbec..ac56ab7845a5 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTest.java @@ -69,6 +69,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java index 2078a307f673..f926cee182d4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class DataMongoTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class DataMongoTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - DataMongoTest annotation = getDataMongoTestAnnotation(testClass); + DataMongoTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataMongoTest.class); return (annotation != null) ? annotation.properties() : null; } - private DataMongoTest getDataMongoTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, DataMongoTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java index 1a5cf582d644..953ce18effd8 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTest.java @@ -72,6 +72,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java index ff6e1bfda61e..658f523e4bd1 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class DataNeo4jTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class DataNeo4jTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - DataNeo4jTest annotation = getDataNeo4jTestAnnotation(testClass); + DataNeo4jTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataNeo4jTest.class); return (annotation != null) ? annotation.properties() : null; } - private DataNeo4jTest getDataNeo4jTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, DataNeo4jTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java index fe2c06a65b18..5f940ca15bca 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTest.java @@ -65,6 +65,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java index 9a102ba36c2a..fdf6d8008308 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class DataRedisTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class DataRedisTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - DataRedisTest annotation = getDataRedisTestAnnotation(testClass); + DataRedisTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataRedisTest.class); return (annotation != null) ? annotation.properties() : null; } - private DataRedisTest getDataRedisTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, DataRedisTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java index d5d876f0eeee..5ad15c0ffa34 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.java @@ -81,6 +81,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java index 35fbf276e888..d51cec257d2f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class JdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class JdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - JdbcTest annotation = getJdbcAnnotation(testClass); + JdbcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + JdbcTest.class); return (annotation != null) ? annotation.properties() : null; } - private JdbcTest getJdbcAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, JdbcTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java index 41d6e289e773..9eec1a00e2a2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTest.java @@ -72,6 +72,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java index 46f1767524e7..b35b5c4af656 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class JooqTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class JooqTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - JooqTest annotation = getJooqTestAnnotation(testClass); + JooqTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + JooqTest.class); return (annotation != null) ? annotation.properties() : null; } - private JooqTest getJooqTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, JooqTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java index ebeebc51fb0c..d66e1a542aa1 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,6 +51,7 @@ * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters} annotation. * * @author Phillip Webb + * @author Artsiom Yudovin * @see AutoConfigureJson * @see AutoConfigureJsonTesters * @see AutoConfigureCache @@ -73,6 +74,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java index 72f885beb7de..d2bffb667e70 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class JsonTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class JsonTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - JsonTest annotation = getJsonTestAnnotation(testClass); + JsonTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + JsonTest.class); return (annotation != null) ? annotation.properties() : null; } - private JsonTest getJsonTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, JsonTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java index f7a24b379792..9255b0bb604f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java @@ -85,6 +85,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java index 49727fc87d60..c49ca01c9f98 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class DataJpaTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class DataJpaTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - DataJpaTest annotation = getDataJpaAnnotation(testClass); + DataJpaTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataJpaTest.class); return (annotation != null) ? annotation.properties() : null; } - private DataJpaTest getDataJpaAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, DataJpaTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java index 2d21bb4e7235..9d27fb33981e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTest.java @@ -81,6 +81,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java index f9c55c5f9b42..4679afa6d785 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -25,16 +25,13 @@ * * @author Artsiom Yudovin */ -public class RestClientTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class RestClientTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected String[] getProperties(Class testClass) { - RestClientTest annotation = getRestClientAnnotation(testClass); + RestClientTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + RestClientTest.class); return (annotation != null) ? annotation.properties() : null; } - private RestClientTest getRestClientAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, RestClientTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java index d339b2cdc140..3d403cfa7fd6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTest.java @@ -88,6 +88,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java index e423c0b77ee9..6ee1e41fcb93 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -28,7 +28,7 @@ * @author Stephane Nicoll * @author Artsiom Yudovin */ -public class WebFluxTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class WebFluxTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected MergedContextConfiguration processMergedContextConfiguration( @@ -39,12 +39,9 @@ protected MergedContextConfiguration processMergedContextConfiguration( @Override protected String[] getProperties(Class testClass) { - WebFluxTest annotation = getWebFluxTestAnnotation(testClass); + WebFluxTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + WebFluxTest.class); return (annotation != null) ? annotation.properties() : null; } - private WebFluxTest getWebFluxTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, WebFluxTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java index dcca84531a89..49550a6c539a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java @@ -90,6 +90,7 @@ * Properties in form {@literal key=value} that should be added to the Spring * {@link Environment} before the test runs. * @return the properties to add + * @since 2.1.0 */ String[] properties() default {}; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java index 6ca7e383b82a..ed8cde0e7ad2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestContextBootstrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -28,7 +28,7 @@ * @author Phillip Webb * @author Artsiom Yudovin */ -public class WebMvcTestContextBootstrapper extends SpringBootTestContextBootstrapper { +class WebMvcTestContextBootstrapper extends SpringBootTestContextBootstrapper { @Override protected MergedContextConfiguration processMergedContextConfiguration( @@ -39,12 +39,9 @@ protected MergedContextConfiguration processMergedContextConfiguration( @Override protected String[] getProperties(Class testClass) { - WebMvcTest annotation = getWebMvcTestAnnotation(testClass); + WebMvcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + WebMvcTest.class); return (annotation != null) ? annotation.properties() : null; } - private WebMvcTest getWebMvcTestAnnotation(Class testClass) { - return AnnotatedElementUtils.getMergedAnnotation(testClass, WebMvcTest.class); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java similarity index 84% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java index cef246846e74..3eaa4334d11a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link DataLdapTest}. + * Tests for the {@link DataLdapTest#properties properties} attribute of + * {@link DataLdapTest @DataLdapTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @DataLdapTest(properties = "spring.profiles.active=test") -public class DataLdapTestEnvironmentPropertiesTests { +public class DataLdapTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java similarity index 84% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java index 59814b6ff73b..78016e032336 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link DataMongoTest}. + * Tests for the {@link DataMongoTest#properties properties} attribute of + * {@link DataMongoTest @DataMongoTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @DataMongoTest(properties = "spring.profiles.active=test") -public class DataMongoTestEnvironmentPropertiesTests { +public class DataMongoTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java similarity index 86% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index 1a7130e49b71..592bc8500e44 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,14 +32,15 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link DataNeo4jTest}. + * Tests for the {@link DataNeo4jTest#properties properties} attribute of + * {@link DataNeo4jTest @DataNeo4jTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) -@ContextConfiguration(initializers = DataNeo4jTestEnvironmentPropertiesTests.Initializer.class) +@ContextConfiguration(initializers = DataNeo4jTestPropertiesIntegrationTests.Initializer.class) @DataNeo4jTest(properties = "spring.profiles.active=test") -public class DataNeo4jTestEnvironmentPropertiesTests { +public class DataNeo4jTestPropertiesIntegrationTests { @ClassRule public static Neo4jContainer neo4j = new Neo4jContainer(); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java similarity index 86% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java index e06d837bdb3b..e6520c6fd2fb 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,14 +32,15 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link DataRedisTest}. + * Tests for the {@link DataRedisTest#properties properties} attribute of + * {@link DataRedisTest @DataRedisTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) -@ContextConfiguration(initializers = DataRedisTestEnvironmentPropertiesTests.Initializer.class) +@ContextConfiguration(initializers = DataRedisTestPropertiesIntegrationTests.Initializer.class) @DataRedisTest(properties = "spring.profiles.active=test") -public class DataRedisTestEnvironmentPropertiesTests { +public class DataRedisTestPropertiesIntegrationTests { @ClassRule public static RedisContainer redis = new RedisContainer(); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java index 98546a9de0bb..0b1b9cea0939 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link JdbcTest}. + * Tests for the {@link JdbcTest#properties properties} attribute of + * {@link JdbcTest @JdbcTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @JdbcTest(properties = "spring.profiles.active=test") -public class JdbcTestEnvironmentPropertiesTests { +public class JdbcTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java index 8fca87a66246..ef2174d7b368 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link JooqTest}. + * Tests for the {@link JooqTest#properties properties} attribute of + * {@link JooqTest @JooqTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @JooqTest(properties = "spring.profiles.active=test") -public class JooqTestEnvironmentPropertiesTests { +public class JooqTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java index 42426e01d9ee..a991712458c6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link JsonTest}. + * Tests for the {@link JsonTest#properties properties} attribute of + * {@link JsonTest @JsonTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @JsonTest(properties = "spring.profiles.active=test") -public class JsonTestEnvironmentPropertiesTests { +public class JsonTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java index 12e6dcb2c40a..622eccabe5bb 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link DataJpaTest}. + * Tests for the {@link DataJpaTest#properties properties} attribute of + * {@link DataJpaTest @DataJpaTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @DataJpaTest(properties = "spring.profiles.active=test") -public class DataJpaTestEnvironmentPropertiesTests { +public class DataJpaTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java similarity index 84% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java index b839e61cfeec..6f27c2548944 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link RestClientTest}. + * Tests for the {@link RestClientTest#properties properties} attribute of + * {@link RestClientTest @RestClientTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @RestClientTest(properties = "spring.profiles.active=test") -public class RestClientTestEnvironmentPropertiesTests { +public class RestClientTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java index 7cb4133ace22..420ea0db869f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link WebFluxTest}. + * Tests for the {@link WebFluxTest#properties properties} attribute of + * {@link WebFluxTest @WebFluxTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @WebFluxTest(properties = "spring.profiles.active=test") -public class WebFluxTestEnvironmentPropertiesTests { +public class WebFluxTestPropertiesIntegrationTests { @Autowired private Environment environment; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java similarity index 85% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java index 136b178e26e5..67cbbb6ce4fe 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestEnvironmentPropertiesTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,13 +26,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Add properties to {@link Environment} via {@link WebMvcTest}. + * Tests for the {@link WebMvcTest#properties properties} attribute of + * {@link WebMvcTest @WebMvcTest}. * * @author Artsiom Yudovin */ @RunWith(SpringRunner.class) @WebMvcTest(properties = "spring.profiles.active=test") -public class WebMvcTestEnvironmentPropertiesTests { +public class WebMvcTestPropertiesIntegrationTests { @Autowired private Environment environment; From 7c43c89e1149aa3170e8cfcc683c432380a2dc03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Proch=C3=A1zka?= Date: Mon, 6 Aug 2018 13:10:06 +0200 Subject: [PATCH 372/701] Stop Elasticsearch REST client from pulling in commons-logging See gh-14004 --- spring-boot-project/spring-boot-dependencies/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4203bdb35ede..534a2e510719 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1806,6 +1806,16 @@ org.elasticsearch.client elasticsearch-rest-high-level-client ${elasticsearch.version} + + + commons-logging + commons-logging + + + org.apache.logging.log4j + log4j-core + + org.firebirdsql.jdbc From bb8dd25d2462308023f9e0e74be3f5600ae45c3e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Aug 2018 12:16:52 +0100 Subject: [PATCH 373/701] Polish "Stop Elasticsearch REST client from pulling in commons-logging" Closes gh-14004 --- .../spring-boot-dependencies/pom.xml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 534a2e510719..4beb37956d68 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1801,22 +1801,18 @@ org.elasticsearch.client elasticsearch-rest-client ${elasticsearch.version} - - - org.elasticsearch.client - elasticsearch-rest-high-level-client - ${elasticsearch.version} commons-logging commons-logging - - org.apache.logging.log4j - log4j-core - + + org.elasticsearch.client + elasticsearch-rest-high-level-client + ${elasticsearch.version} + org.firebirdsql.jdbc jaybird-jdk17 From dcd80c087edc782f86a79a5082a597190fa405b3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 14:34:57 +0200 Subject: [PATCH 374/701] Harmonize task execution naming --- ...va => TaskExecutionAutoConfiguration.java} | 10 +++++----- ...ties.java => TaskExecutionProperties.java} | 5 +++-- .../web/servlet/WebMvcAutoConfiguration.java | 8 ++++---- ... TaskExecutionAutoConfigurationTests.java} | 20 ++++++++++--------- .../servlet/WebMvcAutoConfigurationTests.java | 10 +++++----- .../appendix-application-properties.adoc | 14 ++++++------- .../main/asciidoc/spring-boot-features.adoc | 10 +++++----- 7 files changed, 40 insertions(+), 37 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/{TaskExecutorAutoConfiguration.java => TaskExecutionAutoConfiguration.java} (91%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/{TaskProperties.java => TaskExecutionProperties.java} (96%) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/{TaskExecutorAutoConfigurationTests.java => TaskExecutionAutoConfigurationTests.java} (91%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java similarity index 91% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java index a5c93e413f64..62709f5d0199 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java @@ -40,21 +40,21 @@ */ @ConditionalOnClass(ThreadPoolTaskExecutor.class) @Configuration -@EnableConfigurationProperties(TaskProperties.class) -public class TaskExecutorAutoConfiguration { +@EnableConfigurationProperties(TaskExecutionProperties.class) +public class TaskExecutionAutoConfiguration { /** * Bean name of the application {@link TaskExecutor}. */ public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor"; - private final TaskProperties properties; + private final TaskExecutionProperties properties; private final ObjectProvider taskExecutorCustomizers; private final ObjectProvider taskDecorator; - public TaskExecutorAutoConfiguration(TaskProperties properties, + public TaskExecutionAutoConfiguration(TaskExecutionProperties properties, ObjectProvider taskExecutorCustomizers, ObjectProvider taskDecorator) { this.properties = properties; @@ -65,7 +65,7 @@ public TaskExecutorAutoConfiguration(TaskProperties properties, @Bean @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder() { - TaskProperties.Pool pool = this.properties.getPool(); + TaskExecutionProperties.Pool pool = this.properties.getPool(); return new TaskExecutorBuilder().queueCapacity(pool.getQueueCapacity()) .corePoolSize(pool.getCoreSize()).maxPoolSize(pool.getMaxSize()) .allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionProperties.java similarity index 96% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionProperties.java index d06b0e4e8ce3..437509c540a1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionProperties.java @@ -24,9 +24,10 @@ * Configuration properties for task execution. * * @author Stephane Nicoll + * @since 2.1.0 */ -@ConfigurationProperties("spring.task") -public class TaskProperties { +@ConfigurationProperties("spring.task.execution") +public class TaskExecutionProperties { private final Pool pool = new Pool(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 92677c0a7cbf..f5c2f6a0e529 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -46,7 +46,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; -import org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; @@ -142,7 +142,7 @@ @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, - TaskExecutorAutoConfiguration.class, ValidationAutoConfiguration.class }) + TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { public static final String DEFAULT_PREFIX = ""; @@ -213,9 +213,9 @@ public void configureMessageConverters(List> converters) @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { if (this.beanFactory.containsBean( - TaskExecutorAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) { + TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) { Object taskExecutor = this.beanFactory.getBean( - TaskExecutorAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME); + TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME); if (taskExecutor instanceof AsyncTaskExecutor) { configurer.setTaskExecutor(((AsyncTaskExecutor) taskExecutor)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfigurationTests.java similarity index 91% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfigurationTests.java index dc23f532e110..710b7ef9bcf4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfigurationTests.java @@ -45,24 +45,25 @@ import static org.mockito.Mockito.verify; /** - * Tests for {@link TaskExecutorAutoConfiguration}. + * Tests for {@link TaskExecutionAutoConfiguration}. * * @author Stephane Nicoll */ -public class TaskExecutorAutoConfigurationTests { +public class TaskExecutionAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( - AutoConfigurations.of(TaskExecutorAutoConfiguration.class)); + AutoConfigurations.of(TaskExecutionAutoConfiguration.class)); @Test public void taskExecutorBuilderShouldApplyCustomSettings() { this.contextRunner - .withPropertyValues("spring.task.pool.queue-capacity=10", - "spring.task.pool.core-size=2", "spring.task.pool.max-size=4", - "spring.task.pool.allow-core-thread-timeout=true", - "spring.task.pool.keep-alive=5s", - "spring.task.thread-name-prefix=mytest-") + .withPropertyValues("spring.task.execution.pool.queue-capacity=10", + "spring.task.execution.pool.core-size=2", + "spring.task.execution.pool.max-size=4", + "spring.task.execution.pool.allow-core-thread-timeout=true", + "spring.task.execution.pool.keep-alive=5s", + "spring.task.execution.thread-name-prefix=mytest-") .run(assertTaskExecutor((taskExecutor) -> { DirectFieldAccessor dfa = new DirectFieldAccessor(taskExecutor); assertThat(dfa.getPropertyValue("queueCapacity")).isEqualTo(10); @@ -132,7 +133,8 @@ public void taskExecutorBuilderShouldApplyCustomizer() { @Test public void enableAsyncUsesAutoConfiguredOneByDefault() { - this.contextRunner.withPropertyValues("spring.task.thread-name-prefix=task-test-") + this.contextRunner + .withPropertyValues("spring.task.execution.thread-name-prefix=task-test-") .withUserConfiguration(AsyncConfiguration.class, TestBean.class) .run((context) -> { assertThat(context).hasSingleBean(TaskExecutor.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 63d4cf9dafe2..8b48bf502fda 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -37,7 +37,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; -import org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter; @@ -479,7 +479,7 @@ public void customAsyncRequestTimeout() { public void asyncTaskExecutorWithApplicationTaskExecutor() { this.contextRunner .withConfiguration( - AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + AutoConfigurations.of(TaskExecutionAutoConfiguration.class)) .run((context) -> { assertThat(context).hasSingleBean(AsyncTaskExecutor.class); assertThat(ReflectionTestUtils.getField( @@ -494,7 +494,7 @@ public void asyncTaskExecutorWithNonMatchApplicationTaskExecutorBean() { this.contextRunner .withUserConfiguration(CustomApplicationTaskExecutorConfig.class) .withConfiguration( - AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + AutoConfigurations.of(TaskExecutionAutoConfiguration.class)) .run((context) -> { assertThat(context).doesNotHaveBean(AsyncTaskExecutor.class); assertThat(ReflectionTestUtils.getField( @@ -508,7 +508,7 @@ public void asyncTaskExecutorWithNonMatchApplicationTaskExecutorBean() { public void asyncTaskExecutorWithMvcConfigurerCanOverrideExecutor() { this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class) .withConfiguration( - AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + AutoConfigurations.of(TaskExecutionAutoConfiguration.class)) .run((context) -> { assertThat(ReflectionTestUtils.getField( context.getBean(RequestMappingHandlerAdapter.class), @@ -522,7 +522,7 @@ public void asyncTaskExecutorWithMvcConfigurerCanOverrideExecutor() { public void asyncTaskExecutorWithCustomNonApplicationTaskExecutor() { this.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfig.class) .withConfiguration( - AutoConfigurations.of(TaskExecutorAutoConfiguration.class)) + AutoConfigurations.of(TaskExecutionAutoConfiguration.class)) .run((context) -> { assertThat(context).hasSingleBean(AsyncTaskExecutor.class); assertThat(ReflectionTestUtils.getField( diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 54a561bdaa21..9bc7de154fdb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -161,13 +161,13 @@ content into your application. Rather, pick only the properties that you need. spring.sendgrid.proxy.host= # SendGrid proxy host. spring.sendgrid.proxy.port= # SendGrid proxy port. - # TASK EXECUTION ({sc-spring-boot-autoconfigure}/task/TaskProperties.{sc-ext}[TaskProperties]) - spring.task.pool.allow-core-thread-timeout=true # Whether core threads are allowed to time out. This enables dynamic growing and shrinking of the pool. - spring.task.pool.core-size=8 # Core number of threads. - spring.task.pool.keep-alive=60s # Time limit for which threads may remain idle before being terminated. - spring.task.pool.max-size= # Maximum allowed number of threads. If tasks are filling up the queue, the pool can expand up to that size to accommodate the load. Ignored if the queue is unbounded. - spring.task.pool.queue-capacity= # Queue capacity. An unbounded capacity does not increase the pool and therefore ignores the "max-size" property. - spring.task.thread-name-prefix=task # Prefix to use for the names of newly created threads. + # TASK EXECUTION ({sc-spring-boot-autoconfigure}/task/TaskExecutionProperties.{sc-ext}[TaskExecutionProperties]) + spring.task.execution.pool.allow-core-thread-timeout=true # Whether core threads are allowed to time out. This enables dynamic growing and shrinking of the pool. + spring.task.execution.pool.core-size=8 # Core number of threads. + spring.task.execution.pool.keep-alive=60s # Time limit for which threads may remain idle before being terminated. + spring.task.execution.pool.max-size= # Maximum allowed number of threads. If tasks are filling up the queue, the pool can expand up to that size to accommodate the load. Ignored if the queue is unbounded. + spring.task.execution.pool.queue-capacity= # Queue capacity. An unbounded capacity does not increase the pool and therefore ignores the "max-size" property. + spring.task.execution.thread-name-prefix=task- # Prefix to use for the names of newly created threads. # ---------------------------------------- # WEB PROPERTIES diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 0fbe182686f4..b5663b1c72ee 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6146,14 +6146,14 @@ asynchronous task execution (`@EnableAsync`) and Spring MVC asynchronous request processing. The thread pool uses 8 core threads that can grow and shrink according to the load. Those -default settings can be fine-tuned using the `spring.task` namespace as shown in the -following example: +default settings can be fine-tuned using the `spring.task.execution` namespace as shown in +the following example: [source,properties,indent=0] ---- - spring.task.pool.max-threads=16 - spring.task.pool.queue-capacity=100 - spring.task.pool.keep-alive=10s + spring.task.execution.pool.max-threads=16 + spring.task.execution.pool.queue-capacity=100 + spring.task.execution.pool.keep-alive=10s ---- This changes the thread pool to use a bounded queue so that when the queue is full (100 From de470540ea832091c63d0bbb0045707865ed14ba Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 8 Aug 2018 14:30:42 +0200 Subject: [PATCH 375/701] Add auto-configuration support for TaskScheduler This commit adds support for providing a default ThreadPoolTaskScheduler with sensible defaults. A new TaskSchedulerBuilder is provided with defaults from the `spring.task.scheduler.*` namespace and can be used to create custom instances. If no custom `TaskScheduler` bean is present, `@EnableScheduling` now uses the auto-configured task scheduler. Closes gh-1397 --- .../task/TaskSchedulingAutoConfiguration.java | 63 ++++++ .../task/TaskSchedulingProperties.java | 65 ++++++ .../boot/autoconfigure/task/package-info.java | 2 +- .../main/resources/META-INF/spring.factories | 3 +- .../TaskSchedulingAutoConfigurationTests.java | 180 +++++++++++++++++ .../appendix-application-properties.adoc | 4 + .../main/asciidoc/spring-boot-features.adoc | 10 +- .../boot/task/TaskSchedulerBuilder.java | 187 ++++++++++++++++++ .../boot/task/TaskSchedulerCustomizer.java | 36 ++++ .../boot/task/package-info.java | 4 +- .../boot/task/TaskSchedulerBuilderTests.java | 128 ++++++++++++ 11 files changed, 675 insertions(+), 7 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerCustomizer.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java new file mode 100644 index 000000000000..d31617ac9397 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import java.util.stream.Collectors; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.task.TaskSchedulerBuilder; +import org.springframework.boot.task.TaskSchedulerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.TaskManagementConfigUtils; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link TaskScheduler}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@ConditionalOnClass(ThreadPoolTaskScheduler.class) +@Configuration +@EnableConfigurationProperties(TaskSchedulingProperties.class) +public class TaskSchedulingAutoConfiguration { + + @Bean + @ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) + @ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class }) + public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { + return builder.build(); + } + + @Bean + @ConditionalOnMissingBean + public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, + ObjectProvider taskSchedulerCustomizers) { + return new TaskSchedulerBuilder().poolSize(properties.getPool().getSize()) + .threadNamePrefix(properties.getThreadNamePrefix()).customizers( + taskSchedulerCustomizers.stream().collect(Collectors.toList())); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java new file mode 100644 index 000000000000..27ee57c2acfc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for task scheduling. + * + * @author Stephane Nicoll + */ +@ConfigurationProperties("spring.task.scheduling") +public class TaskSchedulingProperties { + + private final Pool pool = new Pool(); + + /** + * Prefix to use for the names of newly created threads. + */ + private String threadNamePrefix = "scheduling-"; + + public Pool getPool() { + return this.pool; + } + + public String getThreadNamePrefix() { + return this.threadNamePrefix; + } + + public void setThreadNamePrefix(String threadNamePrefix) { + this.threadNamePrefix = threadNamePrefix; + } + + public static class Pool { + + /** + * Maximum allowed number of threads. + */ + private int size = 1; + + public int getSize() { + return this.size; + } + + public void setSize(int size) { + this.size = size; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java index 960bf71f3a06..9e4d59051bfc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for task execution. + * Auto-configuration for task execution and scheduling. */ package org.springframework.boot.autoconfigure.task; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 023f9d6b4d2e..0373f938f9aa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -96,6 +96,7 @@ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ +org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\ @@ -108,7 +109,7 @@ org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveO org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ -org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\ +org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java new file mode 100644 index 000000000000..9f3824fd412f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java @@ -0,0 +1,180 @@ +/* + * Copyright 2012-2018 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.autoconfigure.task; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.task.TaskSchedulerCustomizer; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link TaskSchedulingAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class TaskSchedulingAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(TestConfiguration.class).withConfiguration( + AutoConfigurations.of(TaskSchedulingAutoConfiguration.class)); + + @Test + public void noSchedulingDoesNotExposeTaskScheduler() { + this.contextRunner.run( + (context) -> assertThat(context).doesNotHaveBean(TaskScheduler.class)); + } + + @Test + public void enableSchedulingWithNoTakExecutorAutoConfiguresOne() { + this.contextRunner + .withPropertyValues( + "spring.task.scheduling.thread-name-prefix=scheduling-test-") + .withUserConfiguration(SchedulingConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(TaskExecutor.class); + TestBean bean = context.getBean(TestBean.class); + Thread.sleep(15); + assertThat(bean.threadNames) + .allMatch((name) -> name.contains("scheduling-test-")); + }); + } + + @Test + public void enableSchedulingWithNoTakExecutorAppliesCustomizers() { + this.contextRunner + .withPropertyValues( + "spring.task.scheduling.thread-name-prefix=scheduling-test-") + .withUserConfiguration(SchedulingConfiguration.class, + TaskSchedulerCustomizerConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(TaskExecutor.class); + TestBean bean = context.getBean(TestBean.class); + Thread.sleep(15); + assertThat(bean.threadNames) + .allMatch((name) -> name.contains("customized-scheduler-")); + }); + } + + @Test + public void enableSchedulingWithExistingTakSchedulerBacksOff() { + this.contextRunner.withUserConfiguration(SchedulingConfiguration.class, + TaskSchedulerConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(TaskScheduler.class); + assertThat(context.getBean(TaskScheduler.class)) + .isInstanceOf(TestTaskScheduler.class); + TestBean bean = context.getBean(TestBean.class); + Thread.sleep(15); + assertThat(bean.threadNames).containsExactly("test-1"); + }); + } + + @Test + public void enableSchedulingWithConfigurerBacksOff() { + this.contextRunner.withUserConfiguration(SchedulingConfiguration.class, + SchedulingConfigurerConfiguration.class).run((context) -> { + assertThat(context).doesNotHaveBean(TaskScheduler.class); + TestBean bean = context.getBean(TestBean.class); + Thread.sleep(15); + assertThat(bean.threadNames).containsExactly("test-1"); + }); + } + + @Configuration + @EnableScheduling + static class SchedulingConfiguration { + + } + + @Configuration + static class TaskSchedulerConfiguration { + + @Bean + public TaskScheduler customTaskScheduler() { + return new TestTaskScheduler(); + } + + } + + @Configuration + static class TaskSchedulerCustomizerConfiguration { + + @Bean + public TaskSchedulerCustomizer testTaskSchedulerCustomizer() { + return ((taskScheduler) -> taskScheduler + .setThreadNamePrefix("customized-scheduler-")); + } + + } + + @Configuration + static class SchedulingConfigurerConfiguration implements SchedulingConfigurer { + + private final TaskScheduler taskScheduler = new TestTaskScheduler(); + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + taskRegistrar.setScheduler(this.taskScheduler); + } + + } + + @Configuration + static class TestConfiguration { + + @Bean + public TestBean testBean() { + return new TestBean(); + } + + } + + static class TestBean { + + private final Set threadNames = new HashSet<>(); + + @Scheduled(fixedRate = 10) + public void accumulate() { + this.threadNames.add(Thread.currentThread().getName()); + } + + } + + static class TestTaskScheduler extends ThreadPoolTaskScheduler { + + TestTaskScheduler() { + setPoolSize(1); + setThreadNamePrefix("test-"); + afterPropertiesSet(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 9bc7de154fdb..3399eb3edde3 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -169,6 +169,10 @@ content into your application. Rather, pick only the properties that you need. spring.task.execution.pool.queue-capacity= # Queue capacity. An unbounded capacity does not increase the pool and therefore ignores the "max-size" property. spring.task.execution.thread-name-prefix=task- # Prefix to use for the names of newly created threads. + # TASK SCHEDULING ({sc-spring-boot-autoconfigure}/task/TaskSchedulingProperties.{sc-ext}[TaskSchedulingProperties]) + spring.task.scheduling.pool.size=1 # Maximum allowed number of threads. + spring.task.scheduling.thread-name-prefix=scheduling- # Prefix to use for the names of newly created threads. + # ---------------------------------------- # WEB PROPERTIES # ---------------------------------------- diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index b5663b1c72ee..2c61a849bed7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6138,8 +6138,8 @@ in a similar manner, as shown in the following example: -[[boot-features-task-execution]] -== Task Execution +[[boot-features-task-execution-scheduling]] +== Task Execution and Scheduling In the absence of a `TaskExecutor` bean in the context, Spring Boot auto-configures a `ThreadPoolTaskExecutor` with sensible defaults that can be automatically associated to asynchronous task execution (`@EnableAsync`) and Spring MVC asynchronous request @@ -6161,6 +6161,12 @@ tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool i aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default). +A `ThreadPoolTaskScheduler` can also be auto-configured if need to be to be associated to +scheduled task execution (`@EnableScheduling`). The thread pool uses one thread by default +and those settings can be fine-tuned using the `spring.task.scheduling` namespace. + +Both a `TaskExecutorBuilder` and `TaskSchedulerBuilder` bean are made available in the +context if a custom executor or scheduler needs to be created. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java new file mode 100644 index 000000000000..228ca4c4370f --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java @@ -0,0 +1,187 @@ +/* + * Copyright 2012-2018 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.task; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Builder that can be used to configure and create a {@link TaskScheduler}. Provides + * convenience methods to set common {@link ThreadPoolTaskScheduler} settings. For + * advanced configuration, consider using {@link TaskSchedulerCustomizer}. + *

+ * In a typical auto-configured Spring Boot application this builder is available as a + * bean and can be injected whenever a {@link TaskScheduler} is needed. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class TaskSchedulerBuilder { + + private final Integer poolSize; + + private final String threadNamePrefix; + + private final Set taskSchedulerCustomizers; + + public TaskSchedulerBuilder(TaskSchedulerCustomizer... taskSchedulerCustomizers) { + Assert.notNull(taskSchedulerCustomizers, + "TaskSchedulerCustomizers must not be null"); + this.poolSize = null; + this.threadNamePrefix = null; + this.taskSchedulerCustomizers = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(taskSchedulerCustomizers))); + } + + public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix, + Set taskSchedulerCustomizers) { + this.poolSize = poolSize; + this.threadNamePrefix = threadNamePrefix; + this.taskSchedulerCustomizers = taskSchedulerCustomizers; + } + + /** + * Set the maximum allowed number of threads. + * @param poolSize the pool size to set + * @return a new builder instance + */ + public TaskSchedulerBuilder poolSize(int poolSize) { + return new TaskSchedulerBuilder(poolSize, this.threadNamePrefix, + this.taskSchedulerCustomizers); + } + + /** + * Set the prefix to use for the names of newly created threads. + * @param threadNamePrefix the thread name prefix to set + * @return a new builder instance + */ + public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) { + return new TaskSchedulerBuilder(this.poolSize, threadNamePrefix, + this.taskSchedulerCustomizers); + } + + /** + * Set the {@link TaskSchedulerCustomizer TaskSchedulerCustomizers} that should be + * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the + * order that they were added after builder configuration has been applied. Setting + * this value will replace any previously configured customizers. + * @param taskSchedulerCustomizers the customizers to set + * @return a new builder instance + * @see #additionalCustomizers(TaskSchedulerCustomizer...) + */ + public TaskSchedulerBuilder customizers( + TaskSchedulerCustomizer... taskSchedulerCustomizers) { + Assert.notNull(taskSchedulerCustomizers, + "TaskSchedulerCustomizers must not be null"); + return customizers(Arrays.asList(taskSchedulerCustomizers)); + } + + /** + * Set the {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be + * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the + * order that they were added after builder configuration has been applied. Setting + * this value will replace any previously configured customizers. + * @param taskSchedulerCustomizers the customizers to set + * @return a new builder instance + * @see #additionalCustomizers(TaskSchedulerCustomizer...) + */ + public TaskSchedulerBuilder customizers( + Collection taskSchedulerCustomizers) { + Assert.notNull(taskSchedulerCustomizers, + "TaskSchedulerCustomizers must not be null"); + return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, + Collections.unmodifiableSet(new LinkedHashSet( + taskSchedulerCustomizers))); + } + + /** + * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied + * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that + * they were added after builder configuration has been applied. + * @param taskSchedulerCustomizers the customizers to add + * @return a new builder instance + * @see #customizers(TaskSchedulerCustomizer...) + */ + public TaskSchedulerBuilder additionalCustomizers( + TaskSchedulerCustomizer... taskSchedulerCustomizers) { + Assert.notNull(taskSchedulerCustomizers, + "TaskSchedulerCustomizers must not be null"); + return additionalCustomizers(Arrays.asList(taskSchedulerCustomizers)); + } + + /** + * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied + * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that + * they were added after builder configuration has been applied. + * @param taskSchedulerCustomizers the customizers to add + * @return a new builder instance + * @see #customizers(TaskSchedulerCustomizer...) + */ + public TaskSchedulerBuilder additionalCustomizers( + Collection taskSchedulerCustomizers) { + Assert.notNull(taskSchedulerCustomizers, + "TaskSchedulerCustomizers must not be null"); + return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, + append(this.taskSchedulerCustomizers, taskSchedulerCustomizers)); + } + + /** + * Build a new {@link ThreadPoolTaskScheduler} instance and configure it using this + * builder. + * @return a configured {@link ThreadPoolTaskScheduler} instance. + * @see #configure(ThreadPoolTaskScheduler) + */ + public ThreadPoolTaskScheduler build() { + return configure(new ThreadPoolTaskScheduler()); + } + + /** + * Configure the provided {@link ThreadPoolTaskScheduler} instance using this builder. + * @param the type of task scheduler + * @param taskScheduler the {@link ThreadPoolTaskScheduler} to configure + * @return the task scheduler instance + * @see #build() + */ + public T configure(T taskScheduler) { + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(() -> this.poolSize).to(taskScheduler::setPoolSize); + map.from(() -> this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix); + + if (!CollectionUtils.isEmpty(this.taskSchedulerCustomizers)) { + for (TaskSchedulerCustomizer customizer : this.taskSchedulerCustomizers) { + customizer.customize(taskScheduler); + } + } + return taskScheduler; + } + + private static Set append(Set set, Collection additions) { + Set result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); + result.addAll(additions); + return Collections.unmodifiableSet(result); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerCustomizer.java new file mode 100644 index 000000000000..e841bb9ef5e3 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerCustomizer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2018 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.task; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +/** + * Callback interface that can be used to customize a {@link ThreadPoolTaskScheduler}. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@FunctionalInterface +public interface TaskSchedulerCustomizer { + + /** + * Callback to customize a {@link ThreadPoolTaskScheduler} instance. + * @param taskScheduler the task scheduler to customize + */ + void customize(ThreadPoolTaskScheduler taskScheduler); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java index 90205e073a58..6e24b26489a0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/package-info.java @@ -15,8 +15,6 @@ */ /** - * Task execution utilities. - * - * @author Stephane Nicoll + * Utilities and classes related to task execution and scheduling. */ package org.springframework.boot.task; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java new file mode 100644 index 000000000000..839cae4393a9 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java @@ -0,0 +1,128 @@ +/* + * Copyright 2012-2018 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.task; + +import java.util.Collections; +import java.util.Set; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link TaskSchedulerBuilder}. + * + * @author Stephane Nicoll + */ +public class TaskSchedulerBuilderTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); + + @Test + public void createWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + new TaskSchedulerBuilder((TaskSchedulerCustomizer[]) null); + } + + @Test + public void poolSettingsShouldApply() { + ThreadPoolTaskScheduler scheduler = this.builder.poolSize(4).build(); + assertThat(scheduler.getPoolSize()).isEqualTo(4); + } + + @Test + public void threadNamePrefixShouldApply() { + ThreadPoolTaskScheduler executor = this.builder.threadNamePrefix("test-").build(); + assertThat(executor.getThreadNamePrefix()).isEqualTo("test-"); + } + + @Test + public void customizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.builder.customizers((TaskSchedulerCustomizer[]) null); + } + + @Test + public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.builder.customizers((Set) null); + } + + @Test + public void customizersShouldApply() { + TaskSchedulerCustomizer customizer = Mockito.mock(TaskSchedulerCustomizer.class); + ThreadPoolTaskScheduler executor = this.builder.customizers(customizer).build(); + Mockito.verify(customizer).customize(executor); + } + + @Test + public void customizersShouldBeAppliedLast() { + ThreadPoolTaskScheduler scheduler = Mockito.spy(new ThreadPoolTaskScheduler()); + this.builder.poolSize(4).threadNamePrefix("test-") + .additionalCustomizers((taskScheduler) -> { + Mockito.verify(taskScheduler).setPoolSize(4); + Mockito.verify(taskScheduler).setThreadNamePrefix("test-"); + }); + this.builder.configure(scheduler); + } + + @Test + public void customizersShouldReplaceExisting() { + TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); + TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); + ThreadPoolTaskScheduler executor = this.builder.customizers(customizer1) + .customizers(Collections.singleton(customizer2)).build(); + Mockito.verifyZeroInteractions(customizer1); + Mockito.verify(customizer2).customize(executor); + } + + @Test + public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.builder.additionalCustomizers((TaskSchedulerCustomizer[]) null); + } + + @Test + public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.builder.additionalCustomizers((Set) null); + } + + @Test + public void additionalCustomizersShouldAddToExisting() { + TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); + TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); + ThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1) + .additionalCustomizers(customizer2).build(); + Mockito.verify(customizer1).customize(scheduler); + Mockito.verify(customizer2).customize(scheduler); + } + +} From 8f2ab952f52f52103be65fb3b2391ebed23cb387 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 17:19:25 +0200 Subject: [PATCH 376/701] Polish javadoc formatting --- .../boot/autoconfigure/condition/ConditionalOnProperty.java | 3 ++- .../boot/devtools/tunnel/server/HttpTunnelServer.java | 3 ++- .../boot/configurationprocessor/json/JSONObject.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java index 2d71b4d69098..692b528ffdc6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java @@ -36,7 +36,8 @@ * should have. The table below shows when a condition matches according to the property * value and the {@link #havingValue()} attribute: * - * + *
+ * * * * diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/tunnel/server/HttpTunnelServer.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/tunnel/server/HttpTunnelServer.java index 8ac0c2d75807..aef4681f66a5 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/tunnel/server/HttpTunnelServer.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/tunnel/server/HttpTunnelServer.java @@ -68,7 +68,8 @@ * Requests should be made using HTTP GET or POST (depending if there is a payload), with * any payload contained in the body. The following response codes can be returned from * the server: - *
Having values
Property Value{@code havingValue=""}
+ *
+ * * * * diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java index caf1d47dab4c..43386a958412 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java @@ -41,7 +41,7 @@ *
  • When the requested type is an int, other {@link Number} types will be coerced using * {@link Number#intValue() intValue}. Strings that can be coerced using * {@link Double#valueOf(String)} will be, and then cast to int. - *
  • When the requested type is a long, other {@link Number} types will + *
  • When the requested type is a long, other {@link Number} types will * be coerced using {@link Number#longValue() longValue}. Strings that can be coerced * using {@link Double#valueOf(String)} will be, and then cast to long. This two-step * conversion is lossy for very large values. For example, the string From 8ffd44077dc54083f98826d126855312b2007284 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 17:25:28 +0200 Subject: [PATCH 377/701] Upgrade to gmavenplus-plugin 1.6.1 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 87f934060f57..73adde121136 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -342,7 +342,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - 1.5 + 1.6.1 org.codehaus.mojo From 98b9a572526c08e592a214a08f208713d4943ff1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Aug 2018 16:18:43 +0100 Subject: [PATCH 378/701] Start building against Spring Data Lovelace RC2 snapshots See gh-14081 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4beb37956d68..1630e96767f5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 2.1.0.M1 4.1.0.M2 2.0.2.RELEASE - Lovelace-RC1 + Lovelace-BUILD-SNAPSHOT 0.25.0.RELEASE 5.1.0.M1 2.2.0.BUILD-SNAPSHOT From 13f08e4c8918b69dafe272e703ccda7055e4a765 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 17:38:26 +0200 Subject: [PATCH 379/701] Polish --- .../spring-boot-deployment-test-tomcat/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-tests/spring-boot-deployment-tests/spring-boot-deployment-test-tomcat/pom.xml b/spring-boot-tests/spring-boot-deployment-tests/spring-boot-deployment-test-tomcat/pom.xml index 867dc61bfd5c..23e6e8750c66 100644 --- a/spring-boot-tests/spring-boot-deployment-tests/spring-boot-deployment-test-tomcat/pom.xml +++ b/spring-boot-tests/spring-boot-deployment-tests/spring-boot-deployment-test-tomcat/pom.xml @@ -12,7 +12,7 @@ Spring Boot Tomcat Deployment Test ${basedir}/../../.. - tomcat8x + tomcat9x https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/${tomcat.version}/tomcat-${tomcat.version}.zip From f2511b7fa3ceec800a2fb6adedcbf0e39c3cb253 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 16 Aug 2018 17:34:42 +0200 Subject: [PATCH 380/701] Improve Web DEBUG logging output configuration Since SPR-16946, Spring Framework revisited the DEBUG logging output developers get while working on Spring MVC and Spring WebFlux applications. This commit aligns to those changes where DEBUG output was produced in Spring Boot (especially in `DefaultErrorWebExceptionHandler`). This also enables DEBUG logging on the related packages when running an application with Spring Boot Developer Tools, providing a better development experience. This is also adding the new `spring.insights.web.log-request-details` configuration property, which logs additional information about the incoming requests at the DEBUG and TRACE levels. Since that information can be sensitive (e.g. credentials, tokens, etc.), this property is not enabled by default nor activated by the Developer Tools. Closes: gh-13511 --- .../http/codec/CodecsAutoConfiguration.java | 18 ++++++- .../insights/InsightsProperties.java | 54 +++++++++++++++++++ .../DefaultErrorWebExceptionHandler.java | 35 ++++-------- .../DispatcherServletAutoConfiguration.java | 12 ++++- ...orWebExceptionHandlerIntegrationTests.java | 21 -------- ...spatcherServletAutoConfigurationTests.java | 4 ++ ...DevToolsPropertyDefaultsPostProcessor.java | 3 ++ .../appendix-application-properties.adoc | 3 ++ .../src/main/asciidoc/using-spring-boot.adoc | 7 +++ 9 files changed, 107 insertions(+), 50 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insights/InsightsProperties.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java index 69794cf30f50..dbf044dcfe3d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -22,7 +22,9 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.insights.InsightsProperties; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -64,4 +66,18 @@ public CodecCustomizer jacksonCodecCustomizer(ObjectMapper objectMapper) { } + @Configuration + @EnableConfigurationProperties(InsightsProperties.class) + static class LoggingCodecConfiguration { + + @Bean + public CodecCustomizer loggingCodecCustomizer(InsightsProperties properties) { + return (configurer) -> { + configurer.defaultCodecs().enableLoggingRequestDetails( + properties.getWeb().isLogRequestDetails()); + }; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insights/InsightsProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insights/InsightsProperties.java new file mode 100644 index 000000000000..9a41d943c011 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insights/InsightsProperties.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2018 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.autoconfigure.insights; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties properties} for . + * + * @author Brian Clozel + * @since 2.1.0 + */ +@ConfigurationProperties(prefix = "spring.insights") +public class InsightsProperties { + + private final Web web = new Web(); + + public Web getWeb() { + return this.web; + } + + public static class Web { + + /** + * Whether logging of (potentially sensitive) request details at DEBUG and TRACE + * level is allowed. + */ + private boolean logRequestDetails = false; + + public boolean isLogRequestDetails() { + return this.logRequestDetails; + } + + public void setLogRequestDetails(boolean logRequestDetails) { + this.logRequestDetails = logRequestDetails; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java index 4c5b4f141e9b..ffd699e563a5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandler.java @@ -20,10 +20,8 @@ import java.util.EnumMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -31,6 +29,7 @@ import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.web.reactive.error.ErrorAttributes; import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpLogging; import org.springframework.http.HttpStatus; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; @@ -39,7 +38,6 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; -import org.springframework.web.server.ResponseStatusException; import static org.springframework.web.reactive.function.server.RequestPredicates.all; import static org.springframework.web.reactive.function.server.RouterFunctions.route; @@ -79,8 +77,8 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa private static final Map SERIES_VIEWS; - private static final Log logger = LogFactory - .getLog(DefaultErrorWebExceptionHandler.class); + private static final Log logger = HttpLogging + .forLogName(DefaultErrorWebExceptionHandler.class); static { Map views = new EnumMap<>(HttpStatus.Series.class); @@ -206,30 +204,15 @@ protected RequestPredicate acceptsTextHtml() { */ protected void logError(ServerRequest request, HttpStatus errorStatus) { Throwable ex = getError(request); - log(request, ex, (errorStatus.is5xxServerError() ? logger::error : logger::warn)); - } - - private void log(ServerRequest request, Throwable ex, - BiConsumer logger) { - if (ex instanceof ResponseStatusException) { - logger.accept(buildMessage(request, ex), null); - } - else { - logger.accept(buildMessage(request, null), ex); + if (logger.isDebugEnabled()) { + logger.debug(request.exchange().getLogPrefix() + formatError(ex, request)); } } - private String buildMessage(ServerRequest request, Throwable ex) { - StringBuilder message = new StringBuilder("Failed to handle request ["); - message.append(request.methodName()); - message.append(" "); - message.append(request.uri()); - message.append("]"); - if (ex != null) { - message.append(": "); - message.append(ex.getMessage()); - } - return message.toString(); + private String formatError(Throwable ex, ServerRequest request) { + String reason = ex.getClass().getSimpleName() + ": " + ex.getMessage(); + return "Resolved [" + reason + "] for HTTP " + request.methodName() + " " + + request.path(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java index 6293e7e0de11..2e30b69a104c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java @@ -36,6 +36,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.autoconfigure.insights.InsightsProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @@ -81,24 +82,31 @@ public class DispatcherServletAutoConfiguration { @Configuration @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) - @EnableConfigurationProperties(WebMvcProperties.class) + @EnableConfigurationProperties({ WebMvcProperties.class, InsightsProperties.class }) protected static class DispatcherServletConfiguration { private final WebMvcProperties webMvcProperties; - public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) { + private final InsightsProperties insightsProperties; + + public DispatcherServletConfiguration(WebMvcProperties webMvcProperties, + InsightsProperties insightsProperties) { this.webMvcProperties = webMvcProperties; + this.insightsProperties = insightsProperties; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); + dispatcherServlet.setShouldHandleFailure(true); dispatcherServlet.setDispatchOptionsRequest( this.webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest( this.webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound( this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); + dispatcherServlet.setEnableLoggingRequestDetails( + this.insightsProperties.getWeb().isLogRequestDetails()); return dispatcherServlet; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandlerIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandlerIntegrationTests.java index 1cd64935c184..ba177ede8a23 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandlerIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/error/DefaultErrorWebExceptionHandlerIntegrationTests.java @@ -30,7 +30,6 @@ import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; -import org.springframework.boot.test.rule.OutputCapture; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -44,10 +43,7 @@ import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.not; /** * Integration tests for {@link DefaultErrorWebExceptionHandler} @@ -70,9 +66,6 @@ public class DefaultErrorWebExceptionHandlerIntegrationTests { @Rule public ExpectedException thrown = ExpectedException.none(); - @Rule - public OutputCapture output = new OutputCapture(); - @Test public void jsonError() { this.contextRunner.run((context) -> { @@ -85,8 +78,6 @@ public void jsonError() { .jsonPath("path").isEqualTo(("/")).jsonPath("message") .isEqualTo("Expected!").jsonPath("exception").doesNotExist() .jsonPath("trace").doesNotExist(); - this.output.expect(allOf(containsString("Failed to handle request [GET /]"), - containsString("IllegalStateException"))); }); } @@ -112,8 +103,6 @@ public void htmlError() { .expectHeader().contentType(MediaType.TEXT_HTML) .expectBody(String.class).returnResult().getResponseBody(); assertThat(body).contains("status: 500").contains("message: Expected!"); - this.output.expect(allOf(containsString("Failed to handle request [GET /]"), - containsString("IllegalStateException"))); }); } @@ -129,9 +118,6 @@ public void bindingResultError() { .isEqualTo(("/bind")).jsonPath("exception").doesNotExist() .jsonPath("errors").isArray().jsonPath("message").isNotEmpty(); }); - this.output.expect(allOf(containsString("Failed to handle request [POST /bind]"), - containsString("Validation failed for argument"), - containsString("Field error in object 'dummyBody' on field 'content'"))); } @Test @@ -197,7 +183,6 @@ public void statusException() { .isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()) .jsonPath("exception") .isEqualTo(ResponseStatusException.class.getName()); - this.output.expect(not(containsString("ResponseStatusException"))); }); } @@ -215,9 +200,6 @@ public void defaultErrorView() { .returnResult().getResponseBody(); assertThat(body).contains("Whitelabel Error Page") .contains("
    Expected!
    "); - this.output.expect( - allOf(containsString("Failed to handle request [GET /]"), - containsString("IllegalStateException"))); }); } @@ -235,9 +217,6 @@ public void escapeHtmlInDefaultErrorView() { .returnResult().getResponseBody(); assertThat(body).contains("Whitelabel Error Page") .doesNotContain(" - - - - - - - org.codehaus.groovy - groovy - ${groovy.version} - - - org.codehaus.groovy - groovy-ant - ${groovy.version} - - - org.springframework - spring-core - ${spring.version} - - -
    org.asciidoctor asciidoctor-maven-plugin @@ -1419,5 +1383,54 @@ + + full-groovy + + [1.8,10] + + full + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + + execute + + generate-resources + + + + + + + + + + + + org.codehaus.groovy + groovy + ${groovy.version} + + + org.codehaus.groovy + groovy-ant + ${groovy.version} + + + org.springframework + spring-core + ${spring.version} + + + + + + From 9a94fb3464d3d86da036a6086c419621fff343f7 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 16:19:44 +0200 Subject: [PATCH 415/701] Add ci build for Java 11 Closes gh-14028 --- .../spring-boot-jdk11-ci-image/Dockerfile | 33 ++++++++++ ci/pipeline.yml | 65 ++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 ci/images/spring-boot-jdk11-ci-image/Dockerfile diff --git a/ci/images/spring-boot-jdk11-ci-image/Dockerfile b/ci/images/spring-boot-jdk11-ci-image/Dockerfile new file mode 100644 index 000000000000..a15a764166c8 --- /dev/null +++ b/ci/images/spring-boot-jdk11-ci-image/Dockerfile @@ -0,0 +1,33 @@ +FROM openjdk:11-ea-24-jdk + +RUN apt-get update && \ + apt-get install -y git && \ + apt-get install -y libxml2-utils && \ + apt-get install -y jq + +ADD https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.2/concourse-java.sh /opt/ + +ENV DOCKER_VERSION=17.05.0-ce \ + ENTRYKIT_VERSION=0.4.0 + +RUN apt-get update && \ + apt-get install -y curl && \ + apt-get install -y libudev1 && \ + apt-get install -y iptables && \ + curl https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz | tar zx && \ + mv /docker/* /bin/ && chmod +x /bin/docker* + +# Install entrykit +RUN curl -L https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz | tar zx && \ + chmod +x entrykit && \ + mv entrykit /bin/entrykit && \ + entrykit --symlink + +ADD https://raw.githubusercontent.com/spring-projects/spring-boot/master/ci/images/docker-lib.sh /docker-lib.sh + +ENTRYPOINT [ \ + "switch", \ + "shell=/bin/sh", "--", \ + "codep", \ + "/bin/docker daemon" \ +] \ No newline at end of file diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 5823c364d154..ea7ea75dcf77 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -61,6 +61,13 @@ resources: username: ((docker-hub-username)) password: ((docker-hub-password)) tag: ((branch)) +- name: spring-boot-jdk11-ci-image + type: docker-image + source: + repository: ((docker-hub-organization))/spring-boot-jdk11-ci-image + username: ((docker-hub-username)) + password: ((docker-hub-password)) + tag: ((branch)) - name: artifactory-repo type: artifactory-resource source: @@ -89,6 +96,13 @@ resources: access_token: ((github-access-token)) branch: ((branch)) context: jdk10-build +- name: repo-status-jdk11-build + type: github-status-resource + source: + repository: ((github-repo-name)) + access_token: ((github-access-token)) + branch: ((branch)) + context: jdk11-build - name: slack-alert type: slack-notification source: @@ -107,6 +121,9 @@ jobs: - put: spring-boot-jdk10-ci-image params: build: ci-images-git-repo/ci/images/spring-boot-jdk10-ci-image + - put: spring-boot-jdk11-ci-image + params: + build: ci-images-git-repo/ci/images/spring-boot-jdk11-ci-image - name: build serial: true public: true @@ -301,6 +318,52 @@ jobs: silent: true icon_emoji: ":concourse:" username: concourse-ci +- name: jdk11-build + serial: true + public: true + plan: + - get: spring-boot-jdk11-ci-image + - get: git-repo + trigger: true + - put: repo-status-jdk11-build + params: { state: "pending", commit: "git-repo" } + - do: + - task: build-project + privileged: true + timeout: 1h30m + image: spring-boot-jdk11-ci-image + file: git-repo/ci/tasks/build-project.yml + - aggregate: + - task: build-samples + timeout: 1h30m + image: spring-boot-jdk11-ci-image + file: git-repo/ci/tasks/build-samples.yml + - task: build-integration-tests + timeout: 1h30m + image: spring-boot-jdk11-ci-image + file: git-repo/ci/tasks/build-integration-tests.yml + - task: build-deployment-tests + timeout: 1h30m + image: spring-boot-jdk11-ci-image + file: git-repo/ci/tasks/build-deployment-tests.yml + on_failure: + do: + - put: repo-status-jdk11-build + params: { state: "failure", commit: "git-repo" } + - put: slack-alert + params: + text: ":concourse-failed: " + silent: true + icon_emoji: ":concourse:" + username: concourse-ci + - put: repo-status-jdk11-build + params: { state: "success", commit: "git-repo" } + - put: slack-alert + params: + text: ":concourse-succeeded: " + silent: true + icon_emoji: ":concourse:" + username: concourse-ci - name: stage-milestone serial: true plan: @@ -436,7 +499,7 @@ jobs: BINTRAY_REPO: ((bintray-repo)) groups: - name: "Build" - jobs: ["build", "jdk9-build", "jdk10-build"] + jobs: ["build", "jdk9-build", "jdk10-build", "jdk11-build"] - name: "Release" jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "sync-to-maven-central"] - name: "CI Images" From 6ecbd8d21b2581713195b135aa4006b4977209ec Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 17 Aug 2018 15:21:34 +0200 Subject: [PATCH 416/701] Auto-Configure FormContentFilter in Spring MVC Because `HttpPutFormContentFilter` has been deprecated in Spring Framework 5.1, this commit updates the auto-configuration to replace it with the new `FormContentFilter`. This new filter is building on the previous one and supports HTTP DELETE requests as well. Both filters should not be used in addition, so the former configuration has been removed. This commit also adds configuration metadata to let developers know about the configuration key change. Closes: gh-13363 --- .../web/servlet/WebMvcAutoConfiguration.java | 12 ++++---- ...itional-spring-configuration-metadata.json | 10 +++++++ .../HttpEncodingAutoConfigurationTests.java | 8 ++--- .../servlet/WebMvcAutoConfigurationTests.java | 29 +++++++++---------- .../appendix-application-properties.adoc | 2 +- ...ter.java => OrderedFormContentFilter.java} | 12 ++++---- 6 files changed, 41 insertions(+), 32 deletions(-) rename spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/{OrderedHttpPutFormContentFilter.java => OrderedFormContentFilter.java} (79%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index dfd39bbc8088..2683a7200c9a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -55,8 +55,8 @@ import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy; import org.springframework.boot.autoconfigure.web.format.WebConversionService; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter; -import org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter; import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter; import org.springframework.context.ApplicationContext; import org.springframework.context.ResourceLoaderAware; @@ -90,8 +90,8 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextListener; +import org.springframework.web.filter.FormContentFilter; import org.springframework.web.filter.HiddenHttpMethodFilter; -import org.springframework.web.filter.HttpPutFormContentFilter; import org.springframework.web.filter.RequestContextFilter; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.HandlerExceptionResolver; @@ -160,10 +160,10 @@ public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { } @Bean - @ConditionalOnMissingBean(HttpPutFormContentFilter.class) - @ConditionalOnProperty(prefix = "spring.mvc.formcontent.putfilter", name = "enabled", matchIfMissing = true) - public OrderedHttpPutFormContentFilter httpPutFormContentFilter() { - return new OrderedHttpPutFormContentFilter(); + @ConditionalOnMissingBean(FormContentFilter.class) + @ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true) + public OrderedFormContentFilter formContentFilter() { + return new OrderedFormContentFilter(); } // Defined as a nested config to ensure WebMvcConfigurer is not read when not diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 2a55eec16d7c..5a45e710ae0c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -464,6 +464,16 @@ "name": "spring.mvc.formcontent.putfilter.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Spring's HttpPutFormContentFilter.", + "defaultValue": true, + "deprecation" : { + "replacement" : "spring.mvc.formcontent.filter.enabled", + "level" : "error" + } + }, + { + "name": "spring.mvc.formcontent.filter.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable Spring's FormContentFilter.", "defaultValue": true }, { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java index cc65700888f5..ed2de567f720 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +33,8 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; +import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter; -import org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; @@ -222,8 +222,8 @@ public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { } @Bean - public OrderedHttpPutFormContentFilter httpPutFormContentFilter() { - return new OrderedHttpPutFormContentFilter(); + public OrderedFormContentFilter formContentFilter() { + return new OrderedFormContentFilter(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index ee863d3da334..c92d8b552511 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -45,7 +45,7 @@ import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; -import org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter; +import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -71,8 +71,8 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.filter.FormContentFilter; import org.springframework.web.filter.HiddenHttpMethodFilter; -import org.springframework.web.filter.HttpPutFormContentFilter; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerMapping; @@ -551,27 +551,26 @@ public void customMediaTypes() { } @Test - public void httpPutFormContentFilterIsAutoConfigured() { + public void formContentFilterIsAutoConfigured() { this.contextRunner.run((context) -> assertThat(context) - .hasSingleBean(OrderedHttpPutFormContentFilter.class)); + .hasSingleBean(OrderedFormContentFilter.class)); } @Test - public void httpPutFormContentFilterCanBeOverridden() { - this.contextRunner.withUserConfiguration(CustomHttpPutFormContentFilter.class) + public void formContentFilterCanBeOverridden() { + this.contextRunner.withUserConfiguration(CustomFormContentFilter.class) .run((context) -> { - assertThat(context) - .doesNotHaveBean(OrderedHttpPutFormContentFilter.class); - assertThat(context).hasSingleBean(HttpPutFormContentFilter.class); + assertThat(context).doesNotHaveBean(OrderedFormContentFilter.class); + assertThat(context).hasSingleBean(FormContentFilter.class); }); } @Test - public void httpPutFormContentFilterCanBeDisabled() { + public void formContentFilterCanBeDisabled() { this.contextRunner - .withPropertyValues("spring.mvc.formcontent.putfilter.enabled=false") + .withPropertyValues("spring.mvc.formcontent.filter.enabled=false") .run((context) -> assertThat(context) - .doesNotHaveBean(HttpPutFormContentFilter.class)); + .doesNotHaveBean(FormContentFilter.class)); } @Test @@ -1076,11 +1075,11 @@ private static class CustomWebBindingInitializer } @Configuration - static class CustomHttpPutFormContentFilter { + static class CustomFormContentFilter { @Bean - public HttpPutFormContentFilter customHttpPutFormContentFilter() { - return new HttpPutFormContentFilter(); + public FormContentFilter customFormContentFilter() { + return new FormContentFilter(); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index be9a0139e293..9b321b87d9d6 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -428,7 +428,7 @@ content into your application. Rather, pick only the properties that you need. spring.mvc.dispatch-trace-request=false # Whether to dispatch TRACE requests to the FrameworkServlet doService method. spring.mvc.dispatch-options-request=true # Whether to dispatch OPTIONS requests to the FrameworkServlet doService method. spring.mvc.favicon.enabled=true # Whether to enable resolution of favicon.ico. - spring.mvc.formcontent.putfilter.enabled=true # Whether to enable Spring's HttpPutFormContentFilter. + spring.mvc.formcontent.filter.enabled=true # Whether to enable Spring's FormContentFilter. spring.mvc.hiddenmethod.filter.enabled=true # Whether to enable Spring's HiddenHttpMethodFilter. spring.mvc.ignore-default-model-on-redirect=true # Whether the content of the "default" model should be ignored during redirect scenarios. spring.mvc.locale= # Locale to use. By default, this locale is overridden by the "Accept-Language" header. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedHttpPutFormContentFilter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedFormContentFilter.java similarity index 79% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedHttpPutFormContentFilter.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedFormContentFilter.java index e3ca4fa9a6ab..8b42e16a50c1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedHttpPutFormContentFilter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/filter/OrderedFormContentFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,16 +18,16 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.core.Ordered; -import org.springframework.web.filter.HttpPutFormContentFilter; +import org.springframework.web.filter.FormContentFilter; /** - * {@link HttpPutFormContentFilter} that also implements {@link Ordered}. + * {@link FormContentFilter} that also implements {@link Ordered}. * * @author Joao Pedro Evangelista - * @since 2.0.0 + * @author Brian Clozel + * @since 2.1.0 */ -public class OrderedHttpPutFormContentFilter extends HttpPutFormContentFilter - implements Ordered { +public class OrderedFormContentFilter extends FormContentFilter implements Ordered { /** * Higher order to ensure the filter is applied before Spring Security. From ba2f2a3727ce6c3bd229d52a35b8dddf9a31ade4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 17 Aug 2018 16:17:00 +0200 Subject: [PATCH 417/701] Polish jaxb setup for JDK 9 and further --- .../spring-boot-autoconfigure/pom.xml | 17 ++--------------- spring-boot-project/spring-boot-cli/pom.xml | 17 ++--------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 083c1e726ba9..f9e08b16b759 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -798,22 +798,9 @@ - java9-10 + java9+ - [9,10] - - - - javax.xml.bind - jaxb-api - true - - - - - java11+ - - [11,) + [9,) diff --git a/spring-boot-project/spring-boot-cli/pom.xml b/spring-boot-project/spring-boot-cli/pom.xml index 54d34cacdff7..d5c63cd14f1d 100644 --- a/spring-boot-project/spring-boot-cli/pom.xml +++ b/spring-boot-project/spring-boot-cli/pom.xml @@ -455,22 +455,9 @@ - java9-10 + java9+ - [9,10] - - - - javax.xml.bind - jaxb-api - true - - - - - java11+ - - [11,) + [9,) From 1c224e5fbbb0bdbf69322279bb42215121ac9da1 Mon Sep 17 00:00:00 2001 From: artsiom Date: Fri, 17 Aug 2018 16:59:14 +0200 Subject: [PATCH 418/701] Add WebFluxRegistrations for custom WebFlux beans This commit adds a new `WebFluxRegistrations` interface that allows developers to register custom instances of key WebFlux infrastructure components, such as `RequestMappingHandlerMapping` and `RequestMappingHandlerAdapter`. Closes gh-13997 --- .../reactive/WebFluxAutoConfiguration.java | 26 +++++- .../web/reactive/WebFluxRegistrations.java | 53 +++++++++++++ .../WebFluxAutoConfigurationTests.java | 79 +++++++++++++++++++ 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxRegistrations.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 0c0c808fd50f..b37c11d3dcc8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -71,6 +71,8 @@ import org.springframework.web.reactive.resource.VersionResourceResolver; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; +import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; +import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.reactive.result.view.ViewResolver; /** @@ -226,8 +228,12 @@ public static class EnableWebFluxConfiguration private final WebFluxProperties webFluxProperties; - public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties) { + private final WebFluxRegistrations webFluxRegistrations; + + public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties, + ObjectProvider webFluxRegistrations) { this.webFluxProperties = webFluxProperties; + this.webFluxRegistrations = webFluxRegistrations.getIfUnique(); } @Bean @@ -249,6 +255,24 @@ public Validator webFluxValidator() { return ValidatorAdapter.get(getApplicationContext(), getValidator()); } + @Override + protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { + if (this.webFluxRegistrations != null && this.webFluxRegistrations + .getRequestMappingHandlerAdapter() != null) { + return this.webFluxRegistrations.getRequestMappingHandlerAdapter(); + } + return super.createRequestMappingHandlerAdapter(); + } + + @Override + protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { + if (this.webFluxRegistrations != null && this.webFluxRegistrations + .getRequestMappingHandlerMapping() != null) { + return this.webFluxRegistrations.getRequestMappingHandlerMapping(); + } + return super.createRequestMappingHandlerMapping(); + } + } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxRegistrations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxRegistrations.java new file mode 100644 index 000000000000..fa57a8a2d254 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxRegistrations.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; +import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; + +/** + * Interface to register key components of the {@link WebFluxAutoConfiguration} in place + * of the default ones provided by Spring WebFlux. + *

    + * All custom instances are later processed by Boot and Spring WebFlux configurations. A + * single instance of this component should be registered, otherwise making it impossible + * to choose from redundant WebFlux components. + * + * @author Artsiom Yudovin + * @since 2.1.0 + * @see org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration.EnableWebFluxConfiguration + */ +public interface WebFluxRegistrations { + + /** + * Return the custom {@link RequestMappingHandlerMapping} that should be used and + * processed by the WebFlux configuration. + * @return the custom {@link RequestMappingHandlerMapping} instance + */ + default RequestMappingHandlerMapping getRequestMappingHandlerMapping() { + return null; + } + + /** + * Return the custom {@link RequestMappingHandlerAdapter} that should be used and + * processed by the WebFlux configuration. + * @return the custom {@link RequestMappingHandlerAdapter} instance + */ + default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() { + return null; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 112ae3b7ced6..74cc41e867b0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -33,6 +33,7 @@ import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.io.ClassPathResource; @@ -370,6 +371,33 @@ public void hiddenHttpMethodFilterCanBeOverridden() { }); } + @Test + public void customRequestMappingHandlerMapping() { + this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerMapping.class) + .run((context) -> assertThat(context) + .getBean(RequestMappingHandlerMapping.class) + .isInstanceOf(MyRequestMappingHandlerMapping.class)); + } + + @Test + public void customRequestMappingHandlerAdapter() { + this.contextRunner.withUserConfiguration(CustomRequestMappingHandlerAdapter.class) + .run((context) -> assertThat(context) + .getBean(RequestMappingHandlerAdapter.class) + .isInstanceOf(MyRequestMappingHandlerAdapter.class)); + } + + @Test + public void multipleWebFluxRegistrations() { + this.contextRunner.withUserConfiguration(MultipleWebFluxRegistrations.class) + .run((context) -> { + assertThat(context.getBean(RequestMappingHandlerMapping.class)) + .isNotInstanceOf(MyRequestMappingHandlerMapping.class); + assertThat(context.getBean(RequestMappingHandlerAdapter.class)) + .isNotInstanceOf(MyRequestMappingHandlerAdapter.class); + }); + } + @Configuration protected static class CustomArgumentResolvers { @@ -485,4 +513,55 @@ public HiddenHttpMethodFilter customHiddenHttpMethodFilter() { } + @Configuration + static class CustomRequestMappingHandlerAdapter { + + @Bean + public WebFluxRegistrations webMvcRegistrationsHandlerAdapter() { + return new WebFluxRegistrations() { + + @Override + public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() { + return new WebFluxAutoConfigurationTests.MyRequestMappingHandlerAdapter(); + } + + }; + } + + } + + private static class MyRequestMappingHandlerAdapter + extends RequestMappingHandlerAdapter { + + } + + @Configuration + @Import({ WebFluxAutoConfigurationTests.CustomRequestMappingHandlerMapping.class, + WebFluxAutoConfigurationTests.CustomRequestMappingHandlerAdapter.class }) + static class MultipleWebFluxRegistrations { + + } + + @Configuration + static class CustomRequestMappingHandlerMapping { + + @Bean + public WebFluxRegistrations webMvcRegistrationsHandlerMapping() { + return new WebFluxRegistrations() { + + @Override + public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { + return new MyRequestMappingHandlerMapping(); + } + + }; + } + + } + + private static class MyRequestMappingHandlerMapping + extends RequestMappingHandlerMapping { + + } + } From 09e09bf4306156183ea37b76432ef4c1563075d5 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 17 Aug 2018 13:02:50 -0700 Subject: [PATCH 419/701] Add starter for OpenID Connect/OAuth2 client Closes gh-13830 --- .../spring-boot-dependencies/pom.xml | 5 +++ .../spring-boot-starters/pom.xml | 1 + .../pom.xml | 38 +++++++++++++++++++ .../spring-boot-sample-oauth2-client/pom.xml | 14 +------ 4 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 72eebf251996..500a772cffc5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -470,6 +470,11 @@ spring-boot-starter-mustache ${revision} + + org.springframework.boot + spring-boot-starter-oauth2-oidc-client + ${revision} + org.springframework.boot spring-boot-starter-reactor-netty diff --git a/spring-boot-project/spring-boot-starters/pom.xml b/spring-boot-project/spring-boot-starters/pom.xml index 06046e23f38c..76a7ca4dfebb 100644 --- a/spring-boot-project/spring-boot-starters/pom.xml +++ b/spring-boot-project/spring-boot-starters/pom.xml @@ -55,6 +55,7 @@ spring-boot-starter-mail spring-boot-starter-mustache spring-boot-starter-actuator + spring-boot-starter-oauth2-oidc-client spring-boot-starter-parent spring-boot-starter-quartz spring-boot-starter-reactor-netty diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml new file mode 100644 index 000000000000..e59f26b07fc9 --- /dev/null +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starters + ${revision} + + spring-boot-starter-oauth2-oidc-client + Spring Boot OAuth2/OpenID Connect Client Starter + Starter for using Spring Security's OAuth2/OpenID Connect client features + + ${basedir}/../../.. + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-core + + + org.springframework.security + spring-security-oauth2-client + + + org.springframework.security + spring-security-oauth2-jose + + + diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/pom.xml b/spring-boot-samples/spring-boot-sample-oauth2-client/pom.xml index b65604255e21..ba2ce54e728e 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/pom.xml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/pom.xml @@ -18,24 +18,12 @@ org.springframework.boot - spring-boot-starter-security + spring-boot-starter-oauth2-oidc-client org.springframework.boot spring-boot-starter-web - - org.springframework.security - spring-security-config - - - org.springframework.security - spring-security-oauth2-client - - - org.springframework.security - spring-security-oauth2-jose - org.apache.httpcomponents From 94d45c7361daf473ab1a193a103b6272c046d4ce Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Fri, 17 Aug 2018 13:42:37 +0200 Subject: [PATCH 420/701] Start building against Spring Session Bean M2 snapshots See gh-14123 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 500a772cffc5..0c3cabfc5d14 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -166,7 +166,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.BUILD-SNAPSHOT - Bean-M1 + Bean-BUILD-SNAPSHOT 3.0.3.RELEASE 3.23.1 3.1.0 From 644ab5f3e4319610632b60cbbc4f9141f3ba3470 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Fri, 17 Aug 2018 18:04:38 +0200 Subject: [PATCH 421/701] Align SessionsEndpoint with Spring Session API improvements This commit aligns SessionsEndpoint with FindByIndexNameSessionRepository API improvements that simplifies retrieval of sessions by principal name. Closes gh-14124 --- .../SessionsEndpointDocumentationTests.java | 4 +--- .../boot/actuate/session/SessionsEndpoint.java | 4 +--- .../boot/actuate/session/SessionsEndpointTests.java | 5 ++--- .../session/SessionsEndpointWebIntegrationTests.java | 11 ++++------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java index 08293bde75fc..ad94c8ab7a61 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/SessionsEndpointDocumentationTests.java @@ -89,9 +89,7 @@ public void sessionsForUsername() throws Exception { sessions.put(sessionOne.getId(), sessionOne); sessions.put(sessionTwo.getId(), sessionTwo); sessions.put(sessionThree.getId(), sessionThree); - given(this.sessionRepository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "alice")) - .willReturn(sessions); + given(this.sessionRepository.findByPrincipalName("alice")).willReturn(sessions); this.mockMvc.perform(get("/actuator/sessions").param("username", "alice")) .andExpect(status().isOk()) .andDo(document("sessions/username", diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/session/SessionsEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/session/SessionsEndpoint.java index 33e2ec43cfab..a636429f1294 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/session/SessionsEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/session/SessionsEndpoint.java @@ -52,9 +52,7 @@ public SessionsEndpoint( @ReadOperation public SessionsReport sessionsForUsername(String username) { Map sessions = this.sessionRepository - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - username); + .findByPrincipalName(username); return new SessionsReport(sessions); } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointTests.java index a2d84eba2def..d033bfe336f0 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointTests.java @@ -48,9 +48,8 @@ public class SessionsEndpointTests { @Test public void sessionsForUsername() { - given(this.repository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "user")) - .willReturn(Collections.singletonMap(session.getId(), session)); + given(this.repository.findByPrincipalName("user")) + .willReturn(Collections.singletonMap(session.getId(), session)); List result = this.endpoint.sessionsForUsername("user") .getSessions(); assertThat(result).hasSize(1); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointWebIntegrationTests.java index 614311887634..3ef535899be5 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/session/SessionsEndpointWebIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -58,9 +58,7 @@ public void sessionsForUsernameWithoutUsernameParam() { @Test public void sessionsForUsernameNoResults() { - given(repository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "user")) - .willReturn(Collections.emptyMap()); + given(repository.findByPrincipalName("user")).willReturn(Collections.emptyMap()); client.get() .uri((builder) -> builder.path("/actuator/sessions") .queryParam("username", "user").build()) @@ -70,9 +68,8 @@ public void sessionsForUsernameNoResults() { @Test public void sessionsForUsernameFound() { - given(repository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "user")) - .willReturn(Collections.singletonMap(session.getId(), session)); + given(repository.findByPrincipalName("user")) + .willReturn(Collections.singletonMap(session.getId(), session)); client.get() .uri((builder) -> builder.path("/actuator/sessions") .queryParam("username", "user").build()) From 3ad3cfd7e2de42aaaf8ba0af258ef21a064027bc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 19 Aug 2018 15:28:54 +0200 Subject: [PATCH 422/701] Polish dependency management for OIDC starter See gh-13830 --- .../spring-boot-starter-oauth2-oidc-client/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml index e59f26b07fc9..7ae182e28313 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml @@ -29,6 +29,12 @@ org.springframework.security spring-security-oauth2-client + + + javax.mail + javax.mail-api + + org.springframework.security From a601bc863b76d47ad92c629ada562849c04c17f5 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sat, 18 Aug 2018 13:27:43 +0200 Subject: [PATCH 423/701] Remove unused method in TypeUtils Closes gh-14130 --- .../boot/configurationprocessor/TypeUtils.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java index ce3e6d32751a..1b3f6dabb82c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java @@ -128,16 +128,6 @@ public boolean isCollectionOrMap(TypeMirror type) { || this.env.getTypeUtils().isAssignable(type, this.mapType); } - public boolean isEnclosedIn(Element candidate, TypeElement element) { - if (candidate == null || element == null) { - return false; - } - if (candidate.equals(element)) { - return true; - } - return isEnclosedIn(candidate.getEnclosingElement(), element); - } - public String getJavaDoc(Element element) { String javadoc = (element != null) ? this.env.getElementUtils().getDocComment(element) : null; From b80f57f336275a6a3bdaac85a91ec9e446713277 Mon Sep 17 00:00:00 2001 From: Marcel Overdijk Date: Sun, 19 Aug 2018 19:02:43 +0200 Subject: [PATCH 424/701] Fix typo Closes gh-14138 --- spring-boot-project/spring-boot-dependencies/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index bf022ff3c74f..adaa23bbdffc 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -62,7 +62,7 @@ 2.3.28 6.3.2 3.0.0 - 2.4.0-b180725.0644 + 2.4.0-b180725.0644 2.5.2 2.8.5 1.4.197 @@ -1841,7 +1841,7 @@ org.glassfish.jaxb jaxb-runtime - ${glassfixh-jaxb.version} + ${glassfish-jaxb.version} org.glassfish.jersey From f804d5ce4c8cbdeb1c9326a5509b61db8111d999 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 20 Aug 2018 11:29:51 +0200 Subject: [PATCH 425/701] Upgrade to Spring Data Lovelace RC2 Closes gh-14081 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index adaa23bbdffc..6a6459dfc3ed 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 2.1.0.M1 4.1.0.M2 2.0.2.RELEASE - Lovelace-BUILD-SNAPSHOT + Lovelace-RC2 0.25.0.RELEASE 5.1.0.M1 2.2.0.BUILD-SNAPSHOT From c00dbc6c2f41416f89a1b973eaddf1baa6ce6da2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 20 Aug 2018 15:04:08 +0200 Subject: [PATCH 426/701] Fix merge commit --- .../orm/jpa/EntityManagerFactoryBuilder.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder.java index 6c0b1311e9b2..eba8e01b6b59 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder.java @@ -58,8 +58,6 @@ public class EntityManagerFactoryBuilder { private AsyncTaskExecutor bootstrapExecutor; - private EntityManagerFactoryBeanCallback callback; - /** * Create a new instance passing in the common pieces that will be shared if multiple * EntityManagerFactory instances are created. @@ -107,15 +105,6 @@ public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) { this.bootstrapExecutor = bootstrapExecutor; } - /** - * An optional callback for new entity manager factory beans. - * @param callback the entity manager factory bean callback - */ - @Deprecated - public void setCallback(EntityManagerFactoryBeanCallback callback) { - this.callback = callback; - } - /** * A fluent builder for a LocalContainerEntityManagerFactoryBean. */ @@ -214,7 +203,6 @@ public Builder jta(boolean jta) { return this; } - @SuppressWarnings("deprecation") public LocalContainerEntityManagerFactoryBean build() { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); if (EntityManagerFactoryBuilder.this.persistenceUnitManager != null) { @@ -249,24 +237,9 @@ public LocalContainerEntityManagerFactoryBean build() { entityManagerFactoryBean.setBootstrapExecutor( EntityManagerFactoryBuilder.this.bootstrapExecutor); } - if (EntityManagerFactoryBuilder.this.callback != null) { - EntityManagerFactoryBuilder.this.callback - .execute(entityManagerFactoryBean); - } return entityManagerFactoryBean; } } - /** - * A callback for new entity manager factory beans created by a Builder. - */ - @FunctionalInterface - @Deprecated - public interface EntityManagerFactoryBeanCallback { - - void execute(LocalContainerEntityManagerFactoryBean factory); - - } - } From 308564702466d99df9f70fec66bf1ab1c89f3d0c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 08:59:34 +0200 Subject: [PATCH 427/701] Upgrade to Spring Amqp 2.1.0.M2 Closes gh-14155 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6a6459dfc3ed..eadd6ba366f6 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -154,7 +154,7 @@ 1.21 7.4.0 5.1.0.RC2 - 2.1.0.M1 + 2.1.0.M2 4.1.0.M2 2.0.2.RELEASE Lovelace-RC2 From 579bed48a97b590f56be1078814f04cb920fe102 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 09:02:32 +0200 Subject: [PATCH 428/701] Upgrade to Spring Kafka 2.2.0.M2 Closes gh-14143 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index eadd6ba366f6..f36141baf66a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -160,7 +160,7 @@ Lovelace-RC2 0.25.0.RELEASE 5.1.0.M1 - 2.2.0.BUILD-SNAPSHOT + 2.2.0.M2 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 16374599d68e926a2dfc9c5ea3a1ca9d0097a0ee Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 09:04:20 +0200 Subject: [PATCH 429/701] Upgrade to Spring Session Bean-M2 Closes gh-14123 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f36141baf66a..39f284bceaeb 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -166,7 +166,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.BUILD-SNAPSHOT - Bean-BUILD-SNAPSHOT + Bean-M2 3.0.3.RELEASE 3.23.1 3.1.0 From 4dc8b7120063acab759b4d5e2197d33af863163e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 09:05:12 +0200 Subject: [PATCH 430/701] Upgrade to Spring Security 5.1.0.RC1 Closes gh-14144 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 39f284bceaeb..1b1c7b8862ba 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.BUILD-SNAPSHOT + 5.1.0.RC1 Bean-M2 3.0.3.RELEASE 3.23.1 From f5d922c71253ea14c102c5c71fd8d4a671ef7cfa Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 09:03:14 +0200 Subject: [PATCH 431/701] Upgrade to Spring Integration 5.1.0.M2 Upgrade to M2 broke a test that was looking for a particular bean that is configured by Spring Integration (`HeaderChannelRegistry`). It looks like INT-4517 is related to the regression as it registers the bean too late for the auto-configuration to see it. This commit changes the condition to a more central bean that is created very early on. Closes gh-14142 --- .../IntegrationGraphEndpointAutoConfiguration.java | 4 ++-- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java index 328e2feb2c83..4136ba13a61f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/integration/IntegrationGraphEndpointAutoConfiguration.java @@ -26,8 +26,8 @@ import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.integration.config.IntegrationConfigurationBeanFactoryPostProcessor; import org.springframework.integration.graph.IntegrationGraphServer; -import org.springframework.integration.support.channel.HeaderChannelRegistry; /** * {@link EnableAutoConfiguration Auto-configuration} for the @@ -39,7 +39,7 @@ */ @Configuration @ConditionalOnClass(IntegrationGraphServer.class) -@ConditionalOnBean(HeaderChannelRegistry.class) +@ConditionalOnBean(IntegrationConfigurationBeanFactoryPostProcessor.class) @AutoConfigureAfter(IntegrationAutoConfiguration.class) public class IntegrationGraphEndpointAutoConfiguration { diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1b1c7b8862ba..16e1de452691 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -159,7 +159,7 @@ 2.0.2.RELEASE Lovelace-RC2 0.25.0.RELEASE - 5.1.0.M1 + 5.1.0.M2 2.2.0.M2 2.3.2.RELEASE 1.2.0.RELEASE From df6e2170a7a5d3fbe587b87f28cc0164bc0c1841 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 21 Aug 2018 10:09:50 +0200 Subject: [PATCH 432/701] Polish --- .../src/main/asciidoc/appendix-application-properties.adoc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 9b321b87d9d6..571a7e34fe8c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -779,7 +779,7 @@ content into your application. Rather, pick only the properties that you need. spring.jdbc.template.query-timeout= # Query timeout. Default is to use the JDBC driver's default configuration. If a duration suffix is not specified, seconds will be used. # JPA ({sc-spring-boot-autoconfigure}/orm/jpa/JpaBaseConfiguration.{sc-ext}[JpaBaseConfiguration], {sc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{sc-ext}[HibernateJpaAutoConfiguration]) - spring.data.jpa.repositories.boostrap-mode=default # Bootstrap mode for JPA repositories. + spring.data.jpa.repositories.bootstrap-mode=default # Bootstrap mode for JPA repositories. spring.data.jpa.repositories.enabled=true # Whether to enable JPA repositories. spring.jpa.database= # Target database to operate on, auto-detected by default. Can be alternatively set using the "databasePlatform" property. spring.jpa.database-platform= # Name of the target database to operate on, auto-detected by default. Can be alternatively set using the "Database" enum. @@ -988,13 +988,10 @@ content into your application. Rather, pick only the properties that you need. spring.artemis.password= # Login password of the broker. spring.artemis.pool.block-if-full=true # Whether to block when a connection is requested and the pool is full. Set it to false to throw a "JMSException" instead. spring.artemis.pool.block-if-full-timeout=-1ms # Blocking period before throwing an exception if the pool is still full. - spring.artemis.pool.create-connection-on-startup=true # Whether to create a connection on startup. Can be used to warm up the pool on startup. spring.artemis.pool.enabled=false # Whether a JmsPoolConnectionFactory should be created, instead of a regular ConnectionFactory. - spring.artemis.pool.expiry-timeout=0ms # Connection expiration timeout. spring.artemis.pool.idle-timeout=30s # Connection idle timeout. spring.artemis.pool.max-connections=1 # Maximum number of pooled connections. spring.artemis.pool.max-sessions-per-connection=500 # Maximum number of pooled sessions per connection in the pool. - spring.artemis.pool.reconnect-on-exception=true # Reset the connection when a "JMSException" occurs. spring.artemis.pool.time-between-expiration-check=-1ms # Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs. spring.artemis.pool.use-anonymous-producers=true # Whether to use only one anonymous "MessageProducer" instance. Set it to false to create one "MessageProducer" every time one is required. spring.artemis.port=61616 # Artemis broker port. From 551689c38bfbeb7bde3fc7090a83565d3d0f79cc Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 21 Aug 2018 16:40:47 +0200 Subject: [PATCH 433/701] Switch back to Spring Framework 5.1.0 SNAPSHOTs --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 16e1de452691..7c718abae101 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -153,7 +153,7 @@ 1.7.25 1.21 7.4.0 - 5.1.0.RC2 + 5.1.0.BUILD-SNAPSHOT 2.1.0.M2 4.1.0.M2 2.0.2.RELEASE From 84901fa58e4261ace4633b579cb4339aa87de87d Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 21 Aug 2018 18:59:34 -0700 Subject: [PATCH 434/701] OnClassCondition report should only include relevant condition Closes gh-11086 --- .../condition/OnClassCondition.java | 2 +- .../condition/ConditionalOnClassTests.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java index cd80f8b02066..4b6b535df9fa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java @@ -158,7 +158,7 @@ private List getCandidates(AnnotatedTypeMetadata metadata, MultiValueMap attributes = metadata .getAllAnnotationAttributes(annotationType.getName(), true); if (attributes == null) { - return Collections.emptyList(); + return null; } List candidates = new ArrayList<>(); addAll(candidates, attributes.get("value")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java index 087771c93d62..ebbcbbe898c9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.condition; +import java.util.Collection; + import org.junit.Test; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; @@ -68,6 +70,20 @@ public void testOnClassConditionWithCombinedXml() { .run(this::hasBarBean); } + @Test + public void onClassConditionOutputShouldNotContainConditionalOnMissingClassInMessage() { + this.contextRunner.withUserConfiguration(BasicConfiguration.class) + .run((context) -> { + Collection conditionAndOutcomes = ConditionEvaluationReport + .get(context.getSourceApplicationContext().getBeanFactory()) + .getConditionAndOutcomesBySource().values(); + String message = conditionAndOutcomes.iterator().next().iterator() + .next().getOutcome().getMessage(); + assertThat(message).doesNotContain( + "@ConditionalOnMissingClass did not find unwanted class"); + }); + } + private void hasBarBean(AssertableApplicationContext context) { assertThat(context).hasBean("bar"); assertThat(context.getBean("bar")).isEqualTo("bar"); From c95b339f02f892aa805a2bae906fc30ffe18a450 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 21 Aug 2018 00:51:26 +0900 Subject: [PATCH 435/701] Polish Closes gh-14149 --- .../data/jpa/JpaRepositoriesAutoConfiguration.java | 2 +- .../data/jpa/JpaRepositoriesAutoConfigurationTests.java | 6 +++--- .../task/TaskSchedulingAutoConfigurationTests.java | 6 +++--- .../data/ldap/DataLdapTestPropertiesIntegrationTests.java | 2 +- .../data/mongo/DataMongoTestPropertiesIntegrationTests.java | 2 +- .../data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java | 2 +- .../data/redis/DataRedisTestPropertiesIntegrationTests.java | 2 +- .../jdbc/JdbcTestPropertiesIntegrationTests.java | 2 +- .../jooq/JooqTestPropertiesIntegrationTests.java | 2 +- .../json/JsonTestPropertiesIntegrationTests.java | 2 +- .../orm/jpa/DataJpaTestPropertiesIntegrationTests.java | 2 +- .../client/RestClientTestPropertiesIntegrationTests.java | 2 +- .../web/reactive/WebFluxTestPropertiesIntegrationTests.java | 2 +- .../web/servlet/WebMvcTestPropertiesIntegrationTests.java | 2 +- .../oauth2/client/SampleOAuth2ClientApplicationTests.java | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java index 09aaff4e3362..2538e04b5cea 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java @@ -71,7 +71,7 @@ public class JpaRepositoriesAutoConfiguration { @Bean @Conditional(BootstrapExecutorCondition.class) - public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBoostrapExecutorCustomizer( + public EntityManagerFactoryBuilderCustomizer entityManagerFactoryBootstrapExecutorCustomizer( ObjectProvider taskExecutor) { return (builder) -> builder.setBootstrapExecutor(taskExecutor.getIfAvailable()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java index 2865daca9777..65da36a2e9fd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java @@ -87,7 +87,7 @@ public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRep } @Test - public void whenBootstrappingModeIsLazyBoostrapExecutorIsConfigured() { + public void whenBootstrappingModeIsLazyBootstrapExecutorIsConfigured() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.data.jpa.repositories.bootstrap-mode=lazy") .run((context) -> assertThat( @@ -96,7 +96,7 @@ public void whenBootstrappingModeIsLazyBoostrapExecutorIsConfigured() { } @Test - public void whenBootstrappingModeIsDeferredBoostrapExecutorIsConfigured() { + public void whenBootstrappingModeIsDeferredBootstrapExecutorIsConfigured() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues( "spring.data.jpa.repositories.bootstrap-mode=deferred") @@ -106,7 +106,7 @@ public void whenBootstrappingModeIsDeferredBoostrapExecutorIsConfigured() { } @Test - public void whenBootstrappingModeIsDefaultBoostrapExecutorIsNotConfigured() { + public void whenBootstrappingModeIsDefaultBootstrapExecutorIsNotConfigured() { this.contextRunner.withUserConfiguration(TestConfiguration.class) .withPropertyValues("spring.data.jpa.repositories.bootstrap-mode=default") .run((context) -> assertThat( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java index 9f3824fd412f..6ce10dcc183b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java @@ -54,7 +54,7 @@ public void noSchedulingDoesNotExposeTaskScheduler() { } @Test - public void enableSchedulingWithNoTakExecutorAutoConfiguresOne() { + public void enableSchedulingWithNoTaskExecutorAutoConfiguresOne() { this.contextRunner .withPropertyValues( "spring.task.scheduling.thread-name-prefix=scheduling-test-") @@ -68,7 +68,7 @@ public void enableSchedulingWithNoTakExecutorAutoConfiguresOne() { } @Test - public void enableSchedulingWithNoTakExecutorAppliesCustomizers() { + public void enableSchedulingWithNoTaskExecutorAppliesCustomizers() { this.contextRunner .withPropertyValues( "spring.task.scheduling.thread-name-prefix=scheduling-test-") @@ -84,7 +84,7 @@ public void enableSchedulingWithNoTakExecutorAppliesCustomizers() { } @Test - public void enableSchedulingWithExistingTakSchedulerBacksOff() { + public void enableSchedulingWithExistingTaskSchedulerBacksOff() { this.contextRunner.withUserConfiguration(SchedulingConfiguration.class, TaskSchedulerConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(TaskScheduler.class); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java index 3eaa4334d11a..df32e11429c0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class DataLdapTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java index 78016e032336..c3f298993e0b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class DataMongoTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index 592bc8500e44..161f2dce5384 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -49,7 +49,7 @@ public class DataNeo4jTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java index e6520c6fd2fb..467007f48f44 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java @@ -49,7 +49,7 @@ public class DataRedisTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java index 0b1b9cea0939..c4cdfdd0b3f2 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class JdbcTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java index ef2174d7b368..637998dc582a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class JooqTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java index a991712458c6..10bc2ec20b2d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class JsonTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java index 622eccabe5bb..bf46e4ad2a16 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class DataJpaTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java index 6f27c2548944..5eb857064fc0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class RestClientTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java index 420ea0db869f..330ac5562a6b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class WebFluxTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java index 67cbbb6ce4fe..eef8fbdc7ab4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java @@ -39,7 +39,7 @@ public class WebMvcTestPropertiesIntegrationTests { private Environment environment; @Test - public void environmentWitNewProfile() { + public void environmentWithNewProfile() { String profile = this.environment.getActiveProfiles()[0]; assertThat(profile).isEqualTo("test"); } diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java index 0c04fabb2f70..254dc3140561 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java @@ -35,7 +35,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret", "YAHOO-CLIENT-ID=my-yahoo-client-id", - "YAHOO-CLIENT-SECRET=my-yahooo-client-secret" }) + "YAHOO-CLIENT-SECRET=my-yahoo-client-secret" }) public class SampleOAuth2ClientApplicationTests { @LocalServerPort From 1bd52bc4324a1089c311ffd4adeacfabf05803c4 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Fri, 20 Jul 2018 18:14:56 +0300 Subject: [PATCH 436/701] Add PropertyMapper.from(value) See gh-13837 --- .../batch/BasicBatchConfigurer.java | 2 +- ...fkaListenerContainerFactoryConfigurer.java | 5 ++-- .../TomcatWebServerFactoryCustomizer.java | 2 +- .../UndertowWebServerFactoryCustomizer.java | 2 +- .../web/servlet/MultipartProperties.java | 8 +++--- .../context/properties/PropertyMapper.java | 12 ++++++++ .../boot/task/TaskExecutorBuilder.java | 15 +++++----- .../boot/task/TaskSchedulerBuilder.java | 4 +-- .../client/WebServiceTemplateBuilder.java | 11 ++++---- .../properties/PropertyMapperTests.java | 28 ++++++++++++++++++- 10 files changed, 62 insertions(+), 27 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java index f14aed862d51..6a91a053be4d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java @@ -122,7 +122,7 @@ protected JobLauncher createJobLauncher() throws Exception { protected JobRepository createJobRepository() throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); PropertyMapper map = PropertyMapper.get(); - map.from(() -> this.dataSource).to(factory::setDataSource); + map.from(this.dataSource).to(factory::setDataSource); map.from(this::determineIsolationLevel).whenNonNull() .to(factory::setIsolationLevelForCreate); map.from(this.properties::getTablePrefix).whenHasText() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java index 5a12fad006e2..bdc00693f574 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java @@ -85,9 +85,8 @@ private void configureListenerFactory( PropertyMapper map = PropertyMapper.get(); Listener properties = this.properties.getListener(); map.from(properties::getConcurrency).whenNonNull().to(factory::setConcurrency); - map.from(() -> this.messageConverter).whenNonNull() - .to(factory::setMessageConverter); - map.from(() -> this.replyTemplate).whenNonNull().to(factory::setReplyTemplate); + map.from(this.messageConverter).whenNonNull().to(factory::setMessageConverter); + map.from(this.replyTemplate).whenNonNull().to(factory::setReplyTemplate); map.from(properties::getType).whenEqualTo(Listener.Type.BATCH) .toCall(() -> factory.setBatchListener(true)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 356369611222..06a4dc21fcf2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -84,7 +84,7 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { tomcatProperties.getMaxThreads())); propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive) .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads)); - propertyMapper.from(() -> determineMaxHttpHeaderSize()).when(this::isPositive) + propertyMapper.from(this::determineMaxHttpHeaderSize).when(this::isPositive) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java index 43f350d59b96..985128cfd3d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java @@ -81,7 +81,7 @@ public void customize(ConfigurableUndertowWebServerFactory factory) { .to(factory::setAccessLogSuffix); propertyMapper.from(accesslogProperties::isRotate) .to(factory::setAccessLogRotate); - propertyMapper.from(() -> getOrDeduceUseForwardHeaders()) + propertyMapper.from(this::getOrDeduceUseForwardHeaders) .to(factory::setUseForwardHeaders); propertyMapper.from(properties::getMaxHttpHeaderSize).when(this::isPositive) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java index 8331ff0bf662..8a43adbd2fae 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java @@ -138,10 +138,10 @@ public void setResolveLazily(boolean resolveLazily) { public MultipartConfigElement createMultipartConfig() { MultipartConfigFactory factory = new MultipartConfigFactory(); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(() -> this.fileSizeThreshold).to(factory::setFileSizeThreshold); - map.from(() -> this.location).whenHasText().to(factory::setLocation); - map.from(() -> this.maxRequestSize).to(factory::setMaxRequestSize); - map.from(() -> this.maxFileSize).to(factory::setMaxFileSize); + map.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold); + map.from(this.location).whenHasText().to(factory::setLocation); + map.from(this.maxRequestSize).to(factory::setMaxRequestSize); + map.from(this.maxFileSize).to(factory::setMaxFileSize); return factory.createMultipartConfig(); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java index 75ba1d9d9bd1..cbe9ad0ddbf8 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java @@ -91,6 +91,18 @@ public PropertyMapper alwaysApplying(SourceOperator operator) { return new PropertyMapper(this, operator); } + /** + * Return a new {@link Source} from the specified value that can be used to perform + * the mapping. + * @param the source type + * @param value the value + * @return a {@link Source} that can be used to complete the mapping + * @see #from(Supplier) + */ + public Source from(T value) { + return from(() -> value); + } + /** * Return a new {@link Source} from the specified value supplier that can be used to * perform the mapping. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java index ca11bb530c11..2e959f286460 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java @@ -279,16 +279,15 @@ public T build(Class taskExecutorClass) { */ public T configure(T taskExecutor) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(() -> this.queueCapacity).to(taskExecutor::setQueueCapacity); - map.from(() -> this.corePoolSize).to(taskExecutor::setCorePoolSize); - map.from(() -> this.maxPoolSize).to(taskExecutor::setMaxPoolSize); - map.from(() -> this.keepAlive).asInt(Duration::getSeconds) + map.from(this.queueCapacity).to(taskExecutor::setQueueCapacity); + map.from(this.corePoolSize).to(taskExecutor::setCorePoolSize); + map.from(this.maxPoolSize).to(taskExecutor::setMaxPoolSize); + map.from(this.keepAlive).asInt(Duration::getSeconds) .to(taskExecutor::setKeepAliveSeconds); - map.from(() -> this.allowCoreThreadTimeOut) - .to(taskExecutor::setAllowCoreThreadTimeOut); - map.from(() -> this.threadNamePrefix).whenHasText() + map.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut); + map.from(this.threadNamePrefix).whenHasText() .to(taskExecutor::setThreadNamePrefix); - map.from(() -> this.taskDecorator).to(taskExecutor::setTaskDecorator); + map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator); if (!CollectionUtils.isEmpty(this.taskExecutorCustomizers)) { for (TaskExecutorCustomizer customizer : this.taskExecutorCustomizers) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java index 228ca4c4370f..ed4f71916c7a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java @@ -167,8 +167,8 @@ public ThreadPoolTaskScheduler build() { */ public T configure(T taskScheduler) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(() -> this.poolSize).to(taskScheduler::setPoolSize); - map.from(() -> this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix); + map.from(this.poolSize).to(taskScheduler::setPoolSize); + map.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix); if (!CollectionUtils.isEmpty(this.taskSchedulerCustomizers)) { for (TaskSchedulerCustomizer customizer : this.taskSchedulerCustomizers) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java index 1baf8d7196c9..5481a8470298 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -502,13 +502,12 @@ public T configure(T webServiceTemplate) { configureMessageSenders(webServiceTemplate); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); applyCustomizers(webServiceTemplate, this.internalCustomizers); - map.from(() -> this.marshaller).to(webServiceTemplate::setMarshaller); - map.from(() -> this.unmarshaller).to(webServiceTemplate::setUnmarshaller); - map.from(() -> this.destinationProvider) - .to(webServiceTemplate::setDestinationProvider); - map.from(() -> this.transformerFactoryClass) + map.from(this.marshaller).to(webServiceTemplate::setMarshaller); + map.from(this.unmarshaller).to(webServiceTemplate::setUnmarshaller); + map.from(this.destinationProvider).to(webServiceTemplate::setDestinationProvider); + map.from(this.transformerFactoryClass) .to(webServiceTemplate::setTransformerFactoryClass); - map.from(() -> this.messageFactory).to(webServiceTemplate::setMessageFactory); + map.from(this.messageFactory).to(webServiceTemplate::setMessageFactory); if (!CollectionUtils.isEmpty(this.interceptors)) { Set merged = new LinkedHashSet<>(this.interceptors); if (webServiceTemplate.getInterceptors() != null) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java index c29317651720..5318986d6d87 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java @@ -37,11 +37,37 @@ public class PropertyMapperTests { @Rule public ExpectedException thrown = ExpectedException.none(); + @Test + public void fromNullValue() { + ExampleDest dest = new ExampleDest(); + this.map.from((String) null).to(dest::setName); + assertThat(dest.getName()).isNull(); + } + + @Test + public void fromValue() { + ExampleDest dest = new ExampleDest(); + this.map.from("Hello World").to(dest::setName); + assertThat(dest.getName()).isEqualTo("Hello World"); + } + + @Test + public void fromValueAsIntShouldAdaptSupplier() { + Integer result = this.map.from("123").asInt(Long::valueOf) + .toInstance(Integer::new); + assertThat(result).isEqualTo(123); + } + + @Test + public void fromValueAlwaysApplyingWhenNonNullShouldAlwaysApplyNonNullToSource() { + this.map.alwaysApplyingWhenNonNull().from((String) null).toCall(Assert::fail); + } + @Test public void fromWhenSupplierIsNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Supplier must not be null"); - this.map.from(null); + this.map.from((Supplier) null); } @Test From 597fe237b5c84f24cfa64a92c8650a32e6842dc2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 22 Aug 2018 15:35:52 +0200 Subject: [PATCH 437/701] Polish "Add PropertyMapper.from(value)" Closes gh-13837 --- .../batch/BasicBatchConfigurer.java | 2 +- .../context/properties/PropertyMapper.java | 24 +++++++++---------- .../properties/PropertyMapperTests.java | 24 +++++++++---------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java index 6a91a053be4d..862d6a726668 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BasicBatchConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java index cbe9ad0ddbf8..fb5a301a2dba 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java @@ -91,24 +91,13 @@ public PropertyMapper alwaysApplying(SourceOperator operator) { return new PropertyMapper(this, operator); } - /** - * Return a new {@link Source} from the specified value that can be used to perform - * the mapping. - * @param the source type - * @param value the value - * @return a {@link Source} that can be used to complete the mapping - * @see #from(Supplier) - */ - public Source from(T value) { - return from(() -> value); - } - /** * Return a new {@link Source} from the specified value supplier that can be used to * perform the mapping. * @param the source type * @param supplier the value supplier * @return a {@link Source} that can be used to complete the mapping + * @see #from(Object) */ public Source from(Supplier supplier) { Assert.notNull(supplier, "Supplier must not be null"); @@ -119,6 +108,17 @@ public Source from(Supplier supplier) { return source; } + /** + * Return a new {@link Source} from the specified value that can be used to perform + * the mapping. + * @param the source type + * @param value the value + * @return a {@link Source} that can be used to complete the mapping + */ + public Source from(T value) { + return from(() -> value); + } + @SuppressWarnings("unchecked") private Source getSource(Supplier supplier) { if (this.parent != null) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java index 5318986d6d87..7b0d5ef985e5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java @@ -120,24 +120,24 @@ public void whenNonNullWhenSuppliedThrowsNullPointerExceptionShouldNotMap() { @Test public void whenTrueWhenValueIsTrueShouldMap() { - Boolean result = this.map.from(() -> true).whenTrue().toInstance(Boolean::new); + Boolean result = this.map.from(true).whenTrue().toInstance(Boolean::new); assertThat(result).isTrue(); } @Test public void whenTrueWhenValueIsFalseShouldNotMap() { - this.map.from(() -> false).whenTrue().toCall(Assert::fail); + this.map.from(false).whenTrue().toCall(Assert::fail); } @Test public void whenFalseWhenValueIsFalseShouldMap() { - Boolean result = this.map.from(() -> false).whenFalse().toInstance(Boolean::new); + Boolean result = this.map.from(false).whenFalse().toInstance(Boolean::new); assertThat(result).isFalse(); } @Test public void whenFalseWhenValueIsTrueShouldNotMap() { - this.map.from(() -> true).whenFalse().toCall(Assert::fail); + this.map.from(true).whenFalse().toCall(Assert::fail); } @Test @@ -147,30 +147,29 @@ public void whenHasTextWhenValueIsNullShouldNotMap() { @Test public void whenHasTextWhenValueIsEmptyShouldNotMap() { - this.map.from(() -> "").whenHasText().toCall(Assert::fail); + this.map.from("").whenHasText().toCall(Assert::fail); } @Test public void whenHasTextWhenValueHasTextShouldMap() { - Integer result = this.map.from(() -> 123).whenHasText().toInstance(Integer::new); + Integer result = this.map.from(123).whenHasText().toInstance(Integer::new); assertThat(result).isEqualTo(123); } @Test public void whenEqualToWhenValueIsEqualShouldMatch() { - String result = this.map.from(() -> "123").whenEqualTo("123") - .toInstance(String::new); + String result = this.map.from("123").whenEqualTo("123").toInstance(String::new); assertThat(result).isEqualTo("123"); } @Test public void whenEqualToWhenValueIsNotEqualShouldNotMatch() { - this.map.from(() -> "123").whenEqualTo("321").toCall(Assert::fail); + this.map.from("123").whenEqualTo("321").toCall(Assert::fail); } @Test public void whenInstanceOfWhenValueIsTargetTypeShouldMatch() { - Long result = this.map.from(() -> 123L).whenInstanceOf(Long.class) + Long result = this.map.from(123L).whenInstanceOf(Long.class) .toInstance((value) -> value + 1); assertThat(result).isEqualTo(124L); } @@ -183,14 +182,13 @@ public void whenInstanceOfWhenValueIsNotTargetTypeShouldNotMatch() { @Test public void whenWhenValueMatchesShouldMap() { - String result = this.map.from(() -> "123").when("123"::equals) - .toInstance(String::new); + String result = this.map.from("123").when("123"::equals).toInstance(String::new); assertThat(result).isEqualTo("123"); } @Test public void whenWhenValueDoesNotMatchShouldNotMap() { - this.map.from(() -> "123").when("321"::equals).toCall(Assert::fail); + this.map.from("123").when("321"::equals).toCall(Assert::fail); } @Test From a7acbbd625cf0a2265ce716b29e5f285b86f1848 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Wed, 8 Aug 2018 14:42:15 -0400 Subject: [PATCH 438/701] Add Kafka Streams auto-configuration See gh-14021 --- .../spring-boot-autoconfigure/pom.xml | 5 + .../kafka/KafkaAutoConfiguration.java | 62 +++++++ .../autoconfigure/kafka/KafkaProperties.java | 156 +++++++++++++++++- .../kafka/KafkaAutoConfigurationTests.java | 66 ++++++++ .../appendix-application-properties.adoc | 21 ++- .../main/asciidoc/spring-boot-features.adoc | 49 +++++- 6 files changed, 349 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index f9e08b16b759..da28b3c8b4e1 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -132,6 +132,11 @@ jest true + + org.apache.kafka + kafka-streams + true + org.flywaydb flyway-core diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java index 0bc7e88e2c98..5b4d253e67b7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java @@ -17,7 +17,11 @@ package org.springframework.boot.autoconfigure.kafka; import java.io.IOException; +import java.util.Map; +import org.apache.kafka.streams.StreamsBuilder; + +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -28,12 +32,17 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; +import org.springframework.kafka.annotation.EnableKafkaStreams; +import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; +import org.springframework.kafka.config.KafkaStreamsConfiguration; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaAdmin; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.core.StreamsBuilderFactoryBean; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.kafka.support.LoggingProducerListener; import org.springframework.kafka.support.ProducerListener; @@ -138,4 +147,57 @@ public KafkaAdmin kafkaAdmin() { return kafkaAdmin; } + @Configuration + @ConditionalOnClass(StreamsBuilder.class) + public static class KafkaStreamsAutoConfiguration { + + @Bean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) + public KafkaStreamsConfiguration defaultKafkaStreamsConfig( + KafkaProperties properties, Environment environment) { + + Map streamsProperties = properties.buildStreamsProperties(); + if (properties.getStreams().getApplicationId() == null) { + if (environment.getProperty("spring.application.id") != null) { + streamsProperties.put("application.id", + environment.getProperty("spring.application.name")); + } + } + return new KafkaStreamsConfiguration(streamsProperties); + } + + @Bean + public KafkaStreamsFactoryBeanConfigurer kafkaStreamsFactoryBeanConfigurer( + StreamsBuilderFactoryBean factoryBean, KafkaProperties properties) { + + return new KafkaStreamsFactoryBeanConfigurer(factoryBean, properties); + } + + @Configuration + @EnableKafkaStreams + public static class EnableKafkaStreamsAutoConfiguration { + + } + + static class KafkaStreamsFactoryBeanConfigurer implements InitializingBean { + + private final StreamsBuilderFactoryBean factoryBean; + + private final KafkaProperties properties; + + KafkaStreamsFactoryBeanConfigurer(StreamsBuilderFactoryBean factoryBean, + KafkaProperties properties) { + this.factoryBean = factoryBean; + this.properties = properties; + } + + @Override + public void afterPropertiesSet() throws Exception { + this.factoryBean + .setAutoStartup(this.properties.getStreams().isAutoStartup()); + } + + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index 5716bcffe8a0..e77cf142f6ea 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -57,7 +57,7 @@ public class KafkaProperties { /** * Comma-delimited list of host:port pairs to use for establishing the initial - * connection to the Kafka cluster. + * connection to the Kafka cluster. Applies to all components unless overridden. */ private List bootstrapServers = new ArrayList<>( Collections.singletonList("localhost:9092")); @@ -79,6 +79,8 @@ public class KafkaProperties { private final Admin admin = new Admin(); + private final Streams streams = new Streams(); + private final Listener listener = new Listener(); private final Ssl ssl = new Ssl(); @@ -123,6 +125,10 @@ public Admin getAdmin() { return this.admin; } + public Streams getStreams() { + return this.streams; + } + public Ssl getSsl() { return this.ssl; } @@ -193,6 +199,19 @@ public Map buildAdminProperties() { return properties; } + /** + * Create an initial map of streams properties from the state of this instance. + *

    + * This allows you to add additional properties, if necessary. + * @return the streams properties initialized with the customizations defined on this + * instance + */ + public Map buildStreamsProperties() { + Map properties = buildCommonProperties(); + properties.putAll(this.streams.buildProperties()); + return properties; + } + public static class Consumer { private final Ssl ssl = new Ssl(); @@ -211,7 +230,7 @@ public static class Consumer { /** * Comma-delimited list of host:port pairs to use for establishing the initial - * connection to the Kafka cluster. + * connection to the Kafka cluster. Overrides the global property, for consumers. */ private List bootstrapServers; @@ -421,7 +440,7 @@ public static class Producer { /** * Comma-delimited list of host:port pairs to use for establishing the initial - * connection to the Kafka cluster. + * connection to the Kafka cluster. Overrides the global property, for producers. */ private List bootstrapServers; @@ -631,6 +650,136 @@ public Map buildProperties() { } + /** + * High (and some medium) priority Streams properties and a general properties bucket. + */ + public static class Streams { + + private final Ssl ssl = new Ssl(); + + /** + * Kafka streams application.id property; default spring.application.name. + */ + private String applicationId; + + /** + * Whether or not to auto-start the streams factory bean. + */ + private boolean autoStartup; + + /** + * Comma-delimited list of host:port pairs to use for establishing the initial + * connection to the Kafka cluster. Overrides the global property, for streams. + */ + private List bootstrapServers; + + /** + * Maximum number of memory bytes to be used for buffering across all threads. + */ + private Integer cacheMaxBytesBuffering; + + /** + * ID to pass to the server when making requests. Used for server-side logging. + */ + private String clientId; + + /** + * The replication factor for change log topics and repartition topics created by + * the stream processing application. + */ + private Integer replicationFactor; + + /** + * Directory location for the state store. + */ + private String stateDir; + + /** + * Additional Kafka properties used to configure the streams. + */ + private final Map properties = new HashMap<>(); + + public Ssl getSsl() { + return this.ssl; + } + + public String getApplicationId() { + return this.applicationId; + } + + public void setApplicationId(String applicationId) { + this.applicationId = applicationId; + } + + public boolean isAutoStartup() { + return this.autoStartup; + } + + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + + public List getBootstrapServers() { + return this.bootstrapServers; + } + + public void setBootstrapServers(List bootstrapServers) { + this.bootstrapServers = bootstrapServers; + } + + public Integer getCacheMaxBytesBuffering() { + return this.cacheMaxBytesBuffering; + } + + public void setCacheMaxBytesBuffering(Integer cacheMaxBytesBuffering) { + this.cacheMaxBytesBuffering = cacheMaxBytesBuffering; + } + + public String getClientId() { + return this.clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Integer getReplicationFactor() { + return this.replicationFactor; + } + + public void setReplicationFactor(Integer replicationFactor) { + this.replicationFactor = replicationFactor; + } + + public String getStateDir() { + return this.stateDir; + } + + public void setStateDir(String stateDir) { + this.stateDir = stateDir; + } + + public Map getProperties() { + return this.properties; + } + + public Map buildProperties() { + Properties properties = new Properties(); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(this::getApplicationId).to(properties.in("application.id")); + map.from(this::getBootstrapServers) + .to(properties.in(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG)); + map.from(this::getCacheMaxBytesBuffering) + .to(properties.in("cache.max.bytes.buffering")); + map.from(this::getClientId) + .to(properties.in(CommonClientConfigs.CLIENT_ID_CONFIG)); + map.from(this::getReplicationFactor).to(properties.in("replication.factor")); + map.from(this::getStateDir).to(properties.in("state.dir")); + return properties.with(this.ssl, this.properties); + } + + } + public static class Template { /** @@ -1011,6 +1160,7 @@ public void setOptions(Map options) { } + @SuppressWarnings("serial") private static class Properties extends HashMap { public java.util.function.Consumer in(String key) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 3e91f1d12c67..660810754485 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -19,6 +19,7 @@ import java.io.File; import java.util.Collections; import java.util.Map; +import java.util.Properties; import javax.security.auth.login.AppConfigurationEntry; @@ -30,6 +31,7 @@ import org.apache.kafka.common.serialization.IntegerSerializer; import org.apache.kafka.common.serialization.LongDeserializer; import org.apache.kafka.common.serialization.LongSerializer; +import org.apache.kafka.streams.StreamsConfig; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; @@ -37,8 +39,10 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.config.KafkaListenerContainerFactory; +import org.springframework.kafka.config.KafkaStreamsConfiguration; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaAdmin; @@ -273,6 +277,68 @@ public void adminProperties() { }); } + @Test + public void streamsProperties() { + this.contextRunner.withPropertyValues("spring.kafka.clientId=cid", + "spring.kafka.bootstrap-servers=localhost:9092,localhost:9093", + "spring.application.name=appName", + "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", + "spring.kafka.streams.cache-max-bytes-buffering=42", + "spring.kafka.streams.client-id=override", + "spring.kafka.streams.properties.fiz.buz=fix.fox", + "spring.kafka.streams.replication-factor=2", + "spring.kafka.streams.state-dir=/tmp/state", + "spring.kafka.streams.ssl.key-password=p7", + "spring.kafka.streams.ssl.key-store-location=classpath:ksLocP", + "spring.kafka.streams.ssl.key-store-password=p8", + "spring.kafka.streams.ssl.key-store-type=PKCS12", + "spring.kafka.streams.ssl.trust-store-location=classpath:tsLocP", + "spring.kafka.streams.ssl.trust-store-password=p9", + "spring.kafka.streams.ssl.trust-store-type=PKCS12", + "spring.kafka.streams.ssl.protocol=TLSv1.2").run((context) -> { + Properties configs = context.getBean( + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, + KafkaStreamsConfiguration.class).asProperties(); + assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + .isEqualTo("localhost:9092, localhost:9093"); + assertThat( + configs.get(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG)) + .isEqualTo("42"); + assertThat(configs.get(StreamsConfig.CLIENT_ID_CONFIG)) + .isEqualTo("override"); + assertThat(configs.get(StreamsConfig.REPLICATION_FACTOR_CONFIG)) + .isEqualTo("2"); + assertThat(configs.get(StreamsConfig.STATE_DIR_CONFIG)) + .isEqualTo("/tmp/state"); + assertThat(configs.get(SslConfigs.SSL_KEY_PASSWORD_CONFIG)) + .isEqualTo("p7"); + assertThat( + (String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG)) + .endsWith(File.separator + "ksLocP"); + assertThat(configs.get(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG)) + .isEqualTo("p8"); + assertThat(configs.get(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG)) + .isEqualTo("PKCS12"); + assertThat((String) configs + .get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG)) + .endsWith(File.separator + "tsLocP"); + assertThat(configs.get(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG)) + .isEqualTo("p9"); + assertThat(configs.get(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG)) + .isEqualTo("PKCS12"); + assertThat(configs.get(SslConfigs.SSL_PROTOCOL_CONFIG)) + .isEqualTo("TLSv1.2"); + assertThat( + context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)) + .isEmpty(); + assertThat(configs.get("foo.bar.baz")).isEqualTo("qux.fiz.buz"); + assertThat(configs.get("fiz.buz")).isEqualTo("fix.fox"); + assertThat(context.getBean( + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME)) + .isNotNull(); + }); + } + @SuppressWarnings("unchecked") @Test public void listenerProperties() { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 571a7e34fe8c..d8b264da78f7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1039,11 +1039,11 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.admin.ssl.trust-store-location= # Location of the trust store file. spring.kafka.admin.ssl.trust-store-password= # Store password for the trust store file. spring.kafka.admin.ssl.trust-store-type= # Type of the trust store. - spring.kafka.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. + spring.kafka.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Applies to all components unless overridden. spring.kafka.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.consumer.auto-commit-interval= # Frequency with which the consumer offsets are auto-committed to Kafka if 'enable.auto.commit' is set to true. spring.kafka.consumer.auto-offset-reset= # What to do when there is no initial offset in Kafka or if the current offset no longer exists on the server. - spring.kafka.consumer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. + spring.kafka.consumer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Overrides the global property, for consumers. spring.kafka.consumer.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.consumer.enable-auto-commit= # Whether the consumer's offset is periodically committed in the background. spring.kafka.consumer.fetch-max-wait= # Maximum amount of time the server blocks before answering the fetch request if there isn't sufficient data to immediately satisfy the requirement given by "fetch.min.bytes". @@ -1079,7 +1079,7 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.listener.type=single # Listener type. spring.kafka.producer.acks= # Number of acknowledgments the producer requires the leader to have received before considering a request complete. spring.kafka.producer.batch-size= # Default batch size in bytes. - spring.kafka.producer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. + spring.kafka.producer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Overrides the global property, for producers. spring.kafka.producer.buffer-memory= # Total bytes of memory the producer can use to buffer records waiting to be sent to the server. spring.kafka.producer.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.producer.compression-type= # Compression type for all data generated by the producer. @@ -1105,6 +1105,21 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.ssl.trust-store-location= # Location of the trust store file. spring.kafka.ssl.trust-store-password= # Store password for the trust store file. spring.kafka.ssl.trust-store-type= # Type of the trust store. + spring.kafka.streams.auto-startup= # Whether or not to auto-start the streams factory bean. + spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Overrides the global property, for streams. + spring.kafka.streams.cache-max-bytes-buffering= # Maximum number of memory bytes to be used for buffering across all threads. + spring.kafka.streams.client-id= # ID to pass to the server when making requests. Used for server-side logging. + spring.kafka.streams.properties.*= # Additional Kafka properties used to configure the streams. + spring.kafka.streams.replication-factor= # The replication factor for change log topics and repartition topics created by the stream processing application. + spring.kafka.streams.ssl.key-password= # Password of the private key in the key store file. + spring.kafka.streams.ssl.key-store-location= # Location of the key store file. + spring.kafka.streams.ssl.key-store-password= # Store password for the key store file. + spring.kafka.streams.ssl.key-store-type= # Type of the key store. + spring.kafka.streams.ssl.protocol= # SSL protocol to use. + spring.kafka.streams.ssl.trust-store-location= # Location of the trust store file. + spring.kafka.streams.ssl.trust-store-password= # Store password for the trust store file. + spring.kafka.streams.ssl.trust-store-type= # Type of the trust store. + spring.kafka.streams.state-dir= # Directory location for the state store. spring.kafka.template.default-topic= # Default topic to which messages are sent. # RABBIT ({sc-spring-boot-autoconfigure}/amqp/RabbitProperties.{sc-ext}[RabbitProperties]) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index f45f4d509c1e..d3bfaeb4799c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,6 +5634,44 @@ The following component creates a listener endpoint on the `someTopic` topic: } ---- +[[boot-deatures-kafka-streams]] +==== Kafka Streams + +Spring for Apache Kafka provides a factory bean to create a `StreamsBuilder` object and +manage the lifecycle of its streams; the factory bean is created when +`@EnableKafkaStreams` is present on a `@Configuration` class. +The factory bean requires a `KafkaStreamsConfiguration` object for streams configuration. + +If Spring Boot detects the `kafka-streams` jar on the classpath, it will auto-configure +the `KafkaStreamsConfiguration` bean from the `KafkaProperties` object as well as enabling +the creation of the factory bean by spring-kafka. + +There are two required Kafka properties for streams (`bootstrap.servers` and +`application.id`); by default, the `application.id` is set to the `spring.application.name` +property, if present. +The `bootstrap.servers` can be set globally or specifically overridden just for streams. +Several other properties are specifically available as boot properties; other arbitrary +Kafka properties can be set using the `spring.kafka.streams.properties` property. +See <> for more information. + +To use the factory bean, simply wire its `StreamsBuilder` into your `@Bean` s. + +==== +[source, java] +---- +@Bean +public KStream kStream(StreamsBuilder streamsBuilder) { + KStream stream = streamsBuilder.stream("ks1In"); + stream.map((k, v) -> new KeyValue(k, v.toUpperCase())) + .to("ks1Out", Produced.with(Serdes.Integer(), new JsonSerde<>())); + return stream; +} +---- +==== + +By default, the factory bean `autoStartup` property is false; to automatically start the +streams managed by the `StreamsBuilder` object it creates, set property +`spting.kafka.streams.auto-startup=true`. [[boot-features-kafka-extra-props]] @@ -5643,13 +5681,14 @@ The properties supported by auto configuration are shown in (hyphenated or camelCase) map directly to the Apache Kafka dotted properties. Refer to the Apache Kafka documentation for details. -The first few of these properties apply to both producers and consumers but can be -specified at the producer or consumer level if you wish to use different values for each. +The first few of these properties apply to all components (producers, consumers, admins, +and streams) but can be +specified at the component level if you wish to use different values. Apache Kafka designates properties with an importance of HIGH, MEDIUM, or LOW. Spring Boot auto-configuration supports all HIGH importance properties, some selected MEDIUM and LOW properties, and any properties that do not have a default value. -Only a subset of the properties supported by Kafka are available through the +Only a subset of the properties supported by Kafka are available directly through the `KafkaProperties` class. If you wish to configure the producer or consumer with additional properties that are not directly supported, use the following properties: @@ -5659,11 +5698,13 @@ properties that are not directly supported, use the following properties: spring.kafka.admin.properties.prop.two=second spring.kafka.consumer.properties.prop.three=third spring.kafka.producer.properties.prop.four=fourth + spring.kafka.streams.properties.prop.five=fifth ---- This sets the common `prop.one` Kafka property to `first` (applies to producers, consumers and admins), the `prop.two` admin property to `second`, the `prop.three` -consumer property to `third` and the `prop.four` producer property to `fourth`. +consumer property to `third`, the `prop.four` producer property to `fourth` and the +`prop.five` streams property to `fifth`. You can also configure the Spring Kafka `JsonDeserializer` as follows: From 6d4bab911cdfb79171b5b71c7e7f2785a1654a50 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 16 Aug 2018 18:15:52 +0200 Subject: [PATCH 439/701] Polish "Add Kafka Streams auto-configuration" Closes gh-14021 --- .../kafka/KafkaAutoConfiguration.java | 65 +--------- .../autoconfigure/kafka/KafkaProperties.java | 2 +- ...aStreamsAnnotationDrivenConfiguration.java | 98 +++++++++++++++ ...afkaAutoConfigurationIntegrationTests.java | 21 +++- .../kafka/KafkaAutoConfigurationTests.java | 118 +++++++++++++++--- spring-boot-project/spring-boot-docs/pom.xml | 5 + .../appendix-application-properties.adoc | 3 +- .../main/asciidoc/spring-boot-features.adoc | 50 +++----- .../docs/kafka/KafkaStreamsBeanExample.java | 53 ++++++++ 9 files changed, 302 insertions(+), 113 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java index 5b4d253e67b7..7750b3fd5c2b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfiguration.java @@ -17,11 +17,7 @@ package org.springframework.boot.autoconfigure.kafka; import java.io.IOException; -import java.util.Map; -import org.apache.kafka.streams.StreamsBuilder; - -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -32,17 +28,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.env.Environment; -import org.springframework.kafka.annotation.EnableKafkaStreams; -import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; -import org.springframework.kafka.config.KafkaStreamsConfiguration; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaAdmin; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; -import org.springframework.kafka.core.StreamsBuilderFactoryBean; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.kafka.support.LoggingProducerListener; import org.springframework.kafka.support.ProducerListener; @@ -61,7 +52,8 @@ @Configuration @ConditionalOnClass(KafkaTemplate.class) @EnableConfigurationProperties(KafkaProperties.class) -@Import(KafkaAnnotationDrivenConfiguration.class) +@Import({ KafkaAnnotationDrivenConfiguration.class, + KafkaStreamsAnnotationDrivenConfiguration.class }) public class KafkaAutoConfiguration { private final KafkaProperties properties; @@ -147,57 +139,4 @@ public KafkaAdmin kafkaAdmin() { return kafkaAdmin; } - @Configuration - @ConditionalOnClass(StreamsBuilder.class) - public static class KafkaStreamsAutoConfiguration { - - @Bean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) - public KafkaStreamsConfiguration defaultKafkaStreamsConfig( - KafkaProperties properties, Environment environment) { - - Map streamsProperties = properties.buildStreamsProperties(); - if (properties.getStreams().getApplicationId() == null) { - if (environment.getProperty("spring.application.id") != null) { - streamsProperties.put("application.id", - environment.getProperty("spring.application.name")); - } - } - return new KafkaStreamsConfiguration(streamsProperties); - } - - @Bean - public KafkaStreamsFactoryBeanConfigurer kafkaStreamsFactoryBeanConfigurer( - StreamsBuilderFactoryBean factoryBean, KafkaProperties properties) { - - return new KafkaStreamsFactoryBeanConfigurer(factoryBean, properties); - } - - @Configuration - @EnableKafkaStreams - public static class EnableKafkaStreamsAutoConfiguration { - - } - - static class KafkaStreamsFactoryBeanConfigurer implements InitializingBean { - - private final StreamsBuilderFactoryBean factoryBean; - - private final KafkaProperties properties; - - KafkaStreamsFactoryBeanConfigurer(StreamsBuilderFactoryBean factoryBean, - KafkaProperties properties) { - this.factoryBean = factoryBean; - this.properties = properties; - } - - @Override - public void afterPropertiesSet() throws Exception { - this.factoryBean - .setAutoStartup(this.properties.getStreams().isAutoStartup()); - } - - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index e77cf142f6ea..a02450cd6263 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -665,7 +665,7 @@ public static class Streams { /** * Whether or not to auto-start the streams factory bean. */ - private boolean autoStartup; + private boolean autoStartup = true; /** * Comma-delimited list of host:port pairs to use for establishing the initial diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java new file mode 100644 index 000000000000..7e48a87ceed0 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2018 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.autoconfigure.kafka; + +import java.util.Map; + +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.StreamsConfig; + +import org.springframework.beans.factory.InitializingBean; +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.context.properties.source.InvalidConfigurationPropertyValueException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; +import org.springframework.kafka.config.KafkaStreamsConfiguration; +import org.springframework.kafka.core.StreamsBuilderFactoryBean; + +/** + * Configuration for Kafka Streams annotation-driven support. + * + * @author Gary Russell + * @author Stephane Nicoll + */ +@Configuration +@ConditionalOnClass(StreamsBuilder.class) +@ConditionalOnBean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME) +class KafkaStreamsAnnotationDrivenConfiguration { + + private final KafkaProperties properties; + + KafkaStreamsAnnotationDrivenConfiguration(KafkaProperties properties) { + this.properties = properties; + } + + @ConditionalOnMissingBean + @Bean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) + public KafkaStreamsConfiguration defaultKafkaStreamsConfig(Environment environment) { + Map streamsProperties = this.properties.buildStreamsProperties(); + if (this.properties.getStreams().getApplicationId() == null) { + String applicationName = environment.getProperty("spring.application.name"); + if (applicationName != null) { + streamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, + applicationName); + } + else { + throw new InvalidConfigurationPropertyValueException( + "spring.kafka.streams.application-id", null, + "This property is mandatory and fallback 'spring.application.name' is not set either."); + } + } + return new KafkaStreamsConfiguration(streamsProperties); + } + + @Bean + public KafkaStreamsFactoryBeanConfigurer kafkaStreamsFactoryBeanConfigurer( + StreamsBuilderFactoryBean factoryBean) { + return new KafkaStreamsFactoryBeanConfigurer(this.properties, factoryBean); + } + + // Separate class required to avoid BeanCurrentlyInCreationException + static class KafkaStreamsFactoryBeanConfigurer implements InitializingBean { + + private final KafkaProperties properties; + + private final StreamsBuilderFactoryBean factoryBean; + + KafkaStreamsFactoryBeanConfigurer(KafkaProperties properties, + StreamsBuilderFactoryBean factoryBean) { + this.properties = properties; + this.factoryBean = factoryBean; + } + + @Override + public void afterPropertiesSet() { + this.factoryBean.setAutoStartup(this.properties.getStreams().isAutoStartup()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java index 7a6e773c1698..8dad270aece4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java @@ -28,9 +28,12 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafkaStreams; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.StreamsBuilderFactoryBean; import org.springframework.kafka.support.KafkaHeaders; import org.springframework.kafka.test.rule.EmbeddedKafkaRule; import org.springframework.messaging.handler.annotation.Header; @@ -41,6 +44,7 @@ * Integration tests for {@link KafkaAutoConfiguration}. * * @author Gary Russell + * @author Stephane Nicoll */ public class KafkaAutoConfigurationIntegrationTests { @@ -83,6 +87,14 @@ public void testEndToEnd() throws Exception { producer.close(); } + @Test + public void testStreams() { + load(KafkaStreamsConfig.class, "spring.application.name:my-app", + "spring.kafka.bootstrap-servers:" + getEmbeddedKafkaBrokersAsString()); + assertThat(this.context.getBean(StreamsBuilderFactoryBean.class).isAutoStartup()) + .isTrue(); + } + private void load(Class config, String... environment) { this.context = doLoad(new Class[] { config }, environment); } @@ -101,7 +113,8 @@ private String getEmbeddedKafkaBrokersAsString() { return embeddedKafka.getEmbeddedKafka().getBrokersAsString(); } - public static class KafkaConfig { + @Configuration + static class KafkaConfig { @Bean public Listener listener() { @@ -115,6 +128,12 @@ public NewTopic adminCreated() { } + @Configuration + @EnableKafkaStreams + static class KafkaStreamsConfig { + + } + public static class Listener { private final CountDownLatch latch = new CountDownLatch(1); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 660810754485..816559e88642 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -18,6 +18,7 @@ import java.io.File; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -31,6 +32,7 @@ import org.apache.kafka.common.serialization.IntegerSerializer; import org.apache.kafka.common.serialization.LongDeserializer; import org.apache.kafka.common.serialization.LongSerializer; +import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.StreamsConfig; import org.junit.Test; @@ -39,6 +41,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafkaStreams; import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.config.KafkaListenerContainerFactory; @@ -279,23 +282,26 @@ public void adminProperties() { @Test public void streamsProperties() { - this.contextRunner.withPropertyValues("spring.kafka.clientId=cid", - "spring.kafka.bootstrap-servers=localhost:9092,localhost:9093", - "spring.application.name=appName", - "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", - "spring.kafka.streams.cache-max-bytes-buffering=42", - "spring.kafka.streams.client-id=override", - "spring.kafka.streams.properties.fiz.buz=fix.fox", - "spring.kafka.streams.replication-factor=2", - "spring.kafka.streams.state-dir=/tmp/state", - "spring.kafka.streams.ssl.key-password=p7", - "spring.kafka.streams.ssl.key-store-location=classpath:ksLocP", - "spring.kafka.streams.ssl.key-store-password=p8", - "spring.kafka.streams.ssl.key-store-type=PKCS12", - "spring.kafka.streams.ssl.trust-store-location=classpath:tsLocP", - "spring.kafka.streams.ssl.trust-store-password=p9", - "spring.kafka.streams.ssl.trust-store-type=PKCS12", - "spring.kafka.streams.ssl.protocol=TLSv1.2").run((context) -> { + this.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class) + .withPropertyValues("spring.kafka.client-id=cid", + "spring.kafka.bootstrap-servers=localhost:9092,localhost:9093", + "spring.application.name=appName", + "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", + "spring.kafka.streams.auto-startup=false", + "spring.kafka.streams.cache-max-bytes-buffering=42", + "spring.kafka.streams.client-id=override", + "spring.kafka.streams.properties.fiz.buz=fix.fox", + "spring.kafka.streams.replication-factor=2", + "spring.kafka.streams.state-dir=/tmp/state", + "spring.kafka.streams.ssl.key-password=p7", + "spring.kafka.streams.ssl.key-store-location=classpath:ksLocP", + "spring.kafka.streams.ssl.key-store-password=p8", + "spring.kafka.streams.ssl.key-store-type=PKCS12", + "spring.kafka.streams.ssl.trust-store-location=classpath:tsLocP", + "spring.kafka.streams.ssl.trust-store-password=p9", + "spring.kafka.streams.ssl.trust-store-type=PKCS12", + "spring.kafka.streams.ssl.protocol=TLSv1.2") + .run((context) -> { Properties configs = context.getBean( KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, KafkaStreamsConfiguration.class).asProperties(); @@ -339,6 +345,63 @@ public void streamsProperties() { }); } + @Test + public void streamsApplicationIdUsesMainApplicationNameByDefault() { + this.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class) + .withPropertyValues("spring.application.name=my-test-app", + "spring.kafka.bootstrap-servers=localhost:9092,localhost:9093", + "spring.kafka.streams.auto-startup=false") + .run((context) -> { + Properties configs = context.getBean( + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, + KafkaStreamsConfiguration.class).asProperties(); + assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + .isEqualTo("localhost:9092, localhost:9093"); + assertThat(configs.get(StreamsConfig.APPLICATION_ID_CONFIG)) + .isEqualTo("my-test-app"); + }); + } + + @Test + public void streamsWithCustomKafkaConfiguration() { + this.contextRunner + .withUserConfiguration(EnableKafkaStreamsConfiguration.class, + TestKafkaStreamsConfiguration.class) + .withPropertyValues("spring.application.name=my-test-app", + "spring.kafka.bootstrap-servers=localhost:9092,localhost:9093", + "spring.kafka.streams.auto-startup=false") + .run((context) -> { + Properties configs = context.getBean( + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, + KafkaStreamsConfiguration.class).asProperties(); + assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + .isEqualTo("localhost:9094, localhost:9095"); + assertThat(configs.get(StreamsConfig.APPLICATION_ID_CONFIG)) + .isEqualTo("test-id"); + }); + } + + @Test + public void streamsApplicationIdIsMandatory() { + this.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class) + .run((context) -> { + assertThat(context).hasFailed(); + assertThat(context).getFailure() + .hasMessageContaining("spring.kafka.streams.application-id") + .hasMessageContaining( + "This property is mandatory and fallback 'spring.application.name' is not set either."); + + }); + } + + @Test + public void streamsApplicationIdIsNotMandatoryIfEnableKafkaStreamsIsNotSet() { + this.contextRunner.run((context) -> { + assertThat(context).hasNotFailed(); + assertThat(context).doesNotHaveBean(StreamsBuilder.class); + }); + } + @SuppressWarnings("unchecked") @Test public void listenerProperties() { @@ -470,4 +533,25 @@ public RecordMessageConverter myMessageConverter() { } + @Configuration + @EnableKafkaStreams + protected static class EnableKafkaStreamsConfiguration { + + } + + @Configuration + protected static class TestKafkaStreamsConfiguration { + + @Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) + public KafkaStreamsConfiguration kafkaStreamsConfiguration() { + Map streamsProperties = new HashMap<>(); + streamsProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + "localhost:9094, localhost:9095"); + streamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, "test-id"); + + return new KafkaStreamsConfiguration(streamsProperties); + } + + } + } diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 96ea4a3ff5e4..6bbe0cd4ef6e 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -397,6 +397,11 @@ commons-dbcp2 true + + org.apache.kafka + kafka-streams + true + org.apache.logging.log4j log4j-api diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index d8b264da78f7..2ff43506242d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1105,7 +1105,8 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.ssl.trust-store-location= # Location of the trust store file. spring.kafka.ssl.trust-store-password= # Store password for the trust store file. spring.kafka.ssl.trust-store-type= # Type of the trust store. - spring.kafka.streams.auto-startup= # Whether or not to auto-start the streams factory bean. + spring.kafka.streams.application-id = # Kafka streams application.id property; default spring.application.name. + spring.kafka.streams.auto-startup=true # Whether or not to auto-start the streams factory bean. spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Overrides the global property, for streams. spring.kafka.streams.cache-max-bytes-buffering= # Maximum number of memory bytes to be used for buffering across all threads. spring.kafka.streams.client-id= # ID to pass to the server when making requests. Used for server-side logging. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index d3bfaeb4799c..cc83d9ae7168 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,44 +5634,34 @@ The following component creates a listener endpoint on the `someTopic` topic: } ---- -[[boot-deatures-kafka-streams]] +[[boot-features-kafka-streams]] ==== Kafka Streams - Spring for Apache Kafka provides a factory bean to create a `StreamsBuilder` object and -manage the lifecycle of its streams; the factory bean is created when -`@EnableKafkaStreams` is present on a `@Configuration` class. -The factory bean requires a `KafkaStreamsConfiguration` object for streams configuration. +manage the lifecycle of its streams. Spring Boot auto-configures the required +`KafkaStreamsConfiguration` bean as long as `kafka-streams` in on the classpath and kafka +streams is enabled via the @EnableKafkaStreams` annotation. -If Spring Boot detects the `kafka-streams` jar on the classpath, it will auto-configure -the `KafkaStreamsConfiguration` bean from the `KafkaProperties` object as well as enabling -the creation of the factory bean by spring-kafka. +Enabling Kafka Streams means that the application id and bootstrap servers must be set. +The former can be configured using `spring.kafka.streams.application-id`, defaulting to +`spring.application.name` if not set. The later can be set globally or +specifically overridden just for streams. -There are two required Kafka properties for streams (`bootstrap.servers` and -`application.id`); by default, the `application.id` is set to the `spring.application.name` -property, if present. -The `bootstrap.servers` can be set globally or specifically overridden just for streams. -Several other properties are specifically available as boot properties; other arbitrary -Kafka properties can be set using the `spring.kafka.streams.properties` property. -See <> for more information. +Several additional properties are available using dedicated properties; other arbitrary +Kafka properties can be set using the `spring.kafka.streams.properties` namespace. See +also <> for more information. -To use the factory bean, simply wire its `StreamsBuilder` into your `@Bean` s. +To use the factory bean, simply wire `StreamsBuilder` into your `@Bean` as shown in the +following example: -==== -[source, java] ----- -@Bean -public KStream kStream(StreamsBuilder streamsBuilder) { - KStream stream = streamsBuilder.stream("ks1In"); - stream.map((k, v) -> new KeyValue(k, v.toUpperCase())) - .to("ks1Out", Produced.with(Serdes.Integer(), new JsonSerde<>())); - return stream; -} +[source,java,indent=0] ---- -==== +include::{code-examples}/kafka/KafkaStreamsBeanExample.java[tag=configuration] +---- + +By default, the streams managed by the `StreamBuilder` object it creates are started +automatically. You can customize this behaviour using the +`spring.kafka.streams.auto-startup` property. -By default, the factory bean `autoStartup` property is false; to automatically start the -streams managed by the `StreamsBuilder` object it creates, set property -`spting.kafka.streams.auto-startup=true`. [[boot-features-kafka-extra-props]] diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java new file mode 100644 index 000000000000..d9ddf5f19540 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2018 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.docs.kafka; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Produced; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafkaStreams; +import org.springframework.kafka.support.serializer.JsonSerde; + +/** + * Example to show usage of {@link StreamsBuilder}. + * + * @author Stephane Nicoll + */ +public class KafkaStreamsBeanExample { + + // tag::configuration[] + @Configuration + @EnableKafkaStreams + static class KafkaStreamsExampleConfiguration { + + @Bean + public KStream kStream(StreamsBuilder streamsBuilder) { + KStream stream = streamsBuilder.stream("ks1In"); + stream.map((k, v) -> new KeyValue(k, v.toUpperCase())).to("ks1Out", + Produced.with(Serdes.Integer(), new JsonSerde<>())); + return stream; + } + + } + // end::configuration[] + +} From e2a75942463faac195a90541917067fc95b8d164 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 22 Aug 2018 19:14:34 +0200 Subject: [PATCH 440/701] Configure Reactor HTTP client resources This commit adds support for the new `ReactorResourceFactory` and ensures that such a bean is created and destroyed with the application context. This will create a `ClientHttpConnector` bean, to be configured on the `WebClient.Builder` instance - or let developers create their own `ClientHttpConnector` bean to override that opinion. By default, the `ReactorResourceFactory` is configured to participate with the global resources, for better efficiency. Closes gh-14058 --- .../ClientHttpConnectorAutoConfiguration.java | 53 ++++++++++++++++ .../ClientHttpConnectorConfiguration.java | 62 +++++++++++++++++++ .../client/WebClientAutoConfiguration.java | 3 +- .../main/resources/META-INF/spring.factories | 1 + ...ntHttpConnectorAutoConfigurationTests.java | 59 ++++++++++++++++++ .../WebClientAutoConfigurationTests.java | 9 +-- .../main/asciidoc/spring-boot-features.adoc | 28 +++++++-- 7 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java new file mode 100644 index 000000000000..828970fd5e4f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive.function.client; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.web.reactive.function.client.WebClientCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.web.reactive.function.client.WebClient; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link ClientHttpConnector}. + *

    + * It can produce a {@link org.springframework.http.client.reactive.ClientHttpConnector} + * bean and possibly a companion {@code ResourceFactory} bean, depending on the chosen + * HTTP client library. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@Configuration +@ConditionalOnClass(WebClient.class) +@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class }) +public class ClientHttpConnectorAutoConfiguration { + + @Bean + @Order(0) + @ConditionalOnBean(ClientHttpConnector.class) + public WebClientCustomizer clientConnectorCustomizer( + ClientHttpConnector clientHttpConnector) { + return (builder) -> builder.clientConnector(clientHttpConnector); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java new file mode 100644 index 000000000000..1997e8b1f7ad --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive.function.client; + +import java.util.function.Function; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.http.client.reactive.ReactorResourceFactory; + +/** + * Configuration classes for WebClient client connectors. + *

    + * Those should be {@code @Import} in a regular auto-configuration class to guarantee + * their order of execution. + * + * @author Brian Clozel + */ +@Configuration +class ClientHttpConnectorConfiguration { + + @Configuration + @ConditionalOnClass(reactor.netty.http.client.HttpClient.class) + @ConditionalOnMissingBean(ClientHttpConnector.class) + public static class ReactorNetty { + + @Bean + @ConditionalOnMissingBean + public ReactorResourceFactory reactorResourceFactory() { + ReactorResourceFactory factory = new ReactorResourceFactory(); + factory.setGlobalResources(false); + return factory; + } + + @Bean + public ReactorClientHttpConnector reactorClientHttpConnector( + ReactorResourceFactory reactorResourceFactory) { + return new ReactorClientHttpConnector(reactorResourceFactory, + Function.identity()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java index 27da9a580190..f775d4061254 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java @@ -49,7 +49,8 @@ */ @Configuration @ConditionalOnClass(WebClient.class) -@AutoConfigureAfter(CodecsAutoConfiguration.class) +@AutoConfigureAfter({ CodecsAutoConfiguration.class, + ClientHttpConnectorAutoConfiguration.class }) public class WebClientAutoConfiguration { private final WebClient.Builder webClientBuilder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index f12e533f7ed8..cf88c0a33c1b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -121,6 +121,7 @@ org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\ org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java new file mode 100644 index 000000000000..844d88b1af8e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive.function.client; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.web.reactive.function.client.WebClientCustomizer; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.http.client.reactive.ReactorResourceFactory; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link ClientHttpConnectorAutoConfiguration} + * + * @author Brian Clozel + */ +public class ClientHttpConnectorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(ClientHttpConnectorAutoConfiguration.class)); + + @Test + public void shouldCreateHttpClientBeans() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(ReactorResourceFactory.class); + assertThat(context).hasSingleBean(ReactorClientHttpConnector.class); + WebClientCustomizer clientCustomizer = context + .getBean(WebClientCustomizer.class); + WebClient.Builder builder = mock(WebClient.Builder.class); + clientCustomizer.customize(builder); + verify(builder, times(1)) + .clientConnector(any(ReactorClientHttpConnector.class)); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfigurationTests.java index 90d0a85bca37..4eeff8ea609c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfigurationTests.java @@ -49,7 +49,9 @@ public class WebClientAutoConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class)); + .withConfiguration( + AutoConfigurations.of(ClientHttpConnectorAutoConfiguration.class, + WebClientAutoConfiguration.class)); @Test public void shouldCreateBuilder() { @@ -58,7 +60,6 @@ public void shouldCreateBuilder() { WebClient webClient = builder.build(); assertThat(webClient).isNotNull(); }); - } @Test @@ -82,7 +83,7 @@ public void webClientShouldApplyCustomizers() { .run((context) -> { WebClient.Builder builder = context.getBean(WebClient.Builder.class); WebClientCustomizer customizer = context - .getBean(WebClientCustomizer.class); + .getBean("webClientCustomizer", WebClientCustomizer.class); builder.build(); verify(customizer).customize(any(WebClient.Builder.class)); }); @@ -115,7 +116,7 @@ public void shouldGetPrototypeScopedBean() { verify(secondConnector).connect(eq(HttpMethod.GET), eq(URI.create("http://second.example.org/foo")), any()); WebClientCustomizer customizer = context - .getBean(WebClientCustomizer.class); + .getBean("webClientCustomizer", WebClientCustomizer.class); verify(customizer, times(1)).customize(any(WebClient.Builder.class)); }); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index cc83d9ae7168..5cf26f22989c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5785,13 +5785,14 @@ Finally, the most extreme (and rarely used) option is to create your own == Calling REST Services with `WebClient` If you have Spring WebFlux on your classpath, you can also choose to use `WebClient` to call remote REST services. Compared to `RestTemplate`, this client has a more functional -feel and is fully reactive. You can create your own client instance with the builder, -`WebClient.create()`. See the {spring-reference}web.html#web-reactive-client[relevant -section on WebClient]. +feel and is fully reactive. You can leanr more about the `WebClient` in the dedicated +{spring-reference}web-reactive.html#webflux-client[section in the Spring Framework docs]. -Spring Boot creates and pre-configures such a builder for you. For example, client HTTP -codecs are configured in the same fashion as the server ones (see -<>). +Spring Boot creates and pre-configures a `WebClient.Builder` for you; it is strongly +advised to inject it in your components and use it to create `WebClient` instances. +Spring Boot is configuring that builder to share HTTP resources, reflect codecs +setup in the same fashion as the server ones (see +<>), and more. The following code shows a typical example: @@ -5815,6 +5816,21 @@ The following code shows a typical example: ---- +[[boot-features-webclient-runtime]] +=== WebClient Runtime + +Spring Boot will auto-detect which `ClientHttpConnector` to drive `WebClient`, depending +on the libraries available on the application classpath. + +Developers can override this choice by defining their own `ClientHttpConnector` bean; +in this case, and depending on your HTTP client library of choice, you should also +define a resource factory bean that manages the HTTP resources for that client. +For example, a `ReactorResourceFactory` bean for the Reactor Netty client. + +You can learn more about the +{spring-reference}web-reactive.html#webflux-client-builder[`WebClient` configuration +options in the Spring Framework reference documentation]. + [[boot-features-webclient-customization]] === WebClient Customization From f74dd7d58cdc4201898b25c8266e9c3a91ef52b7 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Thu, 23 Aug 2018 10:37:58 +0200 Subject: [PATCH 441/701] Manage dependency for Jetty RS HTTP client This commit adds the Jetty RS HTTP client to the Spring Boot dependency management. As of SPR-15092 and SPR-17124, this HTTP client library is supported by Spring Framework. This commit is first step towards supporting that library as a driver for the WebClient / ClientHttpConnector auto-configuration. See gh-14005 --- spring-boot-project/spring-boot-dependencies/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 361705ca4418..bc414fa526f5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -104,6 +104,7 @@ 9.4.11.v20180605 2.2.0.v201112011158 8.5.24.2 + 1.0.1 1.14 4.5.2 2.10 @@ -1756,6 +1757,11 @@ import pom + + org.eclipse.jetty + jetty-reactive-httpclient + ${jetty-reactive-httpclient.version} + org.eclipse.jetty.orbit javax.servlet.jsp From 53f3982748da6c5f4f98bbb1cacf26f368f74986 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 23 Aug 2018 10:51:43 +0200 Subject: [PATCH 442/701] Support Jetty RS as HTTP driver for WebClient This commit adds a new auto-configuration choice for `ClientHttpConnector`, this time using the Jetty RS HTTP client library if available. This is the best choice in case the application runs on a Jetty reactive server, as both client and server will share resources. Closes gh-14005 --- .../spring-boot-autoconfigure/pom.xml | 5 ++ .../ClientHttpConnectorAutoConfiguration.java | 3 +- .../ClientHttpConnectorConfiguration.java | 22 +++++++++ ...ntHttpConnectorAutoConfigurationTests.java | 48 +++++++++++++++++++ .../main/asciidoc/spring-boot-features.adoc | 6 +++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index da28b3c8b4e1..59de46a536d0 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -280,6 +280,11 @@ jetty-webapp true + + org.eclipse.jetty + jetty-reactive-httpclient + true + org.eclipse.jetty.websocket javax-websocket-server-impl diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java index 828970fd5e4f..e25157fc0061 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfiguration.java @@ -39,7 +39,8 @@ */ @Configuration @ConditionalOnClass(WebClient.class) -@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class }) +@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class, + ClientHttpConnectorConfiguration.JettyClient.class }) public class ClientHttpConnectorAutoConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java index 1997e8b1f7ad..78493c20b714 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java @@ -23,6 +23,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.reactive.ClientHttpConnector; +import org.springframework.http.client.reactive.JettyClientHttpConnector; +import org.springframework.http.client.reactive.JettyResourceFactory; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.http.client.reactive.ReactorResourceFactory; @@ -59,4 +61,24 @@ public ReactorClientHttpConnector reactorClientHttpConnector( } + @Configuration + @ConditionalOnClass(org.eclipse.jetty.reactive.client.ReactiveRequest.class) + @ConditionalOnMissingBean(ClientHttpConnector.class) + public static class JettyClient { + + @Bean + @ConditionalOnMissingBean + public JettyResourceFactory jettyResourceFactory() { + return new JettyResourceFactory(); + } + + @Bean + public JettyClientHttpConnector jettyClientHttpConnector( + JettyResourceFactory jettyResourceFactory) { + return new JettyClientHttpConnector(jettyResourceFactory, (httpClient) -> { + }); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java index 844d88b1af8e..56fad97f655c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorAutoConfigurationTests.java @@ -21,6 +21,9 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.web.reactive.function.client.WebClientCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.http.client.reactive.ReactorResourceFactory; import org.springframework.web.reactive.function.client.WebClient; @@ -56,4 +59,49 @@ public void shouldCreateHttpClientBeans() { }); } + @Test + public void shouldNotOverrideCustomClientConnector() { + this.contextRunner.withUserConfiguration(CustomClientHttpConnectorConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(ClientHttpConnector.class) + .hasBean("customConnector") + .doesNotHaveBean(ReactorResourceFactory.class); + WebClientCustomizer clientCustomizer = context + .getBean(WebClientCustomizer.class); + WebClient.Builder builder = mock(WebClient.Builder.class); + clientCustomizer.customize(builder); + verify(builder, times(1)) + .clientConnector(any(ClientHttpConnector.class)); + }); + } + + @Test + public void shouldUseCustomReactorResourceFactory() { + this.contextRunner.withUserConfiguration(CustomReactorResourceConfig.class) + .run((context) -> assertThat(context) + .hasSingleBean(ReactorClientHttpConnector.class) + .hasSingleBean(ReactorResourceFactory.class) + .hasBean("customReactorResourceFactory")); + } + + @Configuration + static class CustomClientHttpConnectorConfig { + + @Bean + public ClientHttpConnector customConnector() { + return mock(ClientHttpConnector.class); + } + + } + + @Configuration + static class CustomReactorResourceConfig { + + @Bean + public ReactorResourceFactory customReactorResourceFactory() { + return new ReactorResourceFactory(); + } + + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5cf26f22989c..820790838b0c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5822,6 +5822,12 @@ The following code shows a typical example: Spring Boot will auto-detect which `ClientHttpConnector` to drive `WebClient`, depending on the libraries available on the application classpath. +The `spring-boot-starter-webflux` depends on `io.projectreactor.netty:reactor-netty` by +default, which brings both server and client implementations. If you choose to use Jetty +as a reactive server instead, you should add a dependency on the Jetty Reactive HTTP +client library, `org.eclipse.jetty:jetty-reactive-httpclient`, because it will +automatically share HTTP resources with the server. + Developers can override this choice by defining their own `ClientHttpConnector` bean; in this case, and depending on your HTTP client library of choice, you should also define a resource factory bean that manages the HTTP resources for that client. From 9602a32a8d4da57a6c1b9cb34240e11545172f2a Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 23 Aug 2018 02:09:49 +0900 Subject: [PATCH 443/701] Polish Closes gh-14172 --- .../autoconfigure/LocalDevToolsAutoConfiguration.java | 9 +++------ .../src/main/asciidoc/spring-boot-features.adoc | 4 ++-- .../ldap/DataLdapTestPropertiesIntegrationTests.java | 3 +-- .../mongo/DataMongoTestPropertiesIntegrationTests.java | 3 +-- .../neo4j/DataNeo4jTestPropertiesIntegrationTests.java | 3 +-- .../redis/DataRedisTestPropertiesIntegrationTests.java | 3 +-- .../jdbc/JdbcTestPropertiesIntegrationTests.java | 3 +-- .../jooq/JooqTestPropertiesIntegrationTests.java | 3 +-- .../json/JsonTestPropertiesIntegrationTests.java | 3 +-- .../orm/jpa/DataJpaTestPropertiesIntegrationTests.java | 3 +-- .../client/RestClientTestPropertiesIntegrationTests.java | 3 +-- .../reactive/WebFluxTestPropertiesIntegrationTests.java | 3 +-- .../servlet/WebMvcTestPropertiesIntegrationTests.java | 3 +-- .../analyzer/NoSuchMethodFailureAnalyzer.java | 4 ++-- .../boot/convert/MockDataSizeTypeDescriptor.java | 2 +- .../analyzer/NoSuchMethodFailureAnalyzerTests.java | 4 +++- 16 files changed, 22 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java index 6ae982153a01..820d6eea7fd5 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java @@ -191,14 +191,11 @@ public boolean supportsSourceType(@Nullable Class sourceType) { @Override public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) { + if (event instanceof ContextRefreshedEvent + || (event instanceof ClassPathChangedEvent + && !((ClassPathChangedEvent) event).isRestartRequired())) { this.liveReloadServer.triggerReload(); } - if (event instanceof ClassPathChangedEvent) { - if (!((ClassPathChangedEvent) event).isRestartRequired()) { - this.liveReloadServer.triggerReload(); - } - } } @Override diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 820790838b0c..51da89eaa9fe 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1290,7 +1290,7 @@ To specify a session timeout of 30 seconds, `30`, `PT30S` and `30s` are all equi read timeout of 500ms can be specified in any of the following form: `500`, `PT0.5S` and `500ms`. -You can also use any of the supported unit. These are: +You can also use any of the supported units. These are: * `ns` for nanoseconds * `us` for microseconds @@ -1331,7 +1331,7 @@ include::{code-examples}/context/properties/bind/AppIoProperties.java[tag=exampl To specify a buffer size of 10 megabytes, `10` and `10MB` are equivalent. A size threshold of 256 bytes can be specified as `256` or `256B`. -You can also use any of the supported unit. These are: +You can also use any of the supported units. These are: * `B` for bytes * `KB` for kilobytes diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java index df32e11429c0..bfd985affc18 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/ldap/DataLdapTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class DataLdapTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java index c3f298993e0b..905669003b47 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/mongo/DataMongoTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class DataMongoTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index 161f2dce5384..cdd81f391cee 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -50,8 +50,7 @@ public class DataNeo4jTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } static class Initializer diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java index 467007f48f44..5d06605e558d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/redis/DataRedisTestPropertiesIntegrationTests.java @@ -50,8 +50,7 @@ public class DataRedisTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } static class Initializer diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java index c4cdfdd0b3f2..8570e7cc0236 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/JdbcTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class JdbcTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java index 637998dc582a..e471784e7868 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jooq/JooqTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class JooqTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java index 10bc2ec20b2d..1f9a161c4a25 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class JsonTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java index bf46e4ad2a16..9a03f6883517 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class DataJpaTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java index 5eb857064fc0..b8a3a6b0a9e5 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/client/RestClientTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class RestClientTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java index 330ac5562a6b..e5550700deee 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class WebFluxTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java index eef8fbdc7ab4..3da589ee5f35 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestPropertiesIntegrationTests.java @@ -40,8 +40,7 @@ public class WebMvcTestPropertiesIntegrationTests { @Test public void environmentWithNewProfile() { - String profile = this.environment.getActiveProfiles()[0]; - assertThat(profile).isEqualTo("test"); + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java index 3ab1d65511cd..7475e11a3e2c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java @@ -86,9 +86,9 @@ private String extractClassName(NoSuchMethodError cause) { private List findCandidates(String className) { try { - return Collections.list((NoSuchMethodFailureAnalyzer.class.getClassLoader() + return Collections.list(NoSuchMethodFailureAnalyzer.class.getClassLoader() .getResources(ClassUtils.convertClassNameToResourcePath(className) - + ".class"))); + + ".class")); } catch (Throwable ex) { return null; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java index 97c64a56378c..c1422befc490 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java @@ -27,7 +27,7 @@ import static org.mockito.Mockito.mock; /** - * Create a mock {@link TypeDescriptor} with optional {@link DataUnit} annotation. + * Create a mock {@link TypeDescriptor} with optional {@link DataSizeUnit} annotation. * * @author Stephane Nicoll */ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java index e1453474e77d..a13bcfe66e0f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java @@ -30,7 +30,9 @@ import static org.mockito.Mockito.mock; /** - * @author awilkinson + * Tests for {@link NoSuchMethodFailureAnalyzer}. + * + * @author Andy Wilkinson */ @RunWith(ModifiedClassPathRunner.class) @ClassPathOverrides("javax.servlet:servlet-api:2.5") From 429cd8d114e56e5802174d94564c3726a2ebc8c7 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 23 Aug 2018 14:09:48 +0200 Subject: [PATCH 444/701] Optimize use of Jackson ObjectMapper instances Closes gh-1789 --- ...ConfigurationPropertiesReportEndpoint.java | 14 ++++++++++--- .../boot/json/JacksonJsonParser.java | 14 +++++++++++++ .../boot/json/JacksonJsonParserTests.java | 21 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpoint.java index 06515af9e67b..4304ab6c3e87 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpoint.java @@ -79,6 +79,8 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext private ApplicationContext context; + private ObjectMapper objectMapper; + @Override public void setApplicationContext(ApplicationContext context) throws BeansException { this.context = context; @@ -94,13 +96,11 @@ public ApplicationConfigurationProperties configurationProperties() { } private ApplicationConfigurationProperties extract(ApplicationContext context) { - ObjectMapper mapper = new ObjectMapper(); - configureObjectMapper(mapper); Map contextProperties = new HashMap<>(); ApplicationContext target = context; while (target != null) { contextProperties.put(target.getId(), - describeConfigurationProperties(target, mapper)); + describeConfigurationProperties(target, getObjectMapper())); target = target.getParent(); } return new ApplicationConfigurationProperties(contextProperties); @@ -179,6 +179,14 @@ protected void configureObjectMapper(ObjectMapper mapper) { applySerializationModifier(mapper); } + private ObjectMapper getObjectMapper() { + if (this.objectMapper == null) { + this.objectMapper = new ObjectMapper(); + configureObjectMapper(this.objectMapper); + } + return this.objectMapper; + } + /** * Ensure only bindable and non-cyclic bean properties are reported. * @param mapper the object mapper diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java index 41651fa1df0e..11f13e757b0a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java @@ -36,6 +36,20 @@ public class JacksonJsonParser extends AbstractJsonParser { private ObjectMapper objectMapper; // Late binding + /** + * Creates a instance with the specified {@link ObjectMapper}. + * @param objectMapper the object mapper to use + */ + public JacksonJsonParser(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Creates an instance with a default {@link ObjectMapper} that is created lazily. + */ + public JacksonJsonParser() { + } + @Override public Map parseMap(String json) { return tryParse(() -> getObjectMapper().readValue(json, MAP_TYPE), diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JacksonJsonParserTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JacksonJsonParserTests.java index 031a4662bba9..e0914409c47a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JacksonJsonParserTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/JacksonJsonParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,10 +16,22 @@ package org.springframework.boot.json; +import java.io.IOException; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + /** * Tests for {@link JacksonJsonParser}. * * @author Dave Syer + * @author Stephane Nicoll */ public class JacksonJsonParserTests extends AbstractJsonParserTests { @@ -28,4 +40,11 @@ protected JsonParser getParser() { return new JacksonJsonParser(); } + @Test + public void instanceWithSpecificObjectMapper() throws IOException { + ObjectMapper objectMapper = spy(new ObjectMapper()); + new JacksonJsonParser(objectMapper).parseMap("{}"); + verify(objectMapper).readValue(eq("{}"), any(TypeReference.class)); + } + } From 8fcd3fcd4c5192c6aed982fbe1576676f4238e2e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 23 Aug 2018 14:49:56 +0200 Subject: [PATCH 445/701] Fix javadoc generation on Java10+ --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 6bbe0cd4ef6e..99bb77f782ef 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -492,6 +492,11 @@ jetty-alpn-conscrypt-server true + + org.eclipse.jetty + jetty-reactive-httpclient + true + org.eclipse.jetty.http2 http2-server From da4624a8820635e56e4464a4ac282c78d16194a4 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 23 Aug 2018 15:35:34 +0200 Subject: [PATCH 446/701] Consider only current context in WebFlux setup This commit introduces a subclass of `DispatcherHandler` that only considers the current context when looking for WebFlux infrastructure beans. This avoids issues where a child context (e.g. with Actuator) picks up infrastructure beans from the parent context and exposes all endpoints instead of getting only the ones from the current context. Closes gh-14012 --- .../SingleContextDispatcherHandler.java | 56 +++++++++++++++++++ .../reactive/WebFluxAutoConfiguration.java | 6 ++ .../WebFluxAutoConfigurationTests.java | 33 +++++++++++ 3 files changed, 95 insertions(+) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java new file mode 100644 index 000000000000..a6e57e4b0e0c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.web.reactive.DispatcherHandler; +import org.springframework.web.reactive.HandlerAdapter; +import org.springframework.web.reactive.HandlerMapping; +import org.springframework.web.reactive.HandlerResultHandler; + +/** + * {@link DispatcherHandler} implementation that only checks for infrastructure beans in + * the current application context (i.e. does not consider the parent context). + * + * @author Brian Clozel + * @since 2.1.0 + */ +public class SingleContextDispatcherHandler extends DispatcherHandler { + + @Override + protected void initStrategies(ApplicationContext context) { + Map mappingBeans = context + .getBeansOfType(HandlerMapping.class, true, false); + ArrayList mappings = new ArrayList<>(mappingBeans.values()); + AnnotationAwareOrderComparator.sort(mappings); + this.handlerMappings = Collections.unmodifiableList(mappings); + Map adapterBeans = context + .getBeansOfType(HandlerAdapter.class, true, false); + this.handlerAdapters = new ArrayList(adapterBeans.values()); + AnnotationAwareOrderComparator.sort(this.handlerAdapters); + Map beans = context + .getBeansOfType(HandlerResultHandler.class, true, false); + this.resultHandlers = new ArrayList<>(beans.values()); + AnnotationAwareOrderComparator.sort(this.resultHandlers); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index b37c11d3dcc8..6a31d78adbf6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -57,6 +57,7 @@ import org.springframework.util.ClassUtils; import org.springframework.validation.Validator; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; +import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration; import org.springframework.web.reactive.config.EnableWebFlux; import org.springframework.web.reactive.config.ResourceChainRegistration; @@ -245,6 +246,11 @@ public FormattingConversionService webFluxConversionService() { return conversionService; } + @Override + public DispatcherHandler webHandler() { + return new SingleContextDispatcherHandler(); + } + @Bean @Override public Validator webFluxValidator() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 74cc41e867b0..650f4ceae86a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -28,6 +28,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; +import org.springframework.boot.test.context.assertj.ApplicationContextAssert; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; @@ -44,6 +46,7 @@ import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; +import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.reactive.config.WebFluxConfigurationSupport; @@ -398,6 +401,26 @@ public void multipleWebFluxRegistrations() { }); } + @Test + public void shouldNotGetHandlerMappingsFromParentContext() { + ApplicationContextRunner parentRunner = new ApplicationContextRunner() + .withUserConfiguration(CustomHandlerMapping.class); + parentRunner.run((parent) -> { + this.contextRunner.withParent(parent).run((context) -> { + assertThat(parent).hasSingleBean(HandlerMapping.class); + assertThat(context).getBeans(HandlerMapping.class).hasSize(4); + assertThat(context) + .getBeans(HandlerMapping.class, + ApplicationContextAssert.Scope.NO_ANCESTORS) + .doesNotContainKey("customHandlerMapping"); + assertThat(context).hasSingleBean(DispatcherHandler.class); + DispatcherHandler dispatcherHandler = context + .getBean(DispatcherHandler.class); + assertThat(dispatcherHandler.getHandlerMappings()).hasSize(3); + }); + }); + } + @Configuration protected static class CustomArgumentResolvers { @@ -564,4 +587,14 @@ private static class MyRequestMappingHandlerMapping } + @Configuration + static class CustomHandlerMapping { + + @Bean + public HandlerMapping customHandlerMapping() { + return mock(HandlerMapping.class); + } + + } + } From 0881b7c39023b757d1111a5603209785ebde4266 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 23 Aug 2018 16:50:48 +0200 Subject: [PATCH 447/701] Revert "Consider only current context in WebFlux setup" This reverts commit da4624a8820635e56e4464a4ac282c78d16194a4. --- .../SingleContextDispatcherHandler.java | 56 ------------------- .../reactive/WebFluxAutoConfiguration.java | 6 -- .../WebFluxAutoConfigurationTests.java | 33 ----------- 3 files changed, 95 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java deleted file mode 100644 index a6e57e4b0e0c..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/SingleContextDispatcherHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.web.reactive; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; - -import org.springframework.context.ApplicationContext; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.web.reactive.DispatcherHandler; -import org.springframework.web.reactive.HandlerAdapter; -import org.springframework.web.reactive.HandlerMapping; -import org.springframework.web.reactive.HandlerResultHandler; - -/** - * {@link DispatcherHandler} implementation that only checks for infrastructure beans in - * the current application context (i.e. does not consider the parent context). - * - * @author Brian Clozel - * @since 2.1.0 - */ -public class SingleContextDispatcherHandler extends DispatcherHandler { - - @Override - protected void initStrategies(ApplicationContext context) { - Map mappingBeans = context - .getBeansOfType(HandlerMapping.class, true, false); - ArrayList mappings = new ArrayList<>(mappingBeans.values()); - AnnotationAwareOrderComparator.sort(mappings); - this.handlerMappings = Collections.unmodifiableList(mappings); - Map adapterBeans = context - .getBeansOfType(HandlerAdapter.class, true, false); - this.handlerAdapters = new ArrayList(adapterBeans.values()); - AnnotationAwareOrderComparator.sort(this.handlerAdapters); - Map beans = context - .getBeansOfType(HandlerResultHandler.class, true, false); - this.resultHandlers = new ArrayList<>(beans.values()); - AnnotationAwareOrderComparator.sort(this.resultHandlers); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 6a31d78adbf6..b37c11d3dcc8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -57,7 +57,6 @@ import org.springframework.util.ClassUtils; import org.springframework.validation.Validator; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; -import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration; import org.springframework.web.reactive.config.EnableWebFlux; import org.springframework.web.reactive.config.ResourceChainRegistration; @@ -246,11 +245,6 @@ public FormattingConversionService webFluxConversionService() { return conversionService; } - @Override - public DispatcherHandler webHandler() { - return new SingleContextDispatcherHandler(); - } - @Bean @Override public Validator webFluxValidator() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 650f4ceae86a..74cc41e867b0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -28,8 +28,6 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; -import org.springframework.boot.test.context.assertj.ApplicationContextAssert; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; @@ -46,7 +44,6 @@ import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; -import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.reactive.config.WebFluxConfigurationSupport; @@ -401,26 +398,6 @@ public void multipleWebFluxRegistrations() { }); } - @Test - public void shouldNotGetHandlerMappingsFromParentContext() { - ApplicationContextRunner parentRunner = new ApplicationContextRunner() - .withUserConfiguration(CustomHandlerMapping.class); - parentRunner.run((parent) -> { - this.contextRunner.withParent(parent).run((context) -> { - assertThat(parent).hasSingleBean(HandlerMapping.class); - assertThat(context).getBeans(HandlerMapping.class).hasSize(4); - assertThat(context) - .getBeans(HandlerMapping.class, - ApplicationContextAssert.Scope.NO_ANCESTORS) - .doesNotContainKey("customHandlerMapping"); - assertThat(context).hasSingleBean(DispatcherHandler.class); - DispatcherHandler dispatcherHandler = context - .getBean(DispatcherHandler.class); - assertThat(dispatcherHandler.getHandlerMappings()).hasSize(3); - }); - }); - } - @Configuration protected static class CustomArgumentResolvers { @@ -587,14 +564,4 @@ private static class MyRequestMappingHandlerMapping } - @Configuration - static class CustomHandlerMapping { - - @Bean - public HandlerMapping customHandlerMapping() { - return mock(HandlerMapping.class); - } - - } - } From 26353a8f35bce42693512864f6f6b0c7a22ba03e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 23 Aug 2018 17:07:52 +0200 Subject: [PATCH 448/701] Port test to use ehcache3 Hibernate 5.3 has deprecated the ehcache2 region factory so this commit upgrades the integration test to use JCache instead. --- .../spring-boot-autoconfigure/pom.xml | 2 +- ...bernate2ndLevelCacheIntegrationTests.java} | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/{Hibernate2ndLevelCacheEhCacheIntegrationTests.java => Hibernate2ndLevelCacheIntegrationTests.java} (71%) diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 336abeece76f..bd627da715f6 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -327,7 +327,7 @@ org.hibernate - hibernate-ehcache + hibernate-jcache true diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheEhCacheIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheIntegrationTests.java similarity index 71% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheEhCacheIntegrationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheIntegrationTests.java index ceea6ffda836..5ba6de41d187 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheEhCacheIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/Hibernate2ndLevelCacheIntegrationTests.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.orm.jpa; -import org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory; +import org.ehcache.jsr107.EhcacheCachingProvider; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,13 +32,13 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for Hibernate 2nd level cache with ehcache2. + * Tests for Hibernate 2nd level cache with jcache. * * @author Stephane Nicoll */ @RunWith(ModifiedClassPathRunner.class) -@ClassPathExclusions("ehcache-3*.jar") -public class Hibernate2ndLevelCacheEhCacheIntegrationTests { +@ClassPathExclusions("ehcache-2*.jar") +public class Hibernate2ndLevelCacheIntegrationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class, @@ -48,11 +48,15 @@ public class Hibernate2ndLevelCacheEhCacheIntegrationTests { .withUserConfiguration(TestConfiguration.class); @Test - public void hibernate2ndLevelCacheWithEhCache2() { - this.contextRunner - .withPropertyValues("spring.cache.type=ehcache", - "spring.jpa.properties.hibernate.cache.region.factory_class=" - + SingletonEhCacheRegionFactory.class.getName()) + public void hibernate2ndLevelCacheWithJCacheAndEhCache3() { + String cachingProviderFqn = EhcacheCachingProvider.class.getName(); + String configLocation = "ehcache3.xml"; + this.contextRunner.withPropertyValues("spring.cache.type=jcache", + "spring.cache.jcache.provider=" + cachingProviderFqn, + "spring.cache.jcache.config=" + configLocation, + "spring.jpa.properties.hibernate.cache.region.factory_class=jcache", + "spring.jpa.properties.hibernate.cache.provider=" + cachingProviderFqn, + "spring.jpa.properties.hibernate.javax.cache.uri=" + configLocation) .run((context) -> assertThat(context).hasNotFailed()); } From fc4340c5d40be646b4854f53db17ad970c6c8d87 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 23 Aug 2018 16:51:27 -0700 Subject: [PATCH 449/701] Rename OAuth2 resource server properties Closes gh-14165 --- .../OAuth2ResourceServerProperties.java | 22 +++++-------------- ...eOAuth2ResourceServerJwkConfiguration.java | 5 ++--- .../OAuth2ResourceServerJwkConfiguration.java | 5 ++--- ...2ResourceServerAutoConfigurationTests.java | 8 +++---- ...2ResourceServerAutoConfigurationTests.java | 6 ++--- .../appendix-application-properties.adoc | 2 +- .../main/asciidoc/spring-boot-features.adoc | 2 +- .../src/main/resources/application.yml | 5 ++--- ...eOauth2ResourceServerApplicationTests.java | 4 ++-- .../src/main/resources/application.yml | 5 ++--- ...eOAuth2ResourceServerApplicationTests.java | 4 ++-- 11 files changed, 27 insertions(+), 41 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java index bf02b208f595..4f6b10721fc3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -23,7 +23,7 @@ * @author Madhura Bhave * @since 2.1.0 */ -@ConfigurationProperties(prefix = "spring.security.oauth2.resource") +@ConfigurationProperties(prefix = "spring.security.oauth2.resourceserver") public class OAuth2ResourceServerProperties { private final Jwt jwt = new Jwt(); @@ -34,27 +34,17 @@ public Jwt getJwt() { public static class Jwt { - private final Jwk jwk = new Jwk(); - - public Jwk getJwk() { - return this.jwk; - } - - } - - public static class Jwk { - /** * JSON Web Key URI to use to verify the JWT token. */ - private String setUri; + private String jwkSetUri; - public String getSetUri() { - return this.setUri; + public String getJwkSetUri() { + return this.jwkSetUri; } - public void setSetUri(String setUri) { - this.setUri = setUri; + public void setJwkSetUri(String jwkSetUri) { + this.jwkSetUri = jwkSetUri; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java index e9977b27c708..3a0c0be7552e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java @@ -39,11 +39,10 @@ class ReactiveOAuth2ResourceServerJwkConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri") + @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") @ConditionalOnMissingBean public ReactiveJwtDecoder jwtDecoder() { - return new NimbusReactiveJwtDecoder( - this.properties.getJwt().getJwk().getSetUri()); + return new NimbusReactiveJwtDecoder(this.properties.getJwt().getJwkSetUri()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java index f6deea3ce5e3..7c322884882c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java @@ -38,11 +38,10 @@ class OAuth2ResourceServerJwkConfiguration { } @Bean - @ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri") + @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") @ConditionalOnMissingBean public JwtDecoder jwtDecoder() { - return new NimbusJwtDecoderJwkSupport( - this.properties.getJwt().getJwk().getSetUri()); + return new NimbusJwtDecoderJwkSupport(this.properties.getJwt().getJwkSetUri()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index fd0095a44549..4b3f1571d800 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -58,7 +58,7 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests { @Test public void autoConfigurationShouldConfigureResourceServer() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .run((context) -> { assertThat(context.getBean(ReactiveJwtDecoder.class)) .isInstanceOf(NimbusReactiveJwtDecoder.class); @@ -75,7 +75,7 @@ public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { @Test public void jwtDecoderBeanIsConditionalOnMissingBean() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(JwtDecoderConfig.class) .run((this::assertFilterConfiguredWithJwtAuthenticationManager)); } @@ -83,7 +83,7 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { @Test public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClass() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(JwtDecoderConfig.class) .withClassLoader( new FilteredClassLoader(BearerTokenAuthenticationToken.class)) @@ -94,7 +94,7 @@ public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationToken @Test public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(SecurityWebFilterChainConfig.class) .run((context) -> { assertThat(context).hasSingleBean(SecurityWebFilterChain.class); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index 78ba79f0feea..f4da36bf5908 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -55,7 +55,7 @@ public class OAuth2ResourceServerAutoConfigurationTests { @Test public void autoConfigurationShouldConfigureResourceServer() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .run((context) -> { assertThat(context.getBean(JwtDecoder.class)) .isInstanceOf(NimbusJwtDecoderJwkSupport.class); @@ -72,7 +72,7 @@ public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { @Test public void jwtDecoderBeanIsConditionalOnMissingBean() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(JwtDecoderConfig.class) .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull()); } @@ -80,7 +80,7 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { @Test public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com") + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(JwtDecoderConfig.class) .withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class)) .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 2ff43506242d..10466330bcff 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -538,7 +538,7 @@ content into your application. Rather, pick only the properties that you need. spring.security.oauth2.client.registration.*= # OAuth client registrations. # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) - spring.security.oauth2.resource.jwt.jwk.set-uri= # JSON Web Key URI to use to verify the JWT token. + spring.security.oauth2.resourceserver.jwt.jwk-set-uri= # JSON Web Key URI to use to verify the JWT token. # ---------------------------------------- # DATA PROPERTIES diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 51da89eaa9fe..66db2788c295 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3324,7 +3324,7 @@ following example: [source,properties,indent=0] ---- - spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys + spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys ---- The same properties are applicable for both servlet and reactive applications. diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml index 2599bf40916c..885202551fea 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml @@ -3,6 +3,5 @@ spring: oauth2: resource: jwt: - jwk: - # To run the application, replace this with a valid JWK Set URI - set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file + # To run the application, replace this with a valid JWK Set URI + jwk-set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java index d1bc8491fcea..7feb8d7f72bf 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java @@ -57,13 +57,13 @@ public static void setup() throws Exception { server.start(); String url = server.url("/.well-known/jwks.json").toString(); server.enqueue(mockResponse()); - System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url); + System.setProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri", url); } @AfterClass public static void shutdown() throws IOException { server.shutdown(); - System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri"); + System.clearProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri"); } @Test diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml index 2599bf40916c..23f8d2ae960f 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/main/resources/application.yml @@ -1,8 +1,7 @@ spring: security: oauth2: - resource: + resourceserver: jwt: - jwk: # To run the application, replace this with a valid JWK Set URI - set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file + jwk-set-uri: https://example.com/oauth2/default/v1/keys \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java index ed1188f3aba3..ce0078fb4f86 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java @@ -50,13 +50,13 @@ public static void setup() throws Exception { server.start(); String url = server.url("/.well-known/jwks.json").toString(); server.enqueue(mockResponse()); - System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url); + System.setProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri", url); } @AfterClass public static void shutdown() throws Exception { server.shutdown(); - System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri"); + System.clearProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri"); } @Test From 833e39eeb64ce3b7184f6c597ce003fe5df425f5 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 23 Aug 2018 17:11:47 +0200 Subject: [PATCH 450/701] Let Hibernate configure the transaction manager on WebSphere Closes gh-8926 --- .../orm/jpa/HibernateJpaConfiguration.java | 46 +++++-------------- .../HibernateJpaAutoConfigurationTests.java | 37 +++++++++------ 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 5141bbf60970..d9a6433ab462 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.orm.jpa; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; @@ -75,14 +76,6 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", "org.hibernate.service.jta.platform.internal.NoJtaPlatform" }; - /** - * {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate - * versions. - */ - private static final String[] WEBSPHERE_JTA_PLATFORM_CLASSES = { - "org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform", - "org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform" }; - private final HibernateProperties hibernateProperties; private final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider; @@ -157,20 +150,15 @@ protected void customizeVendorProperties(Map vendorProperties) { private void configureJtaPlatform(Map vendorProperties) throws LinkageError { JtaTransactionManager jtaTransactionManager = getJtaTransactionManager(); - if (jtaTransactionManager != null) { - if (runningOnWebSphere()) { - // We can never use SpringJtaPlatform on WebSphere as - // WebSphereUowTransactionManager has a null TransactionManager - // which will cause Hibernate to NPE - configureWebSphereTransactionPlatform(vendorProperties); - } - else { - configureSpringJtaPlatform(vendorProperties, jtaTransactionManager); - } - } - else { + // Make sure Hibernate doesn't attempt to auto-detect a JTA platform + if (jtaTransactionManager == null) { vendorProperties.put(JTA_PLATFORM, getNoJtaPlatformManager()); } + // As of Hibernate 5.2, Hibernate can fully integrate with the WebSphere + // transaction manager on its own. + else if (!runningOnWebSphere()) { + configureSpringJtaPlatform(vendorProperties, jtaTransactionManager); + } } private void configureProviderDisablesAutocommit( @@ -193,15 +181,6 @@ private boolean runningOnWebSphere() { getClass().getClassLoader()); } - private void configureWebSphereTransactionPlatform( - Map vendorProperties) { - vendorProperties.put(JTA_PLATFORM, getWebSphereJtaPlatformManager()); - } - - private Object getWebSphereJtaPlatformManager() { - return getJtaPlatformManager(WEBSPHERE_JTA_PLATFORM_CLASSES); - } - private void configureSpringJtaPlatform(Map vendorProperties, JtaTransactionManager jtaTransactionManager) { try { @@ -233,11 +212,7 @@ private boolean isUsingJndi() { } private Object getNoJtaPlatformManager() { - return getJtaPlatformManager(NO_JTA_PLATFORM_CLASSES); - } - - private Object getJtaPlatformManager(String[] candidates) { - for (String candidate : candidates) { + for (String candidate : NO_JTA_PLATFORM_CLASSES) { try { return Class.forName(candidate).newInstance(); } @@ -245,7 +220,8 @@ private Object getJtaPlatformManager(String[] candidates) { // Continue searching } } - throw new IllegalStateException("Could not configure JTA platform"); + throw new IllegalStateException("No available JtaPlatform candidates amongst" + + Arrays.toString(NO_JTA_PLATFORM_CLASSES)); } private static class NamingStrategiesHibernatePropertiesCustomizer diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index c748c9c79dbf..8bdf09c03e96 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -35,7 +35,9 @@ import com.zaxxer.hikari.HikariDataSource; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.internal.SessionFactoryImpl; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; @@ -52,6 +54,8 @@ import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.JpaTransactionManager; @@ -148,13 +152,7 @@ public void testLiquibasePlusValidation() { public void jtaDefaultPlatform() { contextRunner() .withConfiguration(AutoConfigurations.of(JtaAutoConfiguration.class)) - .run((context) -> { - Map jpaPropertyMap = context - .getBean(LocalContainerEntityManagerFactoryBean.class) - .getJpaPropertyMap(); - assertThat(jpaPropertyMap.get("hibernate.transaction.jta.platform")) - .isInstanceOf(SpringJtaPlatform.class); - }); + .run(assertJtaPlatform(SpringJtaPlatform.class)); } @Test @@ -164,14 +162,23 @@ public void jtaCustomPlatform() { "spring.jpa.properties.hibernate.transaction.jta.platform:" + TestJtaPlatform.class.getName()) .withConfiguration(AutoConfigurations.of(JtaAutoConfiguration.class)) - .run((context) -> { - Map jpaPropertyMap = context - .getBean(LocalContainerEntityManagerFactoryBean.class) - .getJpaPropertyMap(); - assertThat((String) jpaPropertyMap - .get("hibernate.transaction.jta.platform")) - .isEqualTo(TestJtaPlatform.class.getName()); - }); + .run(assertJtaPlatform(TestJtaPlatform.class)); + } + + @Test + public void jtaNotUsedByTheApplication() { + contextRunner().run(assertJtaPlatform(NoJtaPlatform.class)); + } + + private ContextConsumer assertJtaPlatform( + Class expectedType) { + return (context) -> { + SessionFactoryImpl sessionFactory = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getNativeEntityManagerFactory().unwrap(SessionFactoryImpl.class); + assertThat(sessionFactory.getServiceRegistry().getService(JtaPlatform.class)) + .isInstanceOf(expectedType); + }; } @Test From 7eecfe31082f82413af60307ebd59eb045165d1d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 24 Aug 2018 11:50:18 +0200 Subject: [PATCH 451/701] Polish See gh-14184 --- .../src/main/asciidoc/spring-boot-features.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 95c90adf8789..ff38bfea1925 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5785,7 +5785,7 @@ Finally, the most extreme (and rarely used) option is to create your own == Calling REST Services with `WebClient` If you have Spring WebFlux on your classpath, you can also choose to use `WebClient` to call remote REST services. Compared to `RestTemplate`, this client has a more functional -feel and is fully reactive. You can leanr more about the `WebClient` in the dedicated +feel and is fully reactive. You can learn more about the `WebClient` in the dedicated {spring-reference}web-reactive.html#webflux-client[section in the Spring Framework docs]. Spring Boot creates and pre-configures a `WebClient.Builder` for you; it is strongly From caf7221485a578d2fa3581fbfa74a6afef7587fc Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 24 Aug 2018 12:12:13 -0700 Subject: [PATCH 452/701] Update OAuth2 config following changes in Spring Security DSL Closes gh-14169 --- .../ReactiveOAuth2ResourceServerWebSecurityConfiguration.java | 4 ++-- .../servlet/OAuth2ResourceServerWebSecurityConfiguration.java | 4 ++-- .../ReactiveOAuth2ResourceServerAutoConfigurationTests.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java index c481fdeabfe3..5b99e00ec074 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerWebSecurityConfiguration.java @@ -42,8 +42,8 @@ class ReactiveOAuth2ResourceServerWebSecurityConfiguration { @Bean @ConditionalOnMissingBean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - http.authorizeExchange().anyExchange().authenticated().and().oauth2() - .resourceServer().jwt().jwtDecoder(this.jwtDecoder); + http.authorizeExchange().anyExchange().authenticated().and() + .oauth2ResourceServer().jwt().jwtDecoder(this.jwtDecoder); return http.build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java index 14e51b04d2ba..7de7d62be1a3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java @@ -37,8 +37,8 @@ static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAda @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().authenticated().and().oauth2() - .resourceServer().jwt(); + http.authorizeRequests().anyRequest().authenticated().and() + .oauth2ResourceServer().jwt(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index 4b3f1571d800..de7c57dd05d3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -146,7 +146,7 @@ static class SecurityWebFilterChainConfig { SecurityWebFilterChain testSpringSecurityFilterChain(ServerHttpSecurity http, ReactiveJwtDecoder decoder) { http.authorizeExchange().pathMatchers("/message/**").hasRole("ADMIN") - .anyExchange().authenticated().and().oauth2().resourceServer().jwt() + .anyExchange().authenticated().and().oauth2ResourceServer().jwt() .jwtDecoder(decoder); return http.build(); } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index bc414fa526f5..8ccaae140733 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -166,7 +166,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.RC1 + 5.1.0.BUILD-SNAPSHOT Bean-M2 3.0.3.RELEASE 3.23.1 From 6be43077124c5bc27125ae4be397d625b7e0a6c5 Mon Sep 17 00:00:00 2001 From: artsiom Date: Tue, 21 Aug 2018 12:24:41 +0300 Subject: [PATCH 453/701] OAuth2 client secret property should not be required --- .../security/oauth2/client/OAuth2ClientProperties.java | 4 +--- .../security/oauth2/client/OAuth2ClientPropertiesTests.java | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index f238643fd0fd..6db2153424da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -30,6 +30,7 @@ * * @author Madhura Bhave * @author Phillip Webb + * @author Artsiom Yudovin */ @ConfigurationProperties(prefix = "spring.security.oauth2.client") public class OAuth2ClientProperties { @@ -61,9 +62,6 @@ private void validateRegistration(Registration registration) { if (!StringUtils.hasText(registration.getClientId())) { throw new IllegalStateException("Client id must not be empty."); } - if (!StringUtils.hasText(registration.getClientSecret())) { - throw new IllegalStateException("Client secret must not be empty."); - } } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java index cfd146c093d7..ff6cc6f8364a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java @@ -24,6 +24,7 @@ * Tests for {@link OAuth2ClientProperties}. * * @author Madhura Bhave + * @author Artsiom Yudovin */ public class OAuth2ClientPropertiesTests { @@ -44,13 +45,11 @@ public void clientIdAbsentThrowsException() { } @Test - public void clientSecretAbsentThrowsException() { + public void clientSecretAbsentNotThrowsException() { OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration(); registration.setClientId("foo"); registration.setProvider("google"); this.properties.getRegistration().put("foo", registration); - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage("Client secret must not be empty."); this.properties.validate(); } From d07e2fa0b25d9c72f5fe440b73f39e3b6131a79d Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 24 Aug 2018 12:23:41 -0700 Subject: [PATCH 454/701] Polish "OAuth2 client secret should not be required" Closes gh-14156 --- .../security/oauth2/client/OAuth2ClientPropertiesTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java index ff6cc6f8364a..75960d497f14 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java @@ -45,7 +45,7 @@ public void clientIdAbsentThrowsException() { } @Test - public void clientSecretAbsentNotThrowsException() { + public void clientSecretAbsentShouldNotThrowException() { OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration(); registration.setClientId("foo"); registration.setProvider("google"); From c827530f4b097b6f6f8500a7f62420ad28c4e862 Mon Sep 17 00:00:00 2001 From: "mhyeon.lee" Date: Mon, 23 Jul 2018 14:24:18 +0900 Subject: [PATCH 455/701] Add user-info-authentication-method Closes gh-13865 --- .../oauth2/client/OAuth2ClientProperties.java | 14 ++++++++++++++ .../OAuth2ClientPropertiesRegistrationAdapter.java | 4 ++++ ...h2ClientPropertiesRegistrationAdapterTests.java | 13 +++++++++++++ .../src/main/asciidoc/spring-boot-features.adoc | 1 + 4 files changed, 32 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index 6db2153424da..42f98ae73cbf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -31,6 +31,7 @@ * @author Madhura Bhave * @author Phillip Webb * @author Artsiom Yudovin + * @author MyeongHyeon Lee */ @ConfigurationProperties(prefix = "spring.security.oauth2.client") public class OAuth2ClientProperties { @@ -195,6 +196,11 @@ public static class Provider { */ private String userInfoUri; + /** + * User info authentication method for the provider. + */ + private String userInfoAuthenticationMethod; + /** * Name of the attribute that will be used to extract the username from the call * to 'userInfoUri'. @@ -235,6 +241,14 @@ public void setUserInfoUri(String userInfoUri) { this.userInfoUri = userInfoUri; } + public String getUserInfoAuthenticationMethod() { + return this.userInfoAuthenticationMethod; + } + + public void setUserInfoAuthenticationMethod(String userInfoAuthenticationMethod) { + this.userInfoAuthenticationMethod = userInfoAuthenticationMethod; + } + public String getUserNameAttribute() { return this.userNameAttribute; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index e8454add7902..d1ce147a3fc9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -28,6 +28,7 @@ import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; import org.springframework.security.oauth2.client.registration.ClientRegistrations; +import org.springframework.security.oauth2.core.AuthenticationMethod; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.util.StringUtils; @@ -39,6 +40,7 @@ * @author Phillip Webb * @author Thiago Hirata * @author Madhura Bhave + * @author MyeongHyeon Lee * @since 2.1.0 */ public final class OAuth2ClientPropertiesRegistrationAdapter { @@ -131,6 +133,8 @@ private static Builder getBuilder(Builder builder, Provider provider) { map.from(provider::getAuthorizationUri).to(builder::authorizationUri); map.from(provider::getTokenUri).to(builder::tokenUri); map.from(provider::getUserInfoUri).to(builder::userInfoUri); + map.from(provider::getUserInfoAuthenticationMethod).as(AuthenticationMethod::new) + .to(builder::userInfoAuthenticationMethod); map.from(provider::getJwkSetUri).to(builder::jwkSetUri); map.from(provider::getUserNameAttribute).to(builder::userNameAttributeName); return builder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 7bbe6caf534e..8e16a767fdc5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -69,6 +69,7 @@ public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() { provider.setAuthorizationUri("http://example.com/auth"); provider.setTokenUri("http://example.com/token"); provider.setUserInfoUri("http://example.com/info"); + provider.setUserInfoAuthenticationMethod("form"); provider.setUserNameAttribute("sub"); provider.setJwkSetUri("http://example.com/jwk"); Registration registration = new Registration(); @@ -91,6 +92,9 @@ public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() { assertThat(adaptedProvider.getTokenUri()).isEqualTo("http://example.com/token"); assertThat(adaptedProvider.getUserInfoEndpoint().getUri()) .isEqualTo("http://example.com/info"); + assertThat(adaptedProvider.getUserInfoEndpoint().getAuthenticationMethod()) + .isEqualTo( + org.springframework.security.oauth2.core.AuthenticationMethod.FORM); assertThat(adaptedProvider.getUserInfoEndpoint().getUserNameAttributeName()) .isEqualTo("sub"); assertThat(adaptedProvider.getJwkSetUri()).isEqualTo("http://example.com/jwk"); @@ -167,6 +171,9 @@ public void getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt .isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo"); assertThat(adaptedProvider.getUserInfoEndpoint().getUserNameAttributeName()) .isEqualTo(IdTokenClaimNames.SUB); + assertThat(adaptedProvider.getUserInfoEndpoint().getAuthenticationMethod()) + .isEqualTo( + org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); assertThat(adaptedProvider.getJwkSetUri()) .isEqualTo("https://www.googleapis.com/oauth2/v3/certs"); assertThat(adapted.getRegistrationId()).isEqualTo("registration"); @@ -210,6 +217,9 @@ public void getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationI .isEqualTo("https://www.googleapis.com/oauth2/v4/token"); assertThat(adaptedProvider.getUserInfoEndpoint().getUri()) .isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo"); + assertThat(adaptedProvider.getUserInfoEndpoint().getAuthenticationMethod()) + .isEqualTo( + org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); assertThat(adaptedProvider.getJwkSetUri()) .isEqualTo("https://www.googleapis.com/oauth2/v3/certs"); assertThat(adapted.getRegistrationId()).isEqualTo("google"); @@ -334,6 +344,9 @@ private void testOidcConfiguration(Registration registration, String providerId) .isEqualTo("https://example.com/oauth2/v3/certs"); assertThat(providerDetails.getUserInfoEndpoint().getUri()) .isEqualTo("https://example.com/oauth2/v3/userinfo"); + assertThat(providerDetails.getUserInfoEndpoint().getAuthenticationMethod()) + .isEqualTo( + org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); } private String cleanIssuerPath(String issuer) { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index a7e7bc0d7dc5..22292f2ec8ee 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3252,6 +3252,7 @@ You can register multiple OAuth2 clients and providers under the spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://my-auth-server/oauth/authorize spring.security.oauth2.client.provider.my-oauth-provider.token-uri=http://my-auth-server/oauth/token spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=http://my-auth-server/userinfo + spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=http://my-auth-server/token_keys spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name ---- From 0c299bbc1f786601a1cea6f2a1b9e36e923e688e Mon Sep 17 00:00:00 2001 From: artsiom Date: Thu, 23 Aug 2018 22:16:27 +0300 Subject: [PATCH 456/701] Support OIDC issuer uri in OAuth resource server config --- .../OAuth2ResourceServerProperties.java | 14 +++ .../resource/OidcIssuerLocationCondition.java | 43 +++++++ .../OAuth2ResourceServerJwkConfiguration.java | 15 ++- ...2ResourceServerAutoConfigurationTests.java | 114 ++++++++++++++++++ .../appendix-application-properties.adoc | 1 + 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java index 4f6b10721fc3..21f97c566a3f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -21,6 +21,7 @@ * OAuth 2.0 resource server properties. * * @author Madhura Bhave + * @author Artsiom Yudovin * @since 2.1.0 */ @ConfigurationProperties(prefix = "spring.security.oauth2.resourceserver") @@ -39,6 +40,11 @@ public static class Jwt { */ private String jwkSetUri; + /** + * Oidc issuer location. + */ + private String oidcIssuerLocation; + public String getJwkSetUri() { return this.jwkSetUri; } @@ -47,6 +53,14 @@ public void setJwkSetUri(String jwkSetUri) { this.jwkSetUri = jwkSetUri; } + public String getOidcIssuerLocation() { + return this.oidcIssuerLocation; + } + + public void setOidcIssuerLocation(String oidcIssuerLocation) { + this.oidcIssuerLocation = oidcIssuerLocation; + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java new file mode 100644 index 000000000000..ae2e91c0cb96 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.security.oauth2.jwt.JwtDecoder; + +/** + * Condition for creating {@link JwtDecoder} by oidc issuer location. + * + * @author Artsiom Yudovin + */ +public class OidcIssuerLocationCondition implements Condition { + + private static final String OIDC_ISSUER_LOCATION = "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location"; + + private static final String JWT_SET_URI = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri"; + + @Override + public boolean matches(ConditionContext conditionContext, + AnnotatedTypeMetadata annotatedTypeMetadata) { + Environment environment = conditionContext.getEnvironment(); + return environment.containsProperty(OIDC_ISSUER_LOCATION) + && !environment.containsProperty(JWT_SET_URI); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java index 7c322884882c..f2ddd42579e1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java @@ -18,15 +18,20 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; +import org.springframework.boot.autoconfigure.security.oauth2.resource.OidcIssuerLocationCondition; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtDecoders; import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; /** - * Configures a {@link JwtDecoder} when a JWK Set URI is available. + * Configures a {@link JwtDecoder} when a JWK Set URI is available or Oidc Issuer + * Location. * * @author Madhura Bhave + * @author Artsiom Yudovin */ @Configuration class OAuth2ResourceServerJwkConfiguration { @@ -44,4 +49,12 @@ public JwtDecoder jwtDecoder() { return new NimbusJwtDecoderJwkSupport(this.properties.getJwt().getJwkSetUri()); } + @Bean + @Conditional(OidcIssuerLocationCondition.class) + @ConditionalOnMissingBean + public JwtDecoder jwtDecoderByOidcIssuerLocation() { + return JwtDecoders + .fromOidcIssuerLocation(this.properties.getJwt().getOidcIssuerLocation()); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index f4da36bf5908..e248b08bbf73 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -15,11 +15,19 @@ */ package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.servlet.Filter; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.After; import org.junit.Test; +import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; @@ -27,6 +35,9 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.jwt.JwtDecoder; @@ -44,6 +55,7 @@ * Tests for {@link OAuth2ResourceServerAutoConfiguration}. * * @author Madhura Bhave + * @author Artsiom Yudovin */ public class OAuth2ResourceServerAutoConfigurationTests { @@ -52,6 +64,15 @@ public class OAuth2ResourceServerAutoConfigurationTests { AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class)) .withUserConfiguration(TestConfig.class); + private MockWebServer server; + + @After + public void cleanup() throws Exception { + if (this.server != null) { + this.server.shutdown(); + } + } + @Test public void autoConfigurationShouldConfigureResourceServer() { this.contextRunner.withPropertyValues( @@ -63,6 +84,46 @@ public void autoConfigurationShouldConfigureResourceServer() { }); } + @Test + public void autoConfigurationShouldConfigureResourceServerOidcIssuerLocation() + throws Exception { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://" + + this.server.getHostName() + ":" + this.server.getPort()) + .run((context) -> { + assertThat(context.getBean(JwtDecoder.class)) + .isInstanceOf(NimbusJwtDecoderJwkSupport.class); + assertThat(getBearerTokenFilter(context)).isNotNull(); + }); + } + + @Test + public void autoConfigurationShouldConfigureSetUriWithTwoProperties() + throws Exception { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://" + + this.server.getHostName() + ":" + this.server.getPort(), + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") + .run((context) -> { + assertThat(context.getBean(JwtDecoder.class)) + .isInstanceOf(NimbusJwtDecoderJwkSupport.class); + assertThat(getBearerTokenFilter(context)).isNotNull(); + assertThat(context.containsBean("jwtDecoder")).isTrue(); + assertThat(context.containsBean("jwtDecoderByOidcIssuerLocation")) + .isFalse(); + }); + } + @Test public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { this.contextRunner @@ -77,6 +138,14 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull()); } + @Test + public void jwtDecoderBeanIsConditionalOnMissingBeanOidcIssuerLocation() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://jwk-oidc-issuer-location.com") + .withUserConfiguration(JwtDecoderConfig.class) + .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull()); + } + @Test public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() { this.contextRunner.withPropertyValues( @@ -86,6 +155,15 @@ public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); } + @Test + public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClassOidcIssuerLocation() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://jwk-oidc-issuer-location.com") + .withUserConfiguration(JwtDecoderConfig.class) + .withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class)) + .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); + } + @SuppressWarnings("unchecked") private Filter getBearerTokenFilter(AssertableWebApplicationContext context) { FilterChainProxy filterChain = (FilterChainProxy) context @@ -98,6 +176,42 @@ private Filter getBearerTokenFilter(AssertableWebApplicationContext context) { .orElse(null); } + private String cleanIssuerPath(String issuer) { + if (issuer.endsWith("/")) { + return issuer.substring(0, issuer.length() - 1); + } + return issuer; + } + + private void setupMockResponse(String issuer) throws JsonProcessingException { + MockResponse mockResponse = new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .setBody(new ObjectMapper().writeValueAsString(getResponse(issuer))) + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + this.server.enqueue(mockResponse); + } + + private Map getResponse(String issuer) { + Map response = new HashMap<>(); + response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth"); + response.put("claims_supported", Collections.emptyList()); + response.put("code_challenge_methods_supported", Collections.emptyList()); + response.put("id_token_signing_alg_values_supported", Collections.emptyList()); + response.put("issuer", issuer); + response.put("jwks_uri", "https://example.com/oauth2/v3/certs"); + response.put("response_types_supported", Collections.emptyList()); + response.put("revocation_endpoint", "https://example.com/o/oauth2/revoke"); + response.put("scopes_supported", Collections.singletonList("openid")); + response.put("subject_types_supported", Collections.singletonList("public")); + response.put("grant_types_supported", + Collections.singletonList("authorization_code")); + response.put("token_endpoint", "https://example.com/oauth2/v4/token"); + response.put("token_endpoint_auth_methods_supported", + Collections.singletonList("client_secret_basic")); + response.put("userinfo_endpoint", "https://example.com/oauth2/v3/userinfo"); + return response; + } + @Configuration @EnableWebSecurity static class TestConfig { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 10466330bcff..0e6fa7110272 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -539,6 +539,7 @@ content into your application. Rather, pick only the properties that you need. # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) spring.security.oauth2.resourceserver.jwt.jwk-set-uri= # JSON Web Key URI to use to verify the JWT token. + spring.security.oauth2.resource.jwt.oidc-issuer-location= # Location for issuer oidc # ---------------------------------------- # DATA PROPERTIES From cf31325e5d969ae5ac38e814a9137030b650468f Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 24 Aug 2018 14:57:45 -0700 Subject: [PATCH 457/701] Polish "OIDC issuer uri in OAuth resource server config" Closes gh-14190 --- .../oauth2/resource/IssuerUriCondition.java | 56 +++++++++++++++++++ .../OAuth2ResourceServerProperties.java | 12 ++-- .../resource/OidcIssuerLocationCondition.java | 43 -------------- .../OAuth2ResourceServerJwkConfiguration.java | 14 ++--- ...2ResourceServerAutoConfigurationTests.java | 39 ++++--------- .../appendix-application-properties.adoc | 2 +- .../main/asciidoc/spring-boot-features.adoc | 9 ++- 7 files changed, 89 insertions(+), 86 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/IssuerUriCondition.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/IssuerUriCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/IssuerUriCondition.java new file mode 100644 index 000000000000..0f08507f8bbd --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/IssuerUriCondition.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.util.StringUtils; + +/** + * Condition for creating {@link JwtDecoder} by oidc issuer location. + * + * @author Artsiom Yudovin + * @since 2.1.0 + */ +public class IssuerUriCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ConditionMessage.Builder message = ConditionMessage + .forCondition("OpenID Connect Issuer URI Condition"); + Environment environment = context.getEnvironment(); + String issuerUri = environment + .getProperty("spring.security.oauth2.resourceserver.jwt.issuer-uri"); + String jwkSetUri = environment + .getProperty("spring.security.oauth2.resourceserver.jwt.jwk-set-uri"); + if (!StringUtils.hasText(issuerUri)) { + return ConditionOutcome + .noMatch(message.didNotFind("issuer-uri property").atAll()); + } + if (StringUtils.hasText(jwkSetUri)) { + return ConditionOutcome + .noMatch(message.found("jwk-set-uri property").items(jwkSetUri)); + } + return ConditionOutcome.match(message.foundExactly("issuer-uri property")); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java index 21f97c566a3f..6df4452a4b65 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java @@ -41,9 +41,9 @@ public static class Jwt { private String jwkSetUri; /** - * Oidc issuer location. + * URI that an OpenID Connect Provider asserts as its Issuer Identifier. */ - private String oidcIssuerLocation; + private String issuerUri; public String getJwkSetUri() { return this.jwkSetUri; @@ -53,12 +53,12 @@ public void setJwkSetUri(String jwkSetUri) { this.jwkSetUri = jwkSetUri; } - public String getOidcIssuerLocation() { - return this.oidcIssuerLocation; + public String getIssuerUri() { + return this.issuerUri; } - public void setOidcIssuerLocation(String oidcIssuerLocation) { - this.oidcIssuerLocation = oidcIssuerLocation; + public void setIssuerUri(String issuerUri) { + this.issuerUri = issuerUri; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java deleted file mode 100644 index ae2e91c0cb96..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OidcIssuerLocationCondition.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.security.oauth2.resource; - -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.security.oauth2.jwt.JwtDecoder; - -/** - * Condition for creating {@link JwtDecoder} by oidc issuer location. - * - * @author Artsiom Yudovin - */ -public class OidcIssuerLocationCondition implements Condition { - - private static final String OIDC_ISSUER_LOCATION = "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location"; - - private static final String JWT_SET_URI = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri"; - - @Override - public boolean matches(ConditionContext conditionContext, - AnnotatedTypeMetadata annotatedTypeMetadata) { - Environment environment = conditionContext.getEnvironment(); - return environment.containsProperty(OIDC_ISSUER_LOCATION) - && !environment.containsProperty(JWT_SET_URI); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java index f2ddd42579e1..d760162198fe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java @@ -17,8 +17,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OidcIssuerLocationCondition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -27,8 +27,8 @@ import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport; /** - * Configures a {@link JwtDecoder} when a JWK Set URI is available or Oidc Issuer - * Location. + * Configures a {@link JwtDecoder} when a JWK Set URI or OpenID Connect Issuer URI is + * available. * * @author Madhura Bhave * @author Artsiom Yudovin @@ -45,16 +45,16 @@ class OAuth2ResourceServerJwkConfiguration { @Bean @ConditionalOnProperty(name = "spring.security.oauth2.resourceserver.jwt.jwk-set-uri") @ConditionalOnMissingBean - public JwtDecoder jwtDecoder() { + public JwtDecoder jwtDecoderByJwkKeySetUri() { return new NimbusJwtDecoderJwkSupport(this.properties.getJwt().getJwkSetUri()); } @Bean - @Conditional(OidcIssuerLocationCondition.class) + @Conditional(IssuerUriCondition.class) @ConditionalOnMissingBean - public JwtDecoder jwtDecoderByOidcIssuerLocation() { + public JwtDecoder jwtDecoderByIssuerUri() { return JwtDecoders - .fromOidcIssuerLocation(this.properties.getJwt().getOidcIssuerLocation()); + .fromOidcIssuerLocation(this.properties.getJwt().getIssuerUri()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java index e248b08bbf73..56cda029bb6b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java @@ -85,16 +85,17 @@ public void autoConfigurationShouldConfigureResourceServer() { } @Test - public void autoConfigurationShouldConfigureResourceServerOidcIssuerLocation() + public void autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws Exception { this.server = new MockWebServer(); this.server.start(); String issuer = this.server.url("").toString(); String cleanIssuerPath = cleanIssuerPath(issuer); setupMockResponse(cleanIssuerPath); - this.contextRunner.withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://" - + this.server.getHostName() + ":" + this.server.getPort()) + this.contextRunner + .withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + + this.server.getHostName() + ":" + this.server.getPort()) .run((context) -> { assertThat(context.getBean(JwtDecoder.class)) .isInstanceOf(NimbusJwtDecoderJwkSupport.class); @@ -103,23 +104,16 @@ public void autoConfigurationShouldConfigureResourceServerOidcIssuerLocation() } @Test - public void autoConfigurationShouldConfigureSetUriWithTwoProperties() - throws Exception { - this.server = new MockWebServer(); - this.server.start(); - String issuer = this.server.url("").toString(); - String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponse(cleanIssuerPath); + public void autoConfigurationWhenBothSetUriAndIssuerUriPresentShouldUseSetUri() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://" - + this.server.getHostName() + ":" + this.server.getPort(), + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://issuer-uri.com", "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .run((context) -> { assertThat(context.getBean(JwtDecoder.class)) .isInstanceOf(NimbusJwtDecoderJwkSupport.class); assertThat(getBearerTokenFilter(context)).isNotNull(); - assertThat(context.containsBean("jwtDecoder")).isTrue(); - assertThat(context.containsBean("jwtDecoderByOidcIssuerLocation")) + assertThat(context.containsBean("jwtDecoderByJwkKeySetUri")).isTrue(); + assertThat(context.containsBean("jwtDecoderByOidcIssuerUri")) .isFalse(); }); } @@ -131,7 +125,7 @@ public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { } @Test - public void jwtDecoderBeanIsConditionalOnMissingBean() { + public void jwtDecoderByJwkSetUriIsConditionalOnMissingBean() { this.contextRunner.withPropertyValues( "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com") .withUserConfiguration(JwtDecoderConfig.class) @@ -139,9 +133,9 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { } @Test - public void jwtDecoderBeanIsConditionalOnMissingBeanOidcIssuerLocation() { + public void jwtDecoderByOidcIssuerUriIsConditionalOnMissingBean() { this.contextRunner.withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://jwk-oidc-issuer-location.com") + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") .withUserConfiguration(JwtDecoderConfig.class) .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull()); } @@ -155,15 +149,6 @@ public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); } - @Test - public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClassOidcIssuerLocation() { - this.contextRunner.withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.oidc-issuer-location=http://jwk-oidc-issuer-location.com") - .withUserConfiguration(JwtDecoderConfig.class) - .withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class)) - .run((context) -> assertThat(getBearerTokenFilter(context)).isNull()); - } - @SuppressWarnings("unchecked") private Filter getBearerTokenFilter(AssertableWebApplicationContext context) { FilterChainProxy filterChain = (FilterChainProxy) context diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 0e6fa7110272..8db9dd7edecb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -539,7 +539,7 @@ content into your application. Rather, pick only the properties that you need. # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) spring.security.oauth2.resourceserver.jwt.jwk-set-uri= # JSON Web Key URI to use to verify the JWT token. - spring.security.oauth2.resource.jwt.oidc-issuer-location= # Location for issuer oidc + spring.security.oauth2.resource.jwt.issuer-uri= # URI that an OpenID Connect Provider asserts as its Issuer Identifier. # ---------------------------------------- # DATA PROPERTIES diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 22292f2ec8ee..1821bf6b9c5c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3320,14 +3320,19 @@ Provider can be configured with the `issuer-uri`: [[boot-features-security-oauth2-server]] ==== Resource Server If you have `spring-security-oauth2-resource-server` on your classpath, Spring Boot can -set up an OAuth2 Resource Server as long as a JWK Set URI is specified, as shown in the -following example: +set up an OAuth2 Resource Server as long as a JWK Set URI or OIDC Issuer URI is specified, +as shown in the following examples: [source,properties,indent=0] ---- spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys ---- +[source,properties,indent=0] +---- + spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/ +---- + The same properties are applicable for both servlet and reactive applications. Alternatively, you can define your own `JwtDecoder` bean for servlet applications From fe3fe0fa63df25699d23a9ee02c37aae3c17a38a Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sun, 26 Aug 2018 05:03:02 +0900 Subject: [PATCH 458/701] Polish Closes gh-14202 --- .../orm/jpa/DataSourceInitializedPublisher.java | 6 +++--- .../restart/classloader/RestartClassLoaderTests.java | 2 +- .../src/main/asciidoc/spring-boot-features.adoc | 2 +- .../properties/source/AbstractPropertyMapperTests.java | 8 -------- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java index 166135fc18df..ebc24e6e1f04 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/DataSourceInitializedPublisher.java @@ -64,7 +64,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof LocalContainerEntityManagerFactoryBean) { LocalContainerEntityManagerFactoryBean factory = (LocalContainerEntityManagerFactoryBean) bean; - factory.setJpaVendorAdapter(new DataSourceSchemeCreatedPublisher(factory)); + factory.setJpaVendorAdapter(new DataSourceSchemaCreatedPublisher(factory)); } return bean; } @@ -140,13 +140,13 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, } - final class DataSourceSchemeCreatedPublisher implements JpaVendorAdapter { + final class DataSourceSchemaCreatedPublisher implements JpaVendorAdapter { private final JpaVendorAdapter delegate; private final LocalContainerEntityManagerFactoryBean factory; - private DataSourceSchemeCreatedPublisher( + private DataSourceSchemaCreatedPublisher( LocalContainerEntityManagerFactoryBean factory) { this.delegate = factory.getJpaVendorAdapter(); this.factory = factory; diff --git a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java index 8327df6993e2..8b0241b5c8d6 100644 --- a/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java +++ b/spring-boot-project/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java @@ -213,7 +213,7 @@ private String readString(InputStream in) throws IOException { private List toList(Enumeration enumeration) { return (enumeration != null) ? Collections.list(enumeration) - : Collections.emptyList(); + : Collections.emptyList(); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1821bf6b9c5c..f0bae95a8e07 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5645,7 +5645,7 @@ The following component creates a listener endpoint on the `someTopic` topic: Spring for Apache Kafka provides a factory bean to create a `StreamsBuilder` object and manage the lifecycle of its streams. Spring Boot auto-configures the required `KafkaStreamsConfiguration` bean as long as `kafka-streams` in on the classpath and kafka -streams is enabled via the @EnableKafkaStreams` annotation. +streams is enabled via the `@EnableKafkaStreams` annotation. Enabling Kafka Streams means that the application id and bootstrap servers must be set. The former can be configured using `spring.kafka.streams.application-id`, defaulting to diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java index bacbcc8e0985..be1c9059e56c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java @@ -31,20 +31,12 @@ public abstract class AbstractPropertyMapperTests { protected abstract PropertyMapper getMapper(); protected final Iterator namesFromString(String name) { - return namesFromString(name, "value"); - } - - protected final Iterator namesFromString(String name, Object value) { return Arrays.stream(getMapper().map(name)) .map((mapping) -> mapping.getConfigurationPropertyName().toString()) .iterator(); } protected final Iterator namesFromConfiguration(String name) { - return namesFromConfiguration(name, "value"); - } - - protected final Iterator namesFromConfiguration(String name, String value) { return Arrays.stream(getMapper().map(ConfigurationPropertyName.of(name))) .map(PropertyMapping::getPropertySourceName).iterator(); } From a86d7cdb97139579f49929f931660a87db73399f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 27 Aug 2018 13:56:48 +0200 Subject: [PATCH 459/701] Add execution id to `repackage` goal Closes gh-14210 --- .../spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc | 2 ++ .../spring-boot-starters/spring-boot-starter-parent/pom.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 152a06c9c2a2..af3e62610cec 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -58,6 +58,8 @@ defaults. The parent project provides the following features: the spring-boot-dependencies pom, that manages the versions of common dependencies. This dependency management lets you omit tags for those dependencies when used in your own pom. +* An execution of the {spring-boot-maven-plugin-site}/repackage-mojo.html[`repackage` +goal] with a `repackage` execution id. * Sensible https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html[resource filtering]. diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/pom.xml index ba459a2917d2..c88f2df33050 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-parent/pom.xml @@ -156,6 +156,7 @@ spring-boot-maven-plugin + repackage repackage From cf17106d8ded5f7be4a8920d2ff438404afcd18a Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 28 Aug 2018 00:15:46 +0900 Subject: [PATCH 460/701] Polish Closes gh-14212 --- .../task/TaskSchedulingProperties.java | 1 + .../main/resources/META-INF/spring.factories | 2 +- .../TaskSchedulingAutoConfigurationTests.java | 4 +- .../WebFluxAutoConfigurationTests.java | 4 +- .../main/asciidoc/spring-boot-features.adoc | 4 +- .../properties/PropertyMapperTests.java | 2 +- .../boot/task/TaskSchedulerBuilderTests.java | 40 ++++++++++--------- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java index 27ee57c2acfc..1edb46bb691c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java @@ -22,6 +22,7 @@ * Configuration properties for task scheduling. * * @author Stephane Nicoll + * @since 2.1.0 */ @ConfigurationProperties("spring.task.scheduling") public class TaskSchedulingProperties { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index cf88c0a33c1b..1070f995bd4c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -96,7 +96,6 @@ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ -org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ @@ -111,6 +110,7 @@ org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2Re org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\ +org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java index 6ce10dcc183b..afb863aa2874 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java @@ -16,8 +16,8 @@ package org.springframework.boot.autoconfigure.task; -import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.junit.Test; @@ -158,7 +158,7 @@ public TestBean testBean() { static class TestBean { - private final Set threadNames = new HashSet<>(); + private final Set threadNames = ConcurrentHashMap.newKeySet(); @Scheduled(fixedRate = 10) public void accumulate() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 74cc41e867b0..4857f023f119 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -517,7 +517,7 @@ public HiddenHttpMethodFilter customHiddenHttpMethodFilter() { static class CustomRequestMappingHandlerAdapter { @Bean - public WebFluxRegistrations webMvcRegistrationsHandlerAdapter() { + public WebFluxRegistrations webFluxRegistrationsHandlerAdapter() { return new WebFluxRegistrations() { @Override @@ -546,7 +546,7 @@ static class MultipleWebFluxRegistrations { static class CustomRequestMappingHandlerMapping { @Bean - public WebFluxRegistrations webMvcRegistrationsHandlerMapping() { + public WebFluxRegistrations webFluxRegistrationsHandlerMapping() { return new WebFluxRegistrations() { @Override diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index f0bae95a8e07..9b2cd915248a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6201,11 +6201,11 @@ tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool i aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default). -A `ThreadPoolTaskScheduler` can also be auto-configured if need to be to be associated to +A `ThreadPoolTaskScheduler` can also be auto-configured if need to be associated to scheduled task execution (`@EnableScheduling`). The thread pool uses one thread by default and those settings can be fine-tuned using the `spring.task.scheduling` namespace. -Both a `TaskExecutorBuilder` and `TaskSchedulerBuilder` bean are made available in the +Both a `TaskExecutorBuilder` bean and a `TaskSchedulerBuilder` bean are made available in the context if a custom executor or scheduler needs to be created. diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java index 7b0d5ef985e5..d0d1760e45ca 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java @@ -52,7 +52,7 @@ public void fromValue() { } @Test - public void fromValueAsIntShouldAdaptSupplier() { + public void fromValueAsIntShouldAdaptValue() { Integer result = this.map.from("123").asInt(Long::valueOf) .toInstance(Integer::new); assertThat(result).isEqualTo(123); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java index 839cae4393a9..39a9a5bf632a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java @@ -22,11 +22,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.Mockito; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Tests for {@link TaskSchedulerBuilder}. @@ -55,8 +58,9 @@ public void poolSettingsShouldApply() { @Test public void threadNamePrefixShouldApply() { - ThreadPoolTaskScheduler executor = this.builder.threadNamePrefix("test-").build(); - assertThat(executor.getThreadNamePrefix()).isEqualTo("test-"); + ThreadPoolTaskScheduler scheduler = this.builder.threadNamePrefix("test-") + .build(); + assertThat(scheduler.getThreadNamePrefix()).isEqualTo("test-"); } @Test @@ -75,30 +79,30 @@ public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { @Test public void customizersShouldApply() { - TaskSchedulerCustomizer customizer = Mockito.mock(TaskSchedulerCustomizer.class); - ThreadPoolTaskScheduler executor = this.builder.customizers(customizer).build(); - Mockito.verify(customizer).customize(executor); + TaskSchedulerCustomizer customizer = mock(TaskSchedulerCustomizer.class); + ThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer).build(); + verify(customizer).customize(scheduler); } @Test public void customizersShouldBeAppliedLast() { - ThreadPoolTaskScheduler scheduler = Mockito.spy(new ThreadPoolTaskScheduler()); + ThreadPoolTaskScheduler scheduler = spy(new ThreadPoolTaskScheduler()); this.builder.poolSize(4).threadNamePrefix("test-") .additionalCustomizers((taskScheduler) -> { - Mockito.verify(taskScheduler).setPoolSize(4); - Mockito.verify(taskScheduler).setThreadNamePrefix("test-"); + verify(taskScheduler).setPoolSize(4); + verify(taskScheduler).setThreadNamePrefix("test-"); }); this.builder.configure(scheduler); } @Test public void customizersShouldReplaceExisting() { - TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); - TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); - ThreadPoolTaskScheduler executor = this.builder.customizers(customizer1) + TaskSchedulerCustomizer customizer1 = mock(TaskSchedulerCustomizer.class); + TaskSchedulerCustomizer customizer2 = mock(TaskSchedulerCustomizer.class); + ThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1) .customizers(Collections.singleton(customizer2)).build(); - Mockito.verifyZeroInteractions(customizer1); - Mockito.verify(customizer2).customize(executor); + verifyZeroInteractions(customizer1); + verify(customizer2).customize(scheduler); } @Test @@ -117,12 +121,12 @@ public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowExce @Test public void additionalCustomizersShouldAddToExisting() { - TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); - TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); + TaskSchedulerCustomizer customizer1 = mock(TaskSchedulerCustomizer.class); + TaskSchedulerCustomizer customizer2 = mock(TaskSchedulerCustomizer.class); ThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1) .additionalCustomizers(customizer2).build(); - Mockito.verify(customizer1).customize(scheduler); - Mockito.verify(customizer2).customize(scheduler); + verify(customizer1).customize(scheduler); + verify(customizer2).customize(scheduler); } } From 422a436df19d8edab11e72ad1b91aca744cabcad Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Sun, 8 Jul 2018 18:12:05 +0200 Subject: [PATCH 461/701] Polish some Collectors See gh-13727 --- .../endpoint/ExposeExcludePropertyEndpointFilter.java | 3 +-- .../boot/actuate/metrics/MetricsEndpoint.java | 2 +- .../boot/autoconfigure/AutoConfigurations.java | 7 +++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java index d61b0370c9be..c2b2e769b87e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ExposeExcludePropertyEndpointFilter.java @@ -20,7 +20,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; @@ -83,7 +82,7 @@ private Set asSet(Collection items) { return Collections.emptySet(); } return items.stream().map((item) -> item.toLowerCase(Locale.ENGLISH)) - .collect(Collectors.toCollection(HashSet::new)); + .collect(Collectors.toSet()); } @Override diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/MetricsEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/MetricsEndpoint.java index fbe4da8f49bb..2e2ebd7e8e25 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/MetricsEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/MetricsEndpoint.java @@ -158,7 +158,7 @@ private Set merge(Set set1, Set set2) { private List asList(Map map, BiFunction mapper) { return map.entrySet().stream() .map((entry) -> mapper.apply(entry.getKey(), entry.getValue())) - .collect(Collectors.toCollection(ArrayList::new)); + .collect(Collectors.toList()); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java index b611cf3b3da7..ea5c50fa034d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,7 +16,6 @@ package org.springframework.boot.autoconfigure; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -48,11 +47,11 @@ protected AutoConfigurations(Collection> classes) { @Override protected Collection> sort(Collection> classes) { List names = classes.stream().map(Class::getName) - .collect(Collectors.toCollection(ArrayList::new)); + .collect(Collectors.toList()); List sorted = SORTER.getInPriorityOrder(names); return sorted.stream() .map((className) -> ClassUtils.resolveClassName(className, null)) - .collect(Collectors.toCollection(ArrayList::new)); + .collect(Collectors.toList()); } @Override From d9c0dbb99d827b4fb98f7a1b11f28019affc935d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 27 Aug 2018 18:09:19 +0200 Subject: [PATCH 462/701] Polish "Polish some Collectors" Closes gh-13727 --- .../springframework/boot/autoconfigure/AutoConfigurations.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java index ea5c50fa034d..4fdcd35bc062 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -51,7 +52,7 @@ protected Collection> sort(Collection> classes) { List sorted = SORTER.getInPriorityOrder(names); return sorted.stream() .map((className) -> ClassUtils.resolveClassName(className, null)) - .collect(Collectors.toList()); + .collect(Collectors.toCollection(ArrayList::new)); } @Override From c7b7a1402ad0ff4b1e52b7e0c0b6b43c9613fb28 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 17 Jul 2018 11:38:34 +0100 Subject: [PATCH 463/701] Make some nested private classes package private Closes gh-13795 --- .../cache/HazelcastJCacheCustomizationConfiguration.java | 3 +-- .../autoconfigure/web/reactive/WebFluxAutoConfiguration.java | 2 +- .../autoconfigure/web/servlet/WebMvcAutoConfiguration.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java index b36cbdf204c3..4168f217d7e8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java @@ -43,8 +43,7 @@ public HazelcastPropertiesCustomizer hazelcastPropertiesCustomizer( return new HazelcastPropertiesCustomizer(hazelcastInstance.getIfUnique()); } - private static class HazelcastPropertiesCustomizer - implements JCachePropertiesCustomizer { + static class HazelcastPropertiesCustomizer implements JCachePropertiesCustomizer { private final HazelcastInstance hazelcastInstance; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index b37c11d3dcc8..bc8e2a38a591 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -292,7 +292,7 @@ interface ResourceHandlerRegistrationCustomizer { } - private static class ResourceChainResourceHandlerRegistrationCustomizer + static class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer { @Autowired diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 2683a7200c9a..19e8ecbc98e1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -598,7 +598,7 @@ interface ResourceHandlerRegistrationCustomizer { } - private static class ResourceChainResourceHandlerRegistrationCustomizer + static class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer { @Autowired From db27d8fdf8caf75f168199b3eb3a7c649532f231 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 27 Aug 2018 18:28:27 +0200 Subject: [PATCH 464/701] Revert "Polish dependency management for OIDC starter" This reverts commit 3ad3cfd7e2de42aaaf8ba0af258ef21a064027bc. Closes gh-14137 --- .../spring-boot-starter-oauth2-oidc-client/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml index 7ae182e28313..e59f26b07fc9 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-oauth2-oidc-client/pom.xml @@ -29,12 +29,6 @@ org.springframework.security spring-security-oauth2-client - - - javax.mail - javax.mail-api - - org.springframework.security From 04b7c4c6d96de0981730365c629e2f3ff9864c0e Mon Sep 17 00:00:00 2001 From: artsiom Date: Sat, 25 Aug 2018 13:08:58 +0300 Subject: [PATCH 465/701] Support issuer uri in reactive OAuth2 resource-server config --- ...eOAuth2ResourceServerJwkConfiguration.java | 12 ++ ...2ResourceServerAutoConfigurationTests.java | 129 ++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java index 3a0c0be7552e..f54f8d15fb67 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java @@ -17,16 +17,20 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.security.oauth2.resource.IssuerUriCondition; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; /** * Configures a {@link ReactiveJwtDecoder} when a JWK Set URI is available. * * @author Madhura Bhave + * @author Artsiom Yudovin */ @Configuration class ReactiveOAuth2ResourceServerJwkConfiguration { @@ -45,4 +49,12 @@ public ReactiveJwtDecoder jwtDecoder() { return new NimbusReactiveJwtDecoder(this.properties.getJwt().getJwkSetUri()); } + @Bean + @Conditional(IssuerUriCondition.class) + @ConditionalOnMissingBean + public ReactiveJwtDecoder jwtDecoderByIssuerUri() { + return ReactiveJwtDecoders + .fromOidcIssuerLocation(this.properties.getJwt().getIssuerUri()); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index de7c57dd05d3..d4334a763366 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -15,9 +15,18 @@ */ package org.springframework.boot.autoconfigure.security.oauth2.resource.reactive; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.After; import org.junit.Test; +import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; @@ -25,6 +34,9 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; @@ -47,6 +59,7 @@ * Tests for {@link ReactiveOAuth2ResourceServerAutoConfiguration}. * * @author Madhura Bhave + * @author Artsiom Yudovin */ public class ReactiveOAuth2ResourceServerAutoConfigurationTests { @@ -55,6 +68,15 @@ public class ReactiveOAuth2ResourceServerAutoConfigurationTests { .of(ReactiveOAuth2ResourceServerAutoConfiguration.class)) .withUserConfiguration(TestConfig.class); + private MockWebServer server; + + @After + public void cleanup() throws Exception { + if (this.server != null) { + this.server.shutdown(); + } + } + @Test public void autoConfigurationShouldConfigureResourceServer() { this.contextRunner.withPropertyValues( @@ -66,6 +88,39 @@ public void autoConfigurationShouldConfigureResourceServer() { }); } + @Test + public void autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() + throws IOException { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + this.contextRunner + .withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + + this.server.getHostName() + ":" + this.server.getPort()) + .run((context) -> { + assertThat(context.getBean(ReactiveJwtDecoder.class)) + .isInstanceOf(NimbusReactiveJwtDecoder.class); + assertFilterConfiguredWithJwtAuthenticationManager(context); + }); + } + + @Test + public void autoConfigurationWhenBothSetUriAndIssuerUriPresentShouldUseSetUri() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://jwk-set-uri.com", + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") + .run((context) -> { + assertThat(context.getBean(ReactiveJwtDecoder.class)) + .isInstanceOf(NimbusReactiveJwtDecoder.class); + assertFilterConfiguredWithJwtAuthenticationManager(context); + assertThat(context.containsBean("jwtDecoder")).isTrue(); + assertThat(context.containsBean("jwtDecoderByIssuerUri")).isFalse(); + }); + } + @Test public void autoConfigurationWhenJwkSetUriNullShouldNotFail() { this.contextRunner.run((context) -> assertThat(context) @@ -80,6 +135,14 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { .run((this::assertFilterConfiguredWithJwtAuthenticationManager)); } + @Test + public void jwtDecoderBeanIsConditionalOnMissingBeanUsingOidcIssuerUri() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") + .withUserConfiguration(JwtDecoderConfig.class) + .run((this::assertFilterConfiguredWithJwtAuthenticationManager)); + } + @Test public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClass() { this.contextRunner.withPropertyValues( @@ -91,6 +154,17 @@ public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationToken .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); } + @Test + public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClassUsingOidcIssuerUri() { + this.contextRunner.withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") + .withUserConfiguration(JwtDecoderConfig.class) + .withClassLoader( + new FilteredClassLoader(BearerTokenAuthenticationToken.class)) + .run((context) -> assertThat(context) + .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); + } + @Test public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() { this.contextRunner.withPropertyValues( @@ -102,6 +176,25 @@ public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAdd }); } + @Test + public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOneUsingOidcIssuerUri() + throws IOException { + this.server = new MockWebServer(); + this.server.start(); + String issuer = this.server.url("").toString(); + String cleanIssuerPath = cleanIssuerPath(issuer); + setupMockResponse(cleanIssuerPath); + this.contextRunner + .withPropertyValues( + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" + + this.server.getHostName() + ":" + this.server.getPort()) + .withUserConfiguration(SecurityWebFilterChainConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(SecurityWebFilterChain.class); + assertThat(context).hasBean("testSpringSecurityFilterChain"); + }); + } + @SuppressWarnings("unchecked") private void assertFilterConfiguredWithJwtAuthenticationManager( AssertableReactiveWebApplicationContext context) { @@ -119,6 +212,42 @@ private void assertFilterConfiguredWithJwtAuthenticationManager( } + private String cleanIssuerPath(String issuer) { + if (issuer.endsWith("/")) { + return issuer.substring(0, issuer.length() - 1); + } + return issuer; + } + + private void setupMockResponse(String issuer) throws JsonProcessingException { + MockResponse mockResponse = new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .setBody(new ObjectMapper().writeValueAsString(getResponse(issuer))) + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + this.server.enqueue(mockResponse); + } + + private Map getResponse(String issuer) { + Map response = new HashMap<>(); + response.put("authorization_endpoint", "https://example.com/o/oauth2/v2/auth"); + response.put("claims_supported", Collections.emptyList()); + response.put("code_challenge_methods_supported", Collections.emptyList()); + response.put("id_token_signing_alg_values_supported", Collections.emptyList()); + response.put("issuer", issuer); + response.put("jwks_uri", "https://example.com/oauth2/v3/certs"); + response.put("response_types_supported", Collections.emptyList()); + response.put("revocation_endpoint", "https://example.com/o/oauth2/revoke"); + response.put("scopes_supported", Collections.singletonList("openid")); + response.put("subject_types_supported", Collections.singletonList("public")); + response.put("grant_types_supported", + Collections.singletonList("authorization_code")); + response.put("token_endpoint", "https://example.com/oauth2/v4/token"); + response.put("token_endpoint_auth_methods_supported", + Collections.singletonList("client_secret_basic")); + response.put("userinfo_endpoint", "https://example.com/oauth2/v3/userinfo"); + return response; + } + @EnableWebFluxSecurity static class TestConfig { From 35d7bb7f340671f2decd98d4623b7adfddb82ad2 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 27 Aug 2018 14:09:48 -0700 Subject: [PATCH 466/701] Polish "issuer uri in reactive resource-server config" Closes gh-14199 --- ...2ResourceServerAutoConfigurationTests.java | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index d4334a763366..bcca68b1519c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -136,7 +136,7 @@ public void jwtDecoderBeanIsConditionalOnMissingBean() { } @Test - public void jwtDecoderBeanIsConditionalOnMissingBeanUsingOidcIssuerUri() { + public void jwtDecoderByIssuerUriBeanIsConditionalOnMissingBean() { this.contextRunner.withPropertyValues( "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") .withUserConfiguration(JwtDecoderConfig.class) @@ -154,17 +154,6 @@ public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationToken .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); } - @Test - public void autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClassUsingOidcIssuerUri() { - this.contextRunner.withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://jwk-oidc-issuer-location.com") - .withUserConfiguration(JwtDecoderConfig.class) - .withClassLoader( - new FilteredClassLoader(BearerTokenAuthenticationToken.class)) - .run((context) -> assertThat(context) - .doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)); - } - @Test public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() { this.contextRunner.withPropertyValues( @@ -176,25 +165,6 @@ public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAdd }); } - @Test - public void autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOneUsingOidcIssuerUri() - throws IOException { - this.server = new MockWebServer(); - this.server.start(); - String issuer = this.server.url("").toString(); - String cleanIssuerPath = cleanIssuerPath(issuer); - setupMockResponse(cleanIssuerPath); - this.contextRunner - .withPropertyValues( - "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://" - + this.server.getHostName() + ":" + this.server.getPort()) - .withUserConfiguration(SecurityWebFilterChainConfig.class) - .run((context) -> { - assertThat(context).hasSingleBean(SecurityWebFilterChain.class); - assertThat(context).hasBean("testSpringSecurityFilterChain"); - }); - } - @SuppressWarnings("unchecked") private void assertFilterConfiguredWithJwtAuthenticationManager( AssertableReactiveWebApplicationContext context) { From f3fa952cbc1911e9f0685820be22c2df0684361c Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 27 Aug 2018 16:35:49 -0700 Subject: [PATCH 467/701] Support WebExceptionHandler in @WebFluxTest Closes gh-13627 --- .../reactive/WebFluxTypeExcludeFilter.java | 2 + .../webclient/ExampleController1.java | 5 +++ .../webclient/ExampleWebExceptionHandler.java | 40 +++++++++++++++++++ ...luxTestAllControllersIntegrationTests.java | 5 +++ 4 files changed, 52 insertions(+) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleWebExceptionHandler.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java index cf9666844c0c..d1650ac5cf04 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java @@ -32,6 +32,7 @@ import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.reactive.config.WebFluxConfigurer; +import org.springframework.web.server.WebExceptionHandler; /** * {@link TypeExcludeFilter} for {@link WebFluxTest @WebFluxTest}. @@ -49,6 +50,7 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { includes.add(WebFluxConfigurer.class); includes.add(Converter.class); includes.add(GenericConverter.class); + includes.add(WebExceptionHandler.class); DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java index 53c31fe653ba..b70e319437c0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java @@ -36,4 +36,9 @@ public Mono one() { return Mono.just("one"); } + @GetMapping("/one/error") + public Mono error() { + throw new RuntimeException("foo"); + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleWebExceptionHandler.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleWebExceptionHandler.java new file mode 100644 index 000000000000..0840ea809b4f --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleWebExceptionHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.web.reactive.webclient; + +import reactor.core.publisher.Mono; + +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebExceptionHandler; + +/** + * Example {@link WebExceptionHandler} used with {@link WebFluxTest} tests. + * + * @author Madhura Bhave + */ +@Component +public class ExampleWebExceptionHandler implements WebExceptionHandler { + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); + return exchange.getResponse().setComplete(); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java index eb9087385f02..c51b909175f8 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java @@ -48,4 +48,9 @@ public void shouldFindController2() { .expectBody(String.class).isEqualTo("two"); } + @Test + public void webExceptionHandling() { + this.webClient.get().uri("/one/error").exchange().expectStatus().isBadRequest(); + } + } From 46415cb859e8ebd51e52fd3a3ea7dd47bbbeb4db Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 28 Aug 2018 21:26:47 +0900 Subject: [PATCH 468/701] Add Spring Boot starter for Narayana in doc Closes gh-14220 --- spring-boot-project/spring-boot-starters/README.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 21590dbcf54b..9b7bed2ec7dd 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -112,6 +112,9 @@ do as they were designed before this was clarified. | http://mybatis.org/mybatis-3/[MyBatis] | https://github.com/mybatis/mybatis-spring-boot +| http://narayana.io/[Narayana] +| https://github.com/snowdrop/narayana-spring-boot + | http://square.github.io/okhttp/[OkHttp] | https://github.com/freefair/okhttp-spring-boot From d549e6001a42b528b7458467ce19469649ea98af Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 22 Aug 2018 13:55:28 +0200 Subject: [PATCH 469/701] Add support for com.mongodb.client.MongoClient Next to com.mongodb.MongoClient the MongoDB Java driver offers the com.mongodb.client.MongoClient as entry point for database and collection operations. Spring Data MongoDB supports c.m.client.MongoClient via its MongoDbFactory using SimpleMongoClientDbFactory. The MongoAutoConfiguration now backs off if any of those two clients is already defined in the Application context allowing MongoDataAutoConfiguration to pick up the users driver implementation of choice. See gh-14176 --- .../mongo/MongoDataAutoConfiguration.java | 112 +++++++++++++++++- .../mongo/MongoAutoConfiguration.java | 3 +- .../MongoDataAutoConfigurationTests.java | 23 ++++ .../mongo/MongoAutoConfigurationTests.java | 23 ++++ 4 files changed, 155 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 9ff49965b952..58cda155f06f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -16,27 +16,35 @@ package org.springframework.boot.autoconfigure.data.mongo; +import java.util.Arrays; +import java.util.List; + import com.mongodb.ClientSessionOptions; import com.mongodb.DB; import com.mongodb.MongoClient; import com.mongodb.client.ClientSession; import com.mongodb.client.MongoDatabase; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 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.data.mongo.MongoDataAutoConfiguration.AnySyncMongoClientAvailable; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.core.convert.DbRefResolver; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; @@ -63,11 +71,12 @@ * @author Phillip Webb * @author Eddú Meléndez * @author Stephane Nicoll + * @author Christoph Strobl * @since 1.1.0 */ @Configuration @ConditionalOnClass({ MongoClient.class, MongoTemplate.class }) -@ConditionalOnBean(MongoClient.class) +@Conditional(AnySyncMongoClientAvailable.class) @EnableConfigurationProperties(MongoProperties.class) @Import(MongoDataConfiguration.class) @AutoConfigureAfter(MongoAutoConfiguration.class) @@ -75,15 +84,22 @@ public class MongoDataAutoConfiguration { private final MongoProperties properties; - public MongoDataAutoConfiguration(MongoProperties properties) { + private final MongoDbFactoryFactory dbFactoryFactory; + + public MongoDataAutoConfiguration(ObjectProvider mongoClientProvider, + ObjectProvider mongoClientClientProvider, + MongoProperties properties) { + this.properties = properties; + this.dbFactoryFactory = new MongoDbFactoryFactory(mongoClientProvider, + mongoClientClientProvider); } @Bean + @Conditional(AnySyncMongoClientAvailable.class) @ConditionalOnMissingBean(MongoDbFactory.class) - public SimpleMongoDbFactory mongoDbFactory(MongoClient mongo) { - String database = this.properties.getMongoClientDatabase(); - return new SimpleMongoDbFactory(mongo, database); + public MongoDbFactory mongoDbFactory() { + return this.dbFactoryFactory.getFor(this.properties.getMongoClientDatabase()); } @Bean @@ -166,4 +182,90 @@ public MongoDbFactory withSession(ClientSession session) { } + /** + * Check if either {@link com.mongodb.MongoClient} or + * {@link com.mongodb.client.MongoClient} is already defined in the + * {@link org.springframework.context.ApplicationContext}. + * + * @author Christoph Strobl + * @since 2.1 + */ + static class AnySyncMongoClientAvailable extends AnyNestedCondition { + + AnySyncMongoClientAvailable() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnBean(com.mongodb.MongoClient.class) + static class MongoClientPreferred { + + } + + @ConditionalOnBean(com.mongodb.client.MongoClient.class) + static class MongoClientClientPreferred { + + } + + } + + /** + * Encapsulation of {@link MongoDbFactory} creation depending on available beans + * {@link com.mongodb.MongoClient} or {@link com.mongodb.client.MongoClient} expressed + * via the given {@link ObjectProvider ObjectProviders}. Prefers the first available + * MongoDB client creating a suitable instance of {@link MongoDbFactory} for it. + * + * @author Christoph Strobl + * @since 2.1 + */ + static class MongoDbFactoryFactory { + + private final List> clientProviders; + + /** + * Create new instance of {@link MongoDbFactoryFactory}. + * @param clientProviders order matters here, as we choose the first available + * one. + */ + MongoDbFactoryFactory(ObjectProvider... clientProviders) { + this.clientProviders = Arrays.asList(clientProviders); + } + + /** + * Get the {@link MongoDbFactory} suitable for the first available MongoDB client. + * @param database the name of the default database to return on + * {@link MongoDbFactory#getDb()}. + * @return new instance of {@link MongoDbFactory} suitable for the first available + * MongoDB client. + */ + MongoDbFactory getFor(String database) { + + Object client = findAvailableClientProvider(); + + if (client instanceof MongoClient) { + return new SimpleMongoDbFactory(MongoClient.class.cast(client), database); + } + + if (client instanceof com.mongodb.client.MongoClient) { + return new SimpleMongoClientDbFactory( + com.mongodb.client.MongoClient.class.cast(client), database); + } + + return null; + } + + private Object findAvailableClientProvider() { + + for (ObjectProvider provider : this.clientProviders) { + Object client = provider.getIfAvailable(); + if (client != null) { + return client; + } + } + + throw new IllegalStateException( + "Expected to find at least one MongoDB client."); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java index 659f709aa474..f93a7edb36f1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java @@ -65,7 +65,8 @@ public void close() { } @Bean - @ConditionalOnMissingBean + @ConditionalOnMissingBean(type = { "com.mongodb.MongoClient", + "com.mongodb.client.MongoClient" }) public MongoClient mongo() { this.mongo = this.factory.createMongoClient(this.options); return this.mongo; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java index 74ba12f9f9bc..a9e6f0b5cf69 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java @@ -21,6 +21,7 @@ import java.util.Set; import com.mongodb.MongoClient; +import com.mongodb.client.MongoClients; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; @@ -39,7 +40,9 @@ import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy; import org.springframework.data.mapping.model.FieldNamingStrategy; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; +import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @@ -173,6 +176,16 @@ public void backsOffIfMongoClientBeanIsNotPresent() { .doesNotHaveBean(MongoDataAutoConfiguration.class)); } + @Test + public void createsMongoDbFactoryForMongoClientClientWhenBeanPresent() { + + this.contextRunner.withUserConfiguration(WithMongoClientClientConfiguration.class) + .run((context) -> { + MongoDbFactory dbFactory = context.getBean(MongoDbFactory.class); + assertThat(dbFactory).isInstanceOf(SimpleMongoClientDbFactory.class); + }); + } + @SuppressWarnings({ "unchecked", "rawtypes" }) private static void assertDomainTypesDiscovered(MongoMappingContext mappingContext, Class... types) { @@ -197,6 +210,16 @@ static class EntityScanConfig { } + @Configuration + static class WithMongoClientClientConfiguration { + + @Bean + com.mongodb.client.MongoClient mongoClient() { + return MongoClients.create(); + } + + } + private static class MyConverter implements Converter { @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index 884ccd8331a2..c2eb05a29b4a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -20,14 +20,17 @@ import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; +import com.mongodb.client.MongoClients; import org.junit.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; /** @@ -78,6 +81,17 @@ public void optionsSslConfig() { }); } + @Test + public void doesNotCreateMongoClientWhenAlreadyDefined() { + + this.contextRunner + .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") + .withUserConfiguration(ConfigurationWithClientMongoClient.class) + .run((context) -> assertThatExceptionOfType( + NoSuchBeanDefinitionException.class) + .isThrownBy(() -> context.getBean(MongoClient.class))); + } + @Configuration static class OptionsConfig { @@ -104,4 +118,13 @@ public SocketFactory mySocketFactory() { } + static class ConfigurationWithClientMongoClient { + + @Bean + com.mongodb.client.MongoClient mongoClient() { + return MongoClients.create(); + } + + } + } From 56329e67d73ba18130b852868d6580d3d082405b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 28 Aug 2018 15:24:31 +0200 Subject: [PATCH 470/701] Polish "Add support for com.mongodb.client.MongoClient" Closes gh-14176 --- .../mongo/MongoDataAutoConfiguration.java | 114 ++++-------------- .../MongoDataAutoConfigurationTests.java | 16 ++- .../mongo/MongoAutoConfigurationTests.java | 16 ++- .../main/asciidoc/spring-boot-features.adoc | 4 + 4 files changed, 49 insertions(+), 101 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 58cda155f06f..cfbe4b1b7a53 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -16,9 +16,6 @@ package org.springframework.boot.autoconfigure.data.mongo; -import java.util.Arrays; -import java.util.List; - import com.mongodb.ClientSessionOptions; import com.mongodb.DB; import com.mongodb.MongoClient; @@ -32,7 +29,7 @@ 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.data.mongo.MongoDataAutoConfiguration.AnySyncMongoClientAvailable; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration.AnyMongoClientAvailable; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -43,6 +40,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoDbFactorySupport; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; @@ -75,8 +73,9 @@ * @since 1.1.0 */ @Configuration -@ConditionalOnClass({ MongoClient.class, MongoTemplate.class }) -@Conditional(AnySyncMongoClientAvailable.class) +@ConditionalOnClass({ MongoClient.class, com.mongodb.client.MongoClient.class, + MongoTemplate.class }) +@Conditional(AnyMongoClientAvailable.class) @EnableConfigurationProperties(MongoProperties.class) @Import(MongoDataConfiguration.class) @AutoConfigureAfter(MongoAutoConfiguration.class) @@ -84,22 +83,25 @@ public class MongoDataAutoConfiguration { private final MongoProperties properties; - private final MongoDbFactoryFactory dbFactoryFactory; - - public MongoDataAutoConfiguration(ObjectProvider mongoClientProvider, - ObjectProvider mongoClientClientProvider, - MongoProperties properties) { - + public MongoDataAutoConfiguration(MongoProperties properties) { this.properties = properties; - this.dbFactoryFactory = new MongoDbFactoryFactory(mongoClientProvider, - mongoClientClientProvider); } @Bean - @Conditional(AnySyncMongoClientAvailable.class) @ConditionalOnMissingBean(MongoDbFactory.class) - public MongoDbFactory mongoDbFactory() { - return this.dbFactoryFactory.getFor(this.properties.getMongoClientDatabase()); + public MongoDbFactorySupport mongoDbFactory(ObjectProvider mongo, + ObjectProvider mongoClient) { + MongoClient preferredClient = mongo.getIfAvailable(); + if (preferredClient != null) { + return new SimpleMongoDbFactory(preferredClient, + this.properties.getMongoClientDatabase()); + } + com.mongodb.client.MongoClient fallbackClient = mongoClient.getIfAvailable(); + if (fallbackClient != null) { + return new SimpleMongoClientDbFactory(fallbackClient, + this.properties.getMongoClientDatabase()); + } + throw new IllegalStateException("Expected to find at least one MongoDB client."); } @Bean @@ -183,87 +185,23 @@ public MongoDbFactory withSession(ClientSession session) { } /** - * Check if either {@link com.mongodb.MongoClient} or - * {@link com.mongodb.client.MongoClient} is already defined in the - * {@link org.springframework.context.ApplicationContext}. - * - * @author Christoph Strobl - * @since 2.1 + * Check if either a {@link com.mongodb.MongoClient} or + * {@link com.mongodb.client.MongoClient} bean is available. */ - static class AnySyncMongoClientAvailable extends AnyNestedCondition { + static class AnyMongoClientAvailable extends AnyNestedCondition { - AnySyncMongoClientAvailable() { + AnyMongoClientAvailable() { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnBean(com.mongodb.MongoClient.class) - static class MongoClientPreferred { + @ConditionalOnBean(MongoClient.class) + static class PreferredClientAvailable { } @ConditionalOnBean(com.mongodb.client.MongoClient.class) - static class MongoClientClientPreferred { - - } - - } - - /** - * Encapsulation of {@link MongoDbFactory} creation depending on available beans - * {@link com.mongodb.MongoClient} or {@link com.mongodb.client.MongoClient} expressed - * via the given {@link ObjectProvider ObjectProviders}. Prefers the first available - * MongoDB client creating a suitable instance of {@link MongoDbFactory} for it. - * - * @author Christoph Strobl - * @since 2.1 - */ - static class MongoDbFactoryFactory { - - private final List> clientProviders; - - /** - * Create new instance of {@link MongoDbFactoryFactory}. - * @param clientProviders order matters here, as we choose the first available - * one. - */ - MongoDbFactoryFactory(ObjectProvider... clientProviders) { - this.clientProviders = Arrays.asList(clientProviders); - } - - /** - * Get the {@link MongoDbFactory} suitable for the first available MongoDB client. - * @param database the name of the default database to return on - * {@link MongoDbFactory#getDb()}. - * @return new instance of {@link MongoDbFactory} suitable for the first available - * MongoDB client. - */ - MongoDbFactory getFor(String database) { - - Object client = findAvailableClientProvider(); - - if (client instanceof MongoClient) { - return new SimpleMongoDbFactory(MongoClient.class.cast(client), database); - } - - if (client instanceof com.mongodb.client.MongoClient) { - return new SimpleMongoClientDbFactory( - com.mongodb.client.MongoClient.class.cast(client), database); - } - - return null; - } - - private Object findAvailableClientProvider() { - - for (ObjectProvider provider : this.clientProviders) { - Object client = provider.getIfAvailable(); - if (client != null) { - return client; - } - } + static class FallbackClientAvailable { - throw new IllegalStateException( - "Expected to find at least one MongoDB client."); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java index a9e6f0b5cf69..432f99c3db1c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java @@ -43,6 +43,7 @@ import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; +import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @@ -177,9 +178,16 @@ public void backsOffIfMongoClientBeanIsNotPresent() { } @Test - public void createsMongoDbFactoryForMongoClientClientWhenBeanPresent() { + public void createsMongoDbFactoryForPreferredMongoClient() { + this.contextRunner.run((context) -> { + MongoDbFactory dbFactory = context.getBean(MongoDbFactory.class); + assertThat(dbFactory).isInstanceOf(SimpleMongoDbFactory.class); + }); + } - this.contextRunner.withUserConfiguration(WithMongoClientClientConfiguration.class) + @Test + public void createsMongoDbFactoryForFallbackMongoClient() { + this.contextRunner.withUserConfiguration(FallbackMongoClientConfiguration.class) .run((context) -> { MongoDbFactory dbFactory = context.getBean(MongoDbFactory.class); assertThat(dbFactory).isInstanceOf(SimpleMongoClientDbFactory.class); @@ -211,10 +219,10 @@ static class EntityScanConfig { } @Configuration - static class WithMongoClientClientConfiguration { + static class FallbackMongoClientConfiguration { @Bean - com.mongodb.client.MongoClient mongoClient() { + com.mongodb.client.MongoClient fallbackMongoClient() { return MongoClients.create(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index c2eb05a29b4a..b86757f85330 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -23,14 +23,12 @@ import com.mongodb.client.MongoClients; import org.junit.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; /** @@ -83,13 +81,13 @@ public void optionsSslConfig() { @Test public void doesNotCreateMongoClientWhenAlreadyDefined() { - this.contextRunner .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") - .withUserConfiguration(ConfigurationWithClientMongoClient.class) - .run((context) -> assertThatExceptionOfType( - NoSuchBeanDefinitionException.class) - .isThrownBy(() -> context.getBean(MongoClient.class))); + .withUserConfiguration(FallbackMongoClientConfig.class).run((context) -> { + assertThat(context).doesNotHaveBean(MongoClient.class); + assertThat(context) + .hasSingleBean(com.mongodb.client.MongoClient.class); + }); } @Configuration @@ -118,10 +116,10 @@ public SocketFactory mySocketFactory() { } - static class ConfigurationWithClientMongoClient { + static class FallbackMongoClientConfig { @Bean - com.mongodb.client.MongoClient mongoClient() { + com.mongodb.client.MongoClient fallbackMongoClient() { return MongoClients.create(); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 9b2cd915248a..38bbfe6e5807 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4029,6 +4029,10 @@ example, you might declare the following settings in your `application.propertie spring.data.mongodb.port=27017 ---- +If you have defined your own `MongoClient`, it will be used to auto-configure a suitable +`MongoDbFactory`. Both `com.mongodb.MongoClient` and `com.mongodb.client.MongoClient` +are supported. + NOTE: If you use the Mongo 3.0 Java driver, `spring.data.mongodb.host` and `spring.data.mongodb.port` are not supported. In such cases, `spring.data.mongodb.uri` should be used to provide all of the configuration. From 59c6dc5c7ad595082ccf37ddd8f891df86543b21 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 27 Aug 2018 09:27:11 -0400 Subject: [PATCH 471/701] Improve Kafka Auto-configuration - transaction manager - error handler - after rollback processor See gh-14215 --- ...fkaListenerContainerFactoryConfigurer.java | 40 +++++++++++++++++++ .../KafkaAnnotationDrivenConfiguration.java | 20 +++++++++- .../kafka/KafkaAutoConfigurationTests.java | 37 +++++++++++++++++ .../spring-boot-dependencies/pom.xml | 2 +- .../main/asciidoc/spring-boot-features.adoc | 15 ++++++- 5 files changed, 110 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java index bdc00693f574..c6b382735196 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java @@ -23,8 +23,11 @@ import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.AfterRollbackProcessor; import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.ErrorHandler; import org.springframework.kafka.support.converter.RecordMessageConverter; +import org.springframework.kafka.transaction.KafkaAwareTransactionManager; /** * Configure {@link ConcurrentKafkaListenerContainerFactory} with sensible defaults. @@ -41,6 +44,12 @@ public class ConcurrentKafkaListenerContainerFactoryConfigurer { private KafkaTemplate replyTemplate; + private KafkaAwareTransactionManager transactionManager; + + private ErrorHandler errorHandler; + + private AfterRollbackProcessor afterRollbackProcessor; + /** * Set the {@link KafkaProperties} to use. * @param properties the properties @@ -65,6 +74,32 @@ void setReplyTemplate(KafkaTemplate replyTemplate) { this.replyTemplate = replyTemplate; } + /** + * Set the {@link KafkaAwareTransactionManager} to use. + * @param transactionManager the transaction manager + */ + public void setTransactionManager( + KafkaAwareTransactionManager transactionManager) { + this.transactionManager = transactionManager; + } + + /** + * Set the {@link ErrorHandler} to use. + * @param errorHandler the error handler + */ + public void setErrorHandler(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + /** + * Set the {@link AfterRollbackProcessor} to use. + * @param afterRollbackProcessor the after rollback processor + */ + public void setAfterRollbackProcessor( + AfterRollbackProcessor afterRollbackProcessor) { + this.afterRollbackProcessor = afterRollbackProcessor; + } + /** * Configure the specified Kafka listener container factory. The factory can be * further tuned and default settings can be overridden. @@ -89,6 +124,9 @@ private void configureListenerFactory( map.from(this.replyTemplate).whenNonNull().to(factory::setReplyTemplate); map.from(properties::getType).whenEqualTo(Listener.Type.BATCH) .toCall(() -> factory.setBatchListener(true)); + map.from(this.errorHandler).whenNonNull().to(factory::setErrorHandler); + map.from(this.afterRollbackProcessor).whenNonNull() + .to(factory::setAfterRollbackProcessor); } private void configureContainer(ContainerProperties container) { @@ -109,6 +147,8 @@ private void configureContainer(ContainerProperties container) { .as(Number::intValue).to(container::setMonitorInterval); map.from(properties::getLogContainerConfig).whenNonNull() .to(container::setLogContainerConfig); + map.from(this.transactionManager).whenNonNull() + .to(container::setTransactionManager); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java index 57ee0c9c7ed6..a9b74a0332ed 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java @@ -26,7 +26,10 @@ import org.springframework.kafka.config.KafkaListenerConfigUtils; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.AfterRollbackProcessor; +import org.springframework.kafka.listener.ErrorHandler; import org.springframework.kafka.support.converter.RecordMessageConverter; +import org.springframework.kafka.transaction.KafkaAwareTransactionManager; /** * Configuration for Kafka annotation-driven support. @@ -45,12 +48,24 @@ class KafkaAnnotationDrivenConfiguration { private final KafkaTemplate kafkaTemplate; + private final KafkaAwareTransactionManager transactionManager; + + private final ErrorHandler errorHandler; + + private final AfterRollbackProcessor afterRollbackProcessor; + KafkaAnnotationDrivenConfiguration(KafkaProperties properties, ObjectProvider messageConverter, - ObjectProvider> kafkaTemplate) { + ObjectProvider> kafkaTemplate, + ObjectProvider> kafkaTransactionManager, + ObjectProvider errorHandler, + ObjectProvider> afterRollbackProcessor) { this.properties = properties; this.messageConverter = messageConverter.getIfUnique(); this.kafkaTemplate = kafkaTemplate.getIfUnique(); + this.transactionManager = kafkaTransactionManager.getIfUnique(); + this.errorHandler = errorHandler.getIfUnique(); + this.afterRollbackProcessor = afterRollbackProcessor.getIfUnique(); } @Bean @@ -60,6 +75,9 @@ public ConcurrentKafkaListenerContainerFactoryConfigurer kafkaListenerContainerF configurer.setKafkaProperties(this.properties); configurer.setMessageConverter(this.messageConverter); configurer.setReplyTemplate(this.kafkaTemplate); + configurer.setErrorHandler(this.errorHandler); + configurer.setTransactionManager(this.transactionManager); + configurer.setAfterRollbackProcessor(this.afterRollbackProcessor); return configurer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 816559e88642..8c168af3c65b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -41,6 +41,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.kafka.annotation.EnableKafkaStreams; import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; @@ -50,12 +51,16 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaAdmin; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.listener.AfterRollbackProcessor; import org.springframework.kafka.listener.ContainerProperties.AckMode; +import org.springframework.kafka.listener.SeekToCurrentErrorHandler; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.kafka.support.converter.MessagingMessageConverter; import org.springframework.kafka.support.converter.RecordMessageConverter; import org.springframework.kafka.test.utils.KafkaTestUtils; +import org.springframework.kafka.transaction.ChainedKafkaTransactionManager; import org.springframework.kafka.transaction.KafkaTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; @@ -155,6 +160,10 @@ public void consumerProperties() { assertThat(configs.get("baz")).isEqualTo("qux"); assertThat(configs.get("foo.bar.baz")).isEqualTo("qux.fiz.buz"); assertThat(configs.get("fiz.buz")).isEqualTo("fix.fox"); + ConcurrentKafkaListenerContainerFactory factory = context + .getBean(ConcurrentKafkaListenerContainerFactory.class); + assertThat(KafkaTestUtils.getPropertyValue(factory, "errorHandler")) + .isSameAs(context.getBean("errorHandler")); }); } @@ -485,6 +494,7 @@ public void listenerProperties() { @Test public void testKafkaTemplateRecordMessageConverters() { this.contextRunner.withUserConfiguration(MessageConverterConfiguration.class) + .withPropertyValues("spring.kafka.producer.transaction-id-prefix=test") .run((context) -> { KafkaTemplate kafkaTemplate = context .getBean(KafkaTemplate.class); @@ -496,6 +506,7 @@ public void testKafkaTemplateRecordMessageConverters() { @Test public void testConcurrentKafkaListenerContainerFactoryWithCustomMessageConverters() { this.contextRunner.withUserConfiguration(MessageConverterConfiguration.class) + .withPropertyValues("spring.kafka.producer.transaction-id-prefix=test") .run((context) -> { ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory = context .getBean(ConcurrentKafkaListenerContainerFactory.class); @@ -503,6 +514,11 @@ public void testConcurrentKafkaListenerContainerFactoryWithCustomMessageConverte kafkaListenerContainerFactory); assertThat(dfa.getPropertyValue("messageConverter")) .isSameAs(context.getBean("myMessageConverter")); + assertThat(kafkaListenerContainerFactory.getContainerProperties() + .getTransactionManager()).isSameAs( + context.getBean("chainedTransactionManager")); + assertThat(dfa.getPropertyValue("afterRollbackProcessor")) + .isSameAs(context.getBean("arp")); }); } @@ -521,6 +537,11 @@ public void testConcurrentKafkaListenerContainerFactoryWithKafkaTemplate() { @Configuration protected static class TestConfiguration { + @Bean + public SeekToCurrentErrorHandler errorHandler() { + return new SeekToCurrentErrorHandler(); + } + } @Configuration @@ -531,6 +552,22 @@ public RecordMessageConverter myMessageConverter() { return mock(RecordMessageConverter.class); } + @Bean + @Primary + public PlatformTransactionManager chainedTransactionManager( + KafkaTransactionManager kafkaTransactionManager) { + + return new ChainedKafkaTransactionManager( + kafkaTransactionManager); + } + + @Bean + public AfterRollbackProcessor arp() { + return (records, consumer, ex, recoverable) -> { + // no-op + }; + } + } @Configuration diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8ccaae140733..8868b75aaa4a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -161,7 +161,7 @@ Lovelace-RC2 0.25.0.RELEASE 5.1.0.M2 - 2.2.0.M2 + 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index d871f00702ed..8219e82528eb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5627,8 +5627,19 @@ bean is defined, it is automatically associated to the auto-configured `KafkaTem When the Apache Kafka infrastructure is present, any bean can be annotated with `@KafkaListener` to create a listener endpoint. If no `KafkaListenerContainerFactory` has been defined, a default one is automatically configured with keys defined in -`spring.kafka.listener.*`. Also, if a `RecordMessageConverter` bean is defined, it is -automatically associated to the default factory. +`spring.kafka.listener.*`. +If the property `spring.kafka.producer.transaction-id-prefix` is defined, a +`KafkaTransactionManager` will be auto-configured with name `kafkaTransactionManager` and +will be wired into the container factory. +Also, if `RecordMessageConverter`, `ErrorHandler` and/or +`AfterRollbackProcessor` beans are defined, they are automatically associated to the +default factory. + +IMPORTANT: The auto configuration of these beans occur if there is just a single +instance. +When using a `ChainedKafkaTransactionManager`, it will usually reference the configured +`KafkaTransactionManager` bean, so the chained manager must be marked +`@Primary` if you want it wired into the container factory. The following component creates a listener endpoint on the `someTopic` topic: From b7ae55866e053b8236feb34891580f4076a5612b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 28 Aug 2018 17:10:49 +0200 Subject: [PATCH 472/701] Polish "Improve Kafka Auto-configuration" Closes gh-14215 --- ...fkaListenerContainerFactoryConfigurer.java | 6 +- .../KafkaAnnotationDrivenConfiguration.java | 4 +- .../kafka/KafkaAutoConfigurationTests.java | 174 +++++++++++------- .../main/asciidoc/spring-boot-features.adoc | 22 +-- 4 files changed, 125 insertions(+), 81 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java index c6b382735196..11dcb6329311 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java @@ -78,7 +78,7 @@ void setReplyTemplate(KafkaTemplate replyTemplate) { * Set the {@link KafkaAwareTransactionManager} to use. * @param transactionManager the transaction manager */ - public void setTransactionManager( + void setTransactionManager( KafkaAwareTransactionManager transactionManager) { this.transactionManager = transactionManager; } @@ -87,7 +87,7 @@ public void setTransactionManager( * Set the {@link ErrorHandler} to use. * @param errorHandler the error handler */ - public void setErrorHandler(ErrorHandler errorHandler) { + void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } @@ -95,7 +95,7 @@ public void setErrorHandler(ErrorHandler errorHandler) { * Set the {@link AfterRollbackProcessor} to use. * @param afterRollbackProcessor the after rollback processor */ - public void setAfterRollbackProcessor( + void setAfterRollbackProcessor( AfterRollbackProcessor afterRollbackProcessor) { this.afterRollbackProcessor = afterRollbackProcessor; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java index a9b74a0332ed..e6d4af48bcf4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaAnnotationDrivenConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -75,8 +75,8 @@ public ConcurrentKafkaListenerContainerFactoryConfigurer kafkaListenerContainerF configurer.setKafkaProperties(this.properties); configurer.setMessageConverter(this.messageConverter); configurer.setReplyTemplate(this.kafkaTemplate); - configurer.setErrorHandler(this.errorHandler); configurer.setTransactionManager(this.transactionManager); + configurer.setErrorHandler(this.errorHandler); configurer.setAfterRollbackProcessor(this.afterRollbackProcessor); return configurer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 8c168af3c65b..1a4881334d9a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -59,6 +59,7 @@ import org.springframework.kafka.support.converter.RecordMessageConverter; import org.springframework.kafka.test.utils.KafkaTestUtils; import org.springframework.kafka.transaction.ChainedKafkaTransactionManager; +import org.springframework.kafka.transaction.KafkaAwareTransactionManager; import org.springframework.kafka.transaction.KafkaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; @@ -81,31 +82,29 @@ public class KafkaAutoConfigurationTests { @Test public void consumerProperties() { - this.contextRunner.withUserConfiguration(TestConfiguration.class) - .withPropertyValues("spring.kafka.bootstrap-servers=foo:1234", - "spring.kafka.properties.foo=bar", - "spring.kafka.properties.baz=qux", - "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", - "spring.kafka.ssl.key-password=p1", - "spring.kafka.ssl.key-store-location=classpath:ksLoc", - "spring.kafka.ssl.key-store-password=p2", - "spring.kafka.ssl.key-store-type=PKCS12", - "spring.kafka.ssl.trust-store-location=classpath:tsLoc", - "spring.kafka.ssl.trust-store-password=p3", - "spring.kafka.ssl.trust-store-type=PKCS12", - "spring.kafka.ssl.protocol=TLSv1.2", - "spring.kafka.consumer.auto-commit-interval=123", - "spring.kafka.consumer.max-poll-records=42", - "spring.kafka.consumer.auto-offset-reset=earliest", - "spring.kafka.consumer.client-id=ccid", // test override common - "spring.kafka.consumer.enable-auto-commit=false", - "spring.kafka.consumer.fetch-max-wait=456", - "spring.kafka.consumer.properties.fiz.buz=fix.fox", - "spring.kafka.consumer.fetch-min-size=789", - "spring.kafka.consumer.group-id=bar", - "spring.kafka.consumer.heartbeat-interval=234", - "spring.kafka.consumer.key-deserializer = org.apache.kafka.common.serialization.LongDeserializer", - "spring.kafka.consumer.value-deserializer = org.apache.kafka.common.serialization.IntegerDeserializer") + this.contextRunner.withPropertyValues("spring.kafka.bootstrap-servers=foo:1234", + "spring.kafka.properties.foo=bar", "spring.kafka.properties.baz=qux", + "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", + "spring.kafka.ssl.key-password=p1", + "spring.kafka.ssl.key-store-location=classpath:ksLoc", + "spring.kafka.ssl.key-store-password=p2", + "spring.kafka.ssl.key-store-type=PKCS12", + "spring.kafka.ssl.trust-store-location=classpath:tsLoc", + "spring.kafka.ssl.trust-store-password=p3", + "spring.kafka.ssl.trust-store-type=PKCS12", + "spring.kafka.ssl.protocol=TLSv1.2", + "spring.kafka.consumer.auto-commit-interval=123", + "spring.kafka.consumer.max-poll-records=42", + "spring.kafka.consumer.auto-offset-reset=earliest", + "spring.kafka.consumer.client-id=ccid", // test override common + "spring.kafka.consumer.enable-auto-commit=false", + "spring.kafka.consumer.fetch-max-wait=456", + "spring.kafka.consumer.properties.fiz.buz=fix.fox", + "spring.kafka.consumer.fetch-min-size=789", + "spring.kafka.consumer.group-id=bar", + "spring.kafka.consumer.heartbeat-interval=234", + "spring.kafka.consumer.key-deserializer = org.apache.kafka.common.serialization.LongDeserializer", + "spring.kafka.consumer.value-deserializer = org.apache.kafka.common.serialization.IntegerDeserializer") .run((context) -> { DefaultKafkaConsumerFactory consumerFactory = context .getBean(DefaultKafkaConsumerFactory.class); @@ -160,36 +159,30 @@ public void consumerProperties() { assertThat(configs.get("baz")).isEqualTo("qux"); assertThat(configs.get("foo.bar.baz")).isEqualTo("qux.fiz.buz"); assertThat(configs.get("fiz.buz")).isEqualTo("fix.fox"); - ConcurrentKafkaListenerContainerFactory factory = context - .getBean(ConcurrentKafkaListenerContainerFactory.class); - assertThat(KafkaTestUtils.getPropertyValue(factory, "errorHandler")) - .isSameAs(context.getBean("errorHandler")); }); } @Test public void producerProperties() { - this.contextRunner.withUserConfiguration(TestConfiguration.class) - .withPropertyValues("spring.kafka.clientId=cid", - "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", - "spring.kafka.producer.acks=all", - "spring.kafka.producer.batch-size=20", - "spring.kafka.producer.bootstrap-servers=bar:1234", // test - // override - "spring.kafka.producer.buffer-memory=12345", - "spring.kafka.producer.compression-type=gzip", - "spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.LongSerializer", - "spring.kafka.producer.retries=2", - "spring.kafka.producer.properties.fiz.buz=fix.fox", - "spring.kafka.producer.ssl.key-password=p4", - "spring.kafka.producer.ssl.key-store-location=classpath:ksLocP", - "spring.kafka.producer.ssl.key-store-password=p5", - "spring.kafka.producer.ssl.key-store-type=PKCS12", - "spring.kafka.producer.ssl.trust-store-location=classpath:tsLocP", - "spring.kafka.producer.ssl.trust-store-password=p6", - "spring.kafka.producer.ssl.trust-store-type=PKCS12", - "spring.kafka.producer.ssl.protocol=TLSv1.2", - "spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.IntegerSerializer") + this.contextRunner.withPropertyValues("spring.kafka.clientId=cid", + "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", + "spring.kafka.producer.acks=all", "spring.kafka.producer.batch-size=20", + "spring.kafka.producer.bootstrap-servers=bar:1234", // test + // override + "spring.kafka.producer.buffer-memory=12345", + "spring.kafka.producer.compression-type=gzip", + "spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.LongSerializer", + "spring.kafka.producer.retries=2", + "spring.kafka.producer.properties.fiz.buz=fix.fox", + "spring.kafka.producer.ssl.key-password=p4", + "spring.kafka.producer.ssl.key-store-location=classpath:ksLocP", + "spring.kafka.producer.ssl.key-store-password=p5", + "spring.kafka.producer.ssl.key-store-type=PKCS12", + "spring.kafka.producer.ssl.trust-store-location=classpath:tsLocP", + "spring.kafka.producer.ssl.trust-store-password=p6", + "spring.kafka.producer.ssl.trust-store-type=PKCS12", + "spring.kafka.producer.ssl.protocol=TLSv1.2", + "spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.IntegerSerializer") .run((context) -> { DefaultKafkaProducerFactory producerFactory = context .getBean(DefaultKafkaProducerFactory.class); @@ -414,7 +407,7 @@ public void streamsApplicationIdIsNotMandatoryIfEnableKafkaStreamsIsNotSet() { @SuppressWarnings("unchecked") @Test public void listenerProperties() { - this.contextRunner.withUserConfiguration(TestConfiguration.class) + this.contextRunner .withPropertyValues("spring.kafka.template.default-topic=testTopic", "spring.kafka.listener.ack-mode=MANUAL", "spring.kafka.listener.client-id=client", @@ -506,7 +499,6 @@ public void testKafkaTemplateRecordMessageConverters() { @Test public void testConcurrentKafkaListenerContainerFactoryWithCustomMessageConverters() { this.contextRunner.withUserConfiguration(MessageConverterConfiguration.class) - .withPropertyValues("spring.kafka.producer.transaction-id-prefix=test") .run((context) -> { ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory = context .getBean(ConcurrentKafkaListenerContainerFactory.class); @@ -514,11 +506,56 @@ public void testConcurrentKafkaListenerContainerFactoryWithCustomMessageConverte kafkaListenerContainerFactory); assertThat(dfa.getPropertyValue("messageConverter")) .isSameAs(context.getBean("myMessageConverter")); - assertThat(kafkaListenerContainerFactory.getContainerProperties() - .getTransactionManager()).isSameAs( - context.getBean("chainedTransactionManager")); + }); + } + + @Test + public void testConcurrentKafkaListenerContainerFactoryWithCustomErrorHandler() { + this.contextRunner.withUserConfiguration(ErrorHandlerConfiguration.class) + .run((context) -> { + ConcurrentKafkaListenerContainerFactory factory = context + .getBean(ConcurrentKafkaListenerContainerFactory.class); + assertThat(KafkaTestUtils.getPropertyValue(factory, "errorHandler")) + .isSameAs(context.getBean("errorHandler")); + }); + } + + @Test + public void testConcurrentKafkaListenerContainerFactoryWithDefaultTransactionManager() { + this.contextRunner + .withPropertyValues("spring.kafka.producer.transaction-id-prefix=test") + .run((context) -> { + assertThat(context).hasSingleBean(KafkaAwareTransactionManager.class); + ConcurrentKafkaListenerContainerFactory factory = context + .getBean(ConcurrentKafkaListenerContainerFactory.class); + assertThat(factory.getContainerProperties().getTransactionManager()) + .isSameAs( + context.getBean(KafkaAwareTransactionManager.class)); + }); + } + + @Test + public void testConcurrentKafkaListenerContainerFactoryWithCustomTransactionManager() { + this.contextRunner.withUserConfiguration(TransactionManagerConfiguration.class) + .withPropertyValues("spring.kafka.producer.transaction-id-prefix=test") + .run((context) -> { + ConcurrentKafkaListenerContainerFactory factory = context + .getBean(ConcurrentKafkaListenerContainerFactory.class); + assertThat(factory.getContainerProperties().getTransactionManager()) + .isSameAs(context.getBean("chainedTransactionManager")); + }); + } + + @Test + public void testConcurrentKafkaListenerContainerFactoryWithCustomAfterRollbackProcessor() { + this.contextRunner + .withUserConfiguration(AfterRollbackProcessorConfiguration.class) + .run((context) -> { + ConcurrentKafkaListenerContainerFactory factory = context + .getBean(ConcurrentKafkaListenerContainerFactory.class); + DirectFieldAccessor dfa = new DirectFieldAccessor(factory); assertThat(dfa.getPropertyValue("afterRollbackProcessor")) - .isSameAs(context.getBean("arp")); + .isSameAs(context.getBean("afterRollbackProcessor")); }); } @@ -535,34 +572,43 @@ public void testConcurrentKafkaListenerContainerFactoryWithKafkaTemplate() { } @Configuration - protected static class TestConfiguration { + protected static class MessageConverterConfiguration { @Bean - public SeekToCurrentErrorHandler errorHandler() { - return new SeekToCurrentErrorHandler(); + public RecordMessageConverter myMessageConverter() { + return mock(RecordMessageConverter.class); } } @Configuration - protected static class MessageConverterConfiguration { + protected static class ErrorHandlerConfiguration { @Bean - public RecordMessageConverter myMessageConverter() { - return mock(RecordMessageConverter.class); + public SeekToCurrentErrorHandler errorHandler() { + return new SeekToCurrentErrorHandler(); } + } + + @Configuration + protected static class TransactionManagerConfiguration { + @Bean @Primary public PlatformTransactionManager chainedTransactionManager( KafkaTransactionManager kafkaTransactionManager) { - return new ChainedKafkaTransactionManager( kafkaTransactionManager); } + } + + @Configuration + protected static class AfterRollbackProcessorConfiguration { + @Bean - public AfterRollbackProcessor arp() { + public AfterRollbackProcessor afterRollbackProcessor() { return (records, consumer, ex, recoverable) -> { // no-op }; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 8219e82528eb..5d945496dddf 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5628,18 +5628,6 @@ When the Apache Kafka infrastructure is present, any bean can be annotated with `@KafkaListener` to create a listener endpoint. If no `KafkaListenerContainerFactory` has been defined, a default one is automatically configured with keys defined in `spring.kafka.listener.*`. -If the property `spring.kafka.producer.transaction-id-prefix` is defined, a -`KafkaTransactionManager` will be auto-configured with name `kafkaTransactionManager` and -will be wired into the container factory. -Also, if `RecordMessageConverter`, `ErrorHandler` and/or -`AfterRollbackProcessor` beans are defined, they are automatically associated to the -default factory. - -IMPORTANT: The auto configuration of these beans occur if there is just a single -instance. -When using a `ChainedKafkaTransactionManager`, it will usually reference the configured -`KafkaTransactionManager` bean, so the chained manager must be marked -`@Primary` if you want it wired into the container factory. The following component creates a listener endpoint on the `someTopic` topic: @@ -5656,6 +5644,16 @@ The following component creates a listener endpoint on the `someTopic` topic: } ---- +If a `KafkaTransactionManager` bean is defined, it is automatically associated to the +container factory. Similarly, if a `RecordMessageConverter`, `ErrorHandler` or +`AfterRollbackProcessor` bean is defined, it is automatically associated to the default +factory. + +TIP: A custom `ChainedKafkaTransactionManager` must be marked `@Primary` as it usually +reference the auto-configured `KafkaTransactionManager` bean. + + + [[boot-features-kafka-streams]] ==== Kafka Streams Spring for Apache Kafka provides a factory bean to create a `StreamsBuilder` object and From f5deebf0cb2fb802bafb5ff85652ebe89e9da98d Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 22 Aug 2018 14:04:10 -0700 Subject: [PATCH 473/701] Support authorization_code grant for OAuth2 client This commit also refactors OAuth2 client properties. With the added support for authorization_code clients, client registrations are now divided into `login` and `authorization_code`. An environment post processor is used for backward compatibility with old Open ID Connect login clients. Closes gh-13812 --- .../client/ClientsConfiguredCondition.java | 34 +++- .../oauth2/client/OAuth2ClientProperties.java | 99 ++++++++--- ...entPropertiesEnvironmentPostProcessor.java | 115 +++++++++++++ ...h2ClientPropertiesRegistrationAdapter.java | 37 +++- .../OAuth2WebSecurityConfiguration.java | 3 +- ...itional-spring-configuration-metadata.json | 9 + .../main/resources/META-INF/spring.factories | 4 + ...opertiesEnvironmentPostProcessorTests.java | 158 ++++++++++++++++++ ...entPropertiesRegistrationAdapterTests.java | 147 ++++++++++------ .../client/OAuth2ClientPropertiesTests.java | 33 +++- ...iveOAuth2ClientAutoConfigurationTests.java | 2 +- ...istrationRepositoryConfigurationTests.java | 2 +- ...istrationRepositoryConfigurationTests.java | 2 +- .../OAuth2WebSecurityConfigurationTests.java | 52 ++++-- .../main/asciidoc/spring-boot-features.adoc | 129 +++++++++----- .../src/main/resources/application.yml | 43 +++-- .../SampleOAuth2ClientApplicationTests.java | 10 +- .../src/main/resources/application.yml | 35 ++-- 18 files changed, 723 insertions(+), 191 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessorTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java index 295abeda5f63..fac1ca580d1e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.security.oauth2.client; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; @@ -37,29 +38,44 @@ */ public class ClientsConfiguredCondition extends SpringBootCondition { - private static final Bindable> STRING_REGISTRATION_MAP = Bindable - .mapOf(String.class, OAuth2ClientProperties.Registration.class); + private static final Bindable> STRING_LOGIN_REGISTRATION_MAP = Bindable + .mapOf(String.class, OAuth2ClientProperties.LoginClientRegistration.class); + + private static final Bindable> STRING_AUTHORIZATIONCODE_REGISTRATION_MAP = Bindable + .mapOf(String.class, + OAuth2ClientProperties.AuthorizationCodeClientRegistration.class); @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage .forCondition("OAuth2 Clients Configured Condition"); - Map registrations = getRegistrations( + Map registrations = getRegistrations( context.getEnvironment()); if (!registrations.isEmpty()) { - return ConditionOutcome.match(message - .foundExactly("registered clients " + registrations.values().stream() - .map(OAuth2ClientProperties.Registration::getClientId) + return ConditionOutcome.match(message.foundExactly( + "registered clients " + registrations.values().stream().map( + OAuth2ClientProperties.BaseClientRegistration::getClientId) .collect(Collectors.joining(", ")))); } return ConditionOutcome.noMatch(message.notAvailable("registered clients")); } - private Map getRegistrations( + private Map getRegistrations( Environment environment) { - return Binder.get(environment).bind("spring.security.oauth2.client.registration", - STRING_REGISTRATION_MAP).orElse(Collections.emptyMap()); + Map registrations = new HashMap(); + Map loginClientRegistrations = Binder + .get(environment).bind("spring.security.oauth2.client.registration.login", + STRING_LOGIN_REGISTRATION_MAP) + .orElse(Collections.emptyMap()); + Map authCodeClientRegistrations = Binder + .get(environment) + .bind("spring.security.oauth2.client.registration.authorizationcode", + STRING_AUTHORIZATIONCODE_REGISTRATION_MAP) + .orElse(Collections.emptyMap()); + registrations.putAll(loginClientRegistrations); + registrations.putAll(authCodeClientRegistrations); + return registrations; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index 42f98ae73cbf..3c83728e4597 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -44,31 +44,105 @@ public class OAuth2ClientProperties { /** * OAuth client registrations. */ - private final Map registration = new HashMap<>(); + private final Registration registration = new Registration(); public Map getProvider() { return this.provider; } - public Map getRegistration() { + public Registration getRegistration() { return this.registration; } @PostConstruct public void validate() { - this.getRegistration().values().forEach(this::validateRegistration); + this.getRegistration().getLogin().values().forEach(this::validateRegistration); + this.getRegistration().getAuthorizationCode().values() + .forEach(this::validateRegistration); } - private void validateRegistration(Registration registration) { + private void validateRegistration(BaseClientRegistration registration) { if (!StringUtils.hasText(registration.getClientId())) { throw new IllegalStateException("Client id must not be empty."); } } + public static class Registration { + + /** + * OpenID Connect client registrations. + */ + private Map login = new HashMap<>(); + + /** + * OAuth2 authorization_code client registrations. + */ + private Map authorizationCode = new HashMap<>(); + + public Map getLogin() { + return this.login; + } + + public void setLogin(Map login) { + this.login = login; + } + + public Map getAuthorizationCode() { + return this.authorizationCode; + } + + public void setAuthorizationCode( + Map authorizationCode) { + this.authorizationCode = authorizationCode; + } + + } + /** - * A single client registration. + * A single client registration for OpenID Connect login. */ - public static class Registration { + public static class LoginClientRegistration extends BaseClientRegistration { + + /** + * Redirect URI. May be left blank when using a pre-defined provider. + */ + private String redirectUriTemplate; + + public String getRedirectUriTemplate() { + return this.redirectUriTemplate; + } + + public void setRedirectUriTemplate(String redirectUriTemplate) { + this.redirectUriTemplate = redirectUriTemplate; + } + + } + + /** + * A single client registration for OAuth2 authorization_code flow. + */ + public static class AuthorizationCodeClientRegistration + extends BaseClientRegistration { + + /** + * Redirect URI for the registration. + */ + private String redirectUri; + + public String getRedirectUri() { + return this.redirectUri; + } + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + + } + + /** + * Base class for a single client registration. + */ + public static class BaseClientRegistration { /** * Reference to the OAuth 2.0 provider to use. May reference an element from the @@ -98,11 +172,6 @@ public static class Registration { */ private String authorizationGrantType; - /** - * Redirect URI. May be left blank when using a pre-defined provider. - */ - private String redirectUriTemplate; - /** * Authorization scopes. May be left blank when using a pre-defined provider. */ @@ -153,14 +222,6 @@ public void setAuthorizationGrantType(String authorizationGrantType) { this.authorizationGrantType = authorizationGrantType; } - public String getRedirectUriTemplate() { - return this.redirectUriTemplate; - } - - public void setRedirectUriTemplate(String redirectUriTemplate) { - this.redirectUriTemplate = redirectUriTemplate; - } - public Set getScope() { return this.scope; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java new file mode 100644 index 000000000000..05a1a5ce71c0 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java @@ -0,0 +1,115 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.context.config.ConfigFileApplicationListener; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +/** + * {@link EnvironmentPostProcessor} that migrates legacy OAuth2 login client properties + * under the `spring.security.oauth2.client.login` prefix. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +public class OAuth2ClientPropertiesEnvironmentPostProcessor + implements EnvironmentPostProcessor, Ordered { + + private static final Bindable> STRING_LEGACY_REGISTRATION_MAP = Bindable + .mapOf(String.class, OAuth2ClientProperties.LoginClientRegistration.class); + + private static final String PREFIX = "spring.security.oauth2.client.registration"; + + private static final String LOGIN_REGISTRATION_PREFIX = PREFIX + ".login."; + + private static final String UPDATED_PROPERTY_SOURCE_SUFFIX = "-updated-oauth-client"; + + private int order = ConfigFileApplicationListener.DEFAULT_ORDER + 1; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, + SpringApplication application) { + environment.getPropertySources().forEach((propertySource) -> { + String name = propertySource.getName(); + Iterable sources = ConfigurationPropertySources + .from(propertySource); + ConfigurationPropertySource source = sources.iterator().next(); + Binder binder = new Binder(sources); + Map map = new LinkedHashMap<>(); + MapPropertySource updatedPropertySource = new MapPropertySource( + name + UPDATED_PROPERTY_SOURCE_SUFFIX, map); + Map registrations = binder + .bind(PREFIX, STRING_LEGACY_REGISTRATION_MAP) + .orElse(Collections.emptyMap()); + registrations.entrySet() + .forEach((entry) -> addProperties(entry, source, map)); + if (!map.isEmpty()) { + environment.getPropertySources().addBefore(name, updatedPropertySource); + } + }); + } + + private void addProperties( + Map.Entry entry, + ConfigurationPropertySource source, Map map) { + OAuth2ClientProperties.LoginClientRegistration registration = entry.getValue(); + String registrationId = entry.getKey(); + addProperty(registrationId, "client-id", registration::getClientId, map, source); + addProperty(registrationId, "client-secret", registration::getClientSecret, map, + source); + addProperty(registrationId, "client-name", registration::getClientName, map, + source); + addProperty(registrationId, "redirect-uri-template", + registration::getRedirectUriTemplate, map, source); + addProperty(registrationId, "authorization-grant-type", + registration::getAuthorizationGrantType, map, source); + addProperty(registrationId, "client-authentication-method", + registration::getClientAuthenticationMethod, map, source); + addProperty(registrationId, "provider", registration::getProvider, map, source); + addProperty(registrationId, "scope", registration::getScope, map, source); + } + + private void addProperty(String registrationId, String property, + Supplier valueSupplier, Map map, + ConfigurationPropertySource source) { + String registrationKey = PREFIX + "." + registrationId + "."; + String loginRegistrationKey = LOGIN_REGISTRATION_PREFIX + registrationId + "."; + if (source.getConfigurationProperty( + ConfigurationPropertyName.of(registrationKey + property)) != null) { + map.put(loginRegistrationKey + property, valueSupplier.get()); + } + } + + @Override + public int getOrder() { + return this.order; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index d1ce147a3fc9..59b433b215bd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -20,7 +20,6 @@ import java.util.Map; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.core.convert.ConversionException; @@ -51,19 +50,35 @@ private OAuth2ClientPropertiesRegistrationAdapter() { public static Map getClientRegistrations( OAuth2ClientProperties properties) { Map clientRegistrations = new HashMap<>(); - properties.getRegistration().forEach((key, value) -> clientRegistrations.put(key, - getClientRegistration(key, value, properties.getProvider()))); + properties.getRegistration().getLogin() + .forEach((key, value) -> clientRegistrations.put(key, + getLoginClientRegistration(key, value, + properties.getProvider()))); + properties.getRegistration().getAuthorizationCode() + .forEach((key, value) -> clientRegistrations.put(key, + getAuthorizationCodeClientRegistration(key, value, + properties.getProvider()))); return clientRegistrations; } - private static ClientRegistration getClientRegistration(String registrationId, - Registration properties, Map providers) { + private static ClientRegistration getAuthorizationCodeClientRegistration( + String registrationId, + OAuth2ClientProperties.AuthorizationCodeClientRegistration properties, + Map providers) { + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + Builder builder = getBuilder(map, registrationId, properties, providers); + map.from(properties::getRedirectUri).to(builder::redirectUriTemplate); + return builder.build(); + } + + private static Builder getBuilder(PropertyMapper map, String registrationId, + OAuth2ClientProperties.BaseClientRegistration properties, + Map providers) { Builder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers); if (builder == null) { builder = getBuilder(registrationId, properties.getProvider(), providers); } - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(properties::getClientId).to(builder::clientId); map.from(properties::getClientSecret).to(builder::clientSecret); map.from(properties::getClientAuthenticationMethod) @@ -71,10 +86,18 @@ private static ClientRegistration getClientRegistration(String registrationId, .to(builder::clientAuthenticationMethod); map.from(properties::getAuthorizationGrantType).as(AuthorizationGrantType::new) .to(builder::authorizationGrantType); - map.from(properties::getRedirectUriTemplate).to(builder::redirectUriTemplate); map.from(properties::getScope).as((scope) -> StringUtils.toStringArray(scope)) .to(builder::scope); map.from(properties::getClientName).to(builder::clientName); + return builder; + } + + private static ClientRegistration getLoginClientRegistration(String registrationId, + OAuth2ClientProperties.LoginClientRegistration properties, + Map providers) { + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + Builder builder = getBuilder(map, registrationId, properties, providers); + map.from(properties::getRedirectUriTemplate).to(builder::redirectUriTemplate); return builder.build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index ffd1f484b7a9..caf65cae9e33 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -60,7 +60,8 @@ static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAda @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().authenticated().and().oauth2Login(); + http.authorizeRequests().anyRequest().authenticated().and().oauth2Login() + .and().oauth2Client().authorizationCodeGrant(); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5a45e710ae0c..85dc74583d18 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -546,6 +546,15 @@ "name": "spring.session.hazelcast.flush-mode", "defaultValue": "on-save" }, + { + "name" : "spring.security.oauth2.client.registration", + "type" : "java.util.Map", + "description" : "Maps client registration-id to a client registration.", + "deprecation" : { + "replacement" : "spring.security.oauth2.client.registration.login", + "level" : "warning" + } + }, { "name": "spring.session.servlet.filter-dispatcher-types", "defaultValue": [ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 1070f995bd4c..4cc1a3bf9fd6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -7,6 +7,10 @@ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingL org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer +# Environment Post Processors +org.springframework.boot.env.EnvironmentPostProcessor=\ +org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesEnvironmentPostProcessor + # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessorTests.java new file mode 100644 index 000000000000..620d35ef3827 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessorTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2012-2018 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.autoconfigure.security.oauth2.client; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.env.SystemEnvironmentPropertySource; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OAuth2ClientPropertiesEnvironmentPostProcessor}. + * + * @author Madhura Bhave + */ +public class OAuth2ClientPropertiesEnvironmentPostProcessorTests { + + private OAuth2ClientPropertiesEnvironmentPostProcessor postProcessor = new OAuth2ClientPropertiesEnvironmentPostProcessor(); + + private MockEnvironment environment; + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.github-client."; + + private static final String ENVIRONMENT_REGISTRATION_PREFIX = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB-CLIENT_"; + + private static final String LOGIN_REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login.github-client."; + + @Before + public void setup() { + this.environment = new MockEnvironment(); + } + + @Test + public void postProcessorWhenLegacyPropertiesShouldConvert() { + Map properties = new HashMap<>(); + properties.put(REGISTRATION_PREFIX + "client-id", "my-client-id"); + properties.put(REGISTRATION_PREFIX + "client-secret", "my-client-secret"); + properties.put(REGISTRATION_PREFIX + "redirect-uri-template", + "http://my-redirect-uri.com"); + properties.put(REGISTRATION_PREFIX + "provider", "github"); + properties.put(REGISTRATION_PREFIX + "scope", "user"); + properties.put(REGISTRATION_PREFIX + "client-name", "my-client-name"); + properties.put(REGISTRATION_PREFIX + "authorization-grant-type", + "authorization_code"); + properties.put(REGISTRATION_PREFIX + "client-authentication-method", "FORM"); + MapPropertySource source = new MapPropertySource("test", properties); + this.environment.getPropertySources().addFirst(source); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertPropertyMigration(); + } + + @Test + public void postProcessorDoesNotCopyMissingProperties() { + Map properties = new HashMap<>(); + properties.put(REGISTRATION_PREFIX + "client-id", "my-client-id"); + MapPropertySource source = new MapPropertySource("test", properties); + this.environment.getPropertySources().addFirst(source); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "client-id")) + .isEqualTo("my-client-id"); + assertThat( + this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "client-secret")) + .isNull(); + } + + @Test + public void postProcessorWhenLegacyEnvironmentVariablesPropertiesShouldConvert() { + Map properties = new HashMap<>(); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "CLIENTID", "my-client-id"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "CLIENTSECRET", + "my-client-secret"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "REDIRECTURITEMPLATE", + "http://my-redirect-uri.com"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "PROVIDER", "github"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "SCOPE", "user"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "CLIENTNAME", "my-client-name"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "AUTHORIZATIONGRANTTYPE", + "authorization_code"); + properties.put(ENVIRONMENT_REGISTRATION_PREFIX + "CLIENTAUTHENTICATIONMETHOD", + "FORM"); + SystemEnvironmentPropertySource source = new SystemEnvironmentPropertySource( + "test-" + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, + properties); + this.environment.getPropertySources().addFirst(source); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertPropertyMigration(); + } + + @Test + public void postProcessorWhenNewPropertiesShouldDoNothing() { + Map properties = new HashMap<>(); + properties.put(LOGIN_REGISTRATION_PREFIX + "client-id", "my-client-id"); + properties.put(LOGIN_REGISTRATION_PREFIX + "client-secret", "my-client-secret"); + properties.put(LOGIN_REGISTRATION_PREFIX + "redirect-uri-template", + "http://my-redirect-uri.com"); + properties.put(LOGIN_REGISTRATION_PREFIX + "provider", "github"); + properties.put(LOGIN_REGISTRATION_PREFIX + "scope", "user"); + properties.put(LOGIN_REGISTRATION_PREFIX + "client-name", "my-client-name"); + properties.put(LOGIN_REGISTRATION_PREFIX + "authorization-grant-type", + "authorization_code"); + properties.put(LOGIN_REGISTRATION_PREFIX + "client-authentication-method", + "FORM"); + MapPropertySource source = new MapPropertySource("test", properties); + this.environment.getPropertySources().addFirst(source); + MutablePropertySources propertySources = new MutablePropertySources( + this.environment.getPropertySources()); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertPropertyMigration(); + assertThat(this.environment.getPropertySources()) + .containsExactlyElementsOf(propertySources); + } + + private void assertPropertyMigration() { + assertThat(this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "client-id")) + .isEqualTo("my-client-id"); + assertThat( + this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "client-secret")) + .isEqualTo("my-client-secret"); + assertThat(this.environment + .getProperty(LOGIN_REGISTRATION_PREFIX + "redirect-uri-template")) + .isEqualTo("http://my-redirect-uri.com"); + assertThat(this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "provider")) + .isEqualTo("github"); + assertThat(this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "scope")) + .isEqualTo("user"); + assertThat( + this.environment.getProperty(LOGIN_REGISTRATION_PREFIX + "client-name")) + .isEqualTo("my-client-name"); + assertThat(this.environment + .getProperty(LOGIN_REGISTRATION_PREFIX + "authorization-grant-type")) + .isEqualTo("authorization_code"); + assertThat(this.environment + .getProperty(LOGIN_REGISTRATION_PREFIX + "client-authentication-method")) + .isEqualTo("FORM"); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 8e16a767fdc5..4e6b1cfac807 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -28,8 +28,8 @@ import org.junit.rules.ExpectedException; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.LoginClientRegistration; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -72,17 +72,17 @@ public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() { provider.setUserInfoAuthenticationMethod("form"); provider.setUserNameAttribute("sub"); provider.setJwkSetUri("http://example.com/jwk"); - Registration registration = new Registration(); - registration.setProvider("provider"); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - registration.setClientAuthenticationMethod("post"); - registration.setAuthorizationGrantType("authorization_code"); - registration.setRedirectUriTemplate("http://example.com/redirect"); - registration.setScope(Collections.singleton("scope")); - registration.setClientName("clientName"); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setProvider("provider"); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + login.setClientAuthenticationMethod("post"); + login.setAuthorizationGrantType("authorization_code"); + login.setRedirectUriTemplate("http://example.com/redirect"); + login.setScope(Collections.singleton("scope")); + login.setClientName("clientName"); + properties.getRegistration().getLogin().put("registration", login); properties.getProvider().put("provider", provider); - properties.getRegistration().put("registration", registration); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("registration"); @@ -114,11 +114,11 @@ public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() { @Test public void getClientRegistrationsWhenUsingCommonProviderShouldAdapt() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Registration registration = new Registration(); - registration.setProvider("google"); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - properties.getRegistration().put("registration", registration); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setProvider("google"); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + properties.getRegistration().getLogin().put("registration", login); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("registration"); @@ -149,16 +149,16 @@ public void getClientRegistrationsWhenUsingCommonProviderShouldAdapt() { @Test public void getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Registration registration = new Registration(); - registration.setProvider("google"); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - registration.setClientAuthenticationMethod("post"); - registration.setAuthorizationGrantType("authorization_code"); - registration.setRedirectUriTemplate("http://example.com/redirect"); - registration.setScope(Collections.singleton("scope")); - registration.setClientName("clientName"); - properties.getRegistration().put("registration", registration); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setProvider("google"); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + login.setClientAuthenticationMethod("post"); + login.setAuthorizationGrantType("authorization_code"); + login.setRedirectUriTemplate("http://example.com/redirect"); + login.setScope(Collections.singleton("scope")); + login.setClientName("clientName"); + properties.getRegistration().getLogin().put("registration", login); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("registration"); @@ -192,9 +192,9 @@ public void getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt @Test public void getClientRegistrationsWhenUnknownProviderShouldThrowException() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Registration registration = new Registration(); - registration.setProvider("missing"); - properties.getRegistration().put("registration", registration); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setProvider("missing"); + properties.getRegistration().getLogin().put("registration", login); this.thrown.expect(IllegalStateException.class); this.thrown.expectMessage("Unknown provider ID 'missing'"); OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties); @@ -203,10 +203,10 @@ public void getClientRegistrationsWhenUnknownProviderShouldThrowException() { @Test public void getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationId() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Registration registration = new Registration(); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - properties.getRegistration().put("google", registration); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + properties.getRegistration().getLogin().put("google", login); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("google"); @@ -235,11 +235,47 @@ public void getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationI assertThat(adapted.getClientName()).isEqualTo("Google"); } + @Test + public void getClientRegistrationsWhenAuhtorizationCodeClientShouldAdapt() { + OAuth2ClientProperties properties = new OAuth2ClientProperties(); + OAuth2ClientProperties.AuthorizationCodeClientRegistration registration = new OAuth2ClientProperties.AuthorizationCodeClientRegistration(); + registration.setClientId("clientId"); + registration.setClientSecret("clientSecret"); + registration.setRedirectUri("http://my-redirect-uri.com"); + properties.getRegistration().getAuthorizationCode().put("google", registration); + Map registrations = OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(properties); + ClientRegistration adapted = registrations.get("google"); + ProviderDetails adaptedProvider = adapted.getProviderDetails(); + assertThat(adaptedProvider.getAuthorizationUri()) + .isEqualTo("https://accounts.google.com/o/oauth2/v2/auth"); + assertThat(adaptedProvider.getTokenUri()) + .isEqualTo("https://www.googleapis.com/oauth2/v4/token"); + assertThat(adaptedProvider.getUserInfoEndpoint().getUri()) + .isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo"); + assertThat(adaptedProvider.getUserInfoEndpoint().getAuthenticationMethod()) + .isEqualTo( + org.springframework.security.oauth2.core.AuthenticationMethod.HEADER); + assertThat(adaptedProvider.getJwkSetUri()) + .isEqualTo("https://www.googleapis.com/oauth2/v3/certs"); + assertThat(adapted.getRegistrationId()).isEqualTo("google"); + assertThat(adapted.getClientId()).isEqualTo("clientId"); + assertThat(adapted.getClientSecret()).isEqualTo("clientSecret"); + assertThat(adapted.getRedirectUriTemplate()) + .isEqualTo("http://my-redirect-uri.com"); + assertThat(adapted.getClientAuthenticationMethod()).isEqualTo( + org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC); + assertThat(adapted.getAuthorizationGrantType()).isEqualTo( + org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE); + assertThat(adapted.getScopes()).containsExactly("openid", "profile", "email"); + assertThat(adapted.getClientName()).isEqualTo("Google"); + } + @Test public void getClientRegistrationsWhenProviderNotSpecifiedAndUnknownProviderShouldThrowException() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); - Registration registration = new Registration(); - properties.getRegistration().put("missing", registration); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + properties.getRegistration().getLogin().put("missing", login); this.thrown.expect(IllegalStateException.class); this.thrown.expectMessage( "Provider ID must be specified for client registration 'missing'"); @@ -249,20 +285,20 @@ public void getClientRegistrationsWhenProviderNotSpecifiedAndUnknownProviderShou @Test public void oidcProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception { - Registration registration = new Registration(); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - testOidcConfiguration(registration, "okta"); + LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + testOidcConfiguration(login, "okta"); } @Test public void oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception { - Registration registration = new Registration(); - registration.setProvider("okta-oidc"); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - testOidcConfiguration(registration, "okta-oidc"); + OAuth2ClientProperties.LoginClientRegistration login = new LoginClientRegistration(); + login.setProvider("okta-oidc"); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + testOidcConfiguration(login, "okta-oidc"); } @Test @@ -273,13 +309,13 @@ public void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDef String issuer = this.server.url("").toString(); String cleanIssuerPath = cleanIssuerPath(issuer); setupMockResponse(cleanIssuerPath); - Registration registration = new Registration(); - registration.setProvider("okta-oidc"); - registration.setClientId("clientId"); - registration.setClientSecret("clientSecret"); - registration.setClientAuthenticationMethod("post"); - registration.setRedirectUriTemplate("http://example.com/redirect"); - registration.setScope(Collections.singleton("user")); + OAuth2ClientProperties.LoginClientRegistration login = new OAuth2ClientProperties.LoginClientRegistration(); + login.setProvider("okta-oidc"); + login.setClientId("clientId"); + login.setClientSecret("clientSecret"); + login.setClientAuthenticationMethod("post"); + login.setRedirectUriTemplate("http://example.com/redirect"); + login.setScope(Collections.singleton("user")); Provider provider = new Provider(); provider.setIssuerUri(issuer); provider.setAuthorizationUri("http://example.com/auth"); @@ -289,7 +325,7 @@ public void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDef provider.setJwkSetUri("http://example.com/jwk"); OAuth2ClientProperties properties = new OAuth2ClientProperties(); properties.getProvider().put("okta-oidc", provider); - properties.getRegistration().put("okta", registration); + properties.getRegistration().getLogin().put("okta", login); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("okta"); @@ -313,8 +349,9 @@ public void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDef .isEqualTo("sub"); } - private void testOidcConfiguration(Registration registration, String providerId) - throws Exception { + private void testOidcConfiguration( + OAuth2ClientProperties.LoginClientRegistration registration, + String providerId) throws Exception { this.server = new MockWebServer(); this.server.start(); String issuer = this.server.url("").toString(); @@ -324,7 +361,7 @@ private void testOidcConfiguration(Registration registration, String providerId) Provider provider = new Provider(); provider.setIssuerUri(issuer); properties.getProvider().put(providerId, provider); - properties.getRegistration().put("okta", registration); + properties.getRegistration().getLogin().put("okta", registration); Map registrations = OAuth2ClientPropertiesRegistrationAdapter .getClientRegistrations(properties); ClientRegistration adapted = registrations.get("okta"); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java index 75960d497f14..0b8f9cbe2710 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java @@ -20,6 +20,9 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.AuthorizationCodeClientRegistration; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.LoginClientRegistration; + /** * Tests for {@link OAuth2ClientProperties}. * @@ -34,11 +37,11 @@ public class OAuth2ClientPropertiesTests { public ExpectedException thrown = ExpectedException.none(); @Test - public void clientIdAbsentThrowsException() { - OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration(); + public void clientIdAbsentForLoginClientsThrowsException() { + LoginClientRegistration registration = new LoginClientRegistration(); registration.setClientSecret("secret"); registration.setProvider("google"); - this.properties.getRegistration().put("foo", registration); + this.properties.getRegistration().getLogin().put("foo", registration); this.thrown.expect(IllegalStateException.class); this.thrown.expectMessage("Client id must not be empty."); this.properties.validate(); @@ -46,10 +49,30 @@ public void clientIdAbsentThrowsException() { @Test public void clientSecretAbsentShouldNotThrowException() { - OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration(); + LoginClientRegistration registration = new LoginClientRegistration(); + registration.setClientId("foo"); + registration.setProvider("google"); + this.properties.getRegistration().getLogin().put("foo", registration); + this.properties.validate(); + } + + @Test + public void clientIdAbsentForAuthorizationCodeClientsThrowsException() { + AuthorizationCodeClientRegistration registration = new AuthorizationCodeClientRegistration(); + registration.setClientSecret("secret"); + registration.setProvider("google"); + this.properties.getRegistration().getAuthorizationCode().put("foo", registration); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("Client id must not be empty."); + this.properties.validate(); + } + + @Test + public void clientSecretAbsentForAuthorizationCodeClientDoesNotThrowException() { + AuthorizationCodeClientRegistration registration = new AuthorizationCodeClientRegistration(); registration.setClientId("foo"); registration.setProvider("google"); - this.properties.getRegistration().put("foo", registration); + this.properties.getRegistration().getAuthorizationCode().put("foo", registration); this.properties.validate(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java index 99c69ba4c9ed..f6c391317df9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -37,7 +37,7 @@ public class ReactiveOAuth2ClientAutoConfigurationTests { .withConfiguration( AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class)); - private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; @Test public void autoConfigurationShouldImportConfigurations() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java index 4ca71fc738f2..749d7b3b9dd7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -33,7 +33,7 @@ public class ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); - private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; @Test public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java index dcea65025c52..74dfe19e144a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -33,7 +33,7 @@ public class OAuth2ClientRegistrationRepositoryConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); - private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; @Test public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index 4c5fd746cbae..7e8466d9086a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -39,7 +39,7 @@ import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter; import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; import org.springframework.security.oauth2.core.AuthorizationGrantType; @@ -68,7 +68,9 @@ public void securityConfigurerConfiguresOAuth2Login() { ClientRegistrationRepository expected = context .getBean(ClientRegistrationRepository.class); ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils - .getField(getAuthCodeFilters(context).get(0), + .getField( + getFilters(context, + OAuth2LoginAuthenticationFilter.class).get(0), "clientRegistrationRepository"); assertThat(isEqual(expected.findByRegistrationId("first"), actual.findByRegistrationId("first"))).isTrue(); @@ -78,11 +80,34 @@ public void securityConfigurerConfiguresOAuth2Login() { } @Test - public void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() { + public void securityConfigurerConfiguresAuthorizationCode() { this.contextRunner - .withUserConfiguration(TestConfig.class, + .withUserConfiguration(ClientRegistrationRepositoryConfiguration.class, OAuth2WebSecurityConfiguration.class) - .run((context) -> assertThat(getAuthCodeFilters(context)).isEmpty()); + .run((context) -> { + ClientRegistrationRepository expected = context + .getBean(ClientRegistrationRepository.class); + ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils + .getField(getFilters(context, + OAuth2AuthorizationCodeGrantFilter.class).get(0), + "clientRegistrationRepository"); + assertThat(isEqual(expected.findByRegistrationId("first"), + actual.findByRegistrationId("first"))).isTrue(); + assertThat(isEqual(expected.findByRegistrationId("second"), + actual.findByRegistrationId("second"))).isTrue(); + }); + } + + @Test + public void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() { + this.contextRunner.withUserConfiguration(TestConfig.class, + OAuth2WebSecurityConfiguration.class).run((context) -> { + assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)) + .isEmpty(); + assertThat( + getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)) + .isEmpty(); + }); } @Test @@ -107,7 +132,11 @@ public void configurationRegistersAuthorizedClientRepositoryBean() { public void securityConfigurerBacksOffWhenOtherWebSecurityAdapterPresent() { this.contextRunner.withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class).run((context) -> { - assertThat(getAuthCodeFilters(context)).isEmpty(); + assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)) + .isEmpty(); + assertThat( + getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)) + .isEmpty(); assertThat(context).getBean(OAuth2AuthorizedClientService.class) .isNotNull(); }); @@ -137,19 +166,14 @@ public void authorizedClientRepositoryBeanIsConditionalOnMissingBean() { } @SuppressWarnings("unchecked") - private List getAuthCodeFilters(AssertableApplicationContext context) { + private List getFilters(AssertableApplicationContext context, + Class filter) { FilterChainProxy filterChain = (FilterChainProxy) context .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN); List filterChains = filterChain.getFilterChains(); List filters = (List) ReflectionTestUtils .getField(filterChains.get(0), "filters"); - List oauth2Filters = filters.stream() - .filter((f) -> f instanceof OAuth2LoginAuthenticationFilter - || f instanceof OAuth2AuthorizationRequestRedirectFilter) - .collect(Collectors.toList()); - return oauth2Filters.stream() - .filter((f) -> f instanceof OAuth2LoginAuthenticationFilter) - .collect(Collectors.toList()); + return filters.stream().filter(filter::isInstance).collect(Collectors.toList()); } private boolean isEqual(ClientRegistration reg1, ClientRegistration reg2) { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5d945496dddf..75c05c006d33 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3219,36 +3219,18 @@ https://oauth.net/2/[OAuth2] is a widely used authorization framework that is su Spring. + [[boot-features-security-oauth2-client]] ==== Client If you have `spring-security-oauth2-client` on your classpath, you can take advantage of -some auto-configuration to make it easy to set up an OAuth2 Client. This configuration -makes use of the properties under `OAuth2ClientProperties`. The same properties are applicable -for both servlet and reactive applications. +some auto-configuration to make it easy to set up an OAuth2/Open ID Connect clients. This configuration +makes use of the properties under `OAuth2ClientProperties`. -You can register multiple OAuth2 clients and providers under the -`spring.security.oauth2.client` prefix, as shown in the following example: +You can register multiple OAuth2/OpenID Connect providers under the `spring.security.oauth2.client.provider` +prefix, as shown in the following example: [source,properties,indent=0] ---- - spring.security.oauth2.client.registration.my-client-1.client-id=abcd - spring.security.oauth2.client.registration.my-client-1.client-secret=password - spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope - spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider - spring.security.oauth2.client.registration.my-client-1.scope=user - spring.security.oauth2.client.registration.my-client-1.redirect-uri-template=http://my-redirect-uri.com - spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic - spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code - - spring.security.oauth2.client.registration.my-client-2.client-id=abcd - spring.security.oauth2.client.registration.my-client-2.client-secret=password - spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope - spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider - spring.security.oauth2.client.registration.my-client-2.scope=email - spring.security.oauth2.client.registration.my-client-2.redirect-uri-template=http://my-redirect-uri.com - spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic - spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code - spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://my-auth-server/oauth/authorize spring.security.oauth2.client.provider.my-oauth-provider.token-uri=http://my-auth-server/oauth/token spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=http://my-auth-server/userinfo @@ -3257,6 +3239,48 @@ You can register multiple OAuth2 clients and providers under the spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name ---- +For OpenID Connect providers that support https://openid.net/specs/openid-connect-discovery-1_0.html[OpenID Connect discovery], +the configuration can be further simplified. The provider needs to be configured with an `issuer-uri` which is the +URI that the it asserts as its Issuer Identifier. For example, if the +`issuer-uri` provided is "https://example.com", then an `OpenID Provider Configuration Request` +will be made to "https://example.com/.well-known/openid-configuration". The result is expected +to be an `OpenID Provider Configuration Response`. The following example shows how an OpenID Connect +Provider can be configured with the `issuer-uri`: + +[source,properties,indent=0] +---- + spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/ +---- + + + +[[boot-features-security-oauth2-login-client-registration]] +===== OpenID Connect Login client registration + +You can register multiple Open ID Connect clients under the +`spring.security.oauth2.client.registration.login` prefix, as shown in the following example: + +[source,properties,indent=0] +---- + spring.security.oauth2.client.registration.login.my-client-1.client-id=abcd + spring.security.oauth2.client.registration.login.my-client-1.client-secret=password + spring.security.oauth2.client.registration.login.my-client-1.client-name=Client for user scope + spring.security.oauth2.client.registration.login.my-client-1.provider=my-oauth-provider + spring.security.oauth2.client.registration.login.my-client-1.scope=user + spring.security.oauth2.client.registration.login.my-client-1.redirect-uri-template=http://localhost:8080/login/oauth2/code/my-client-1 + spring.security.oauth2.client.registration.login.my-client-1.client-authentication-method=basic + spring.security.oauth2.client.registration.login.my-client-1.authorization-grant-type=authorization_code + + spring.security.oauth2.client.registration.login.my-client-2.client-id=abcd + spring.security.oauth2.client.registration.login.my-client-2.client-secret=password + spring.security.oauth2.client.registration.login.my-client-2.client-name=Client for email scope + spring.security.oauth2.client.registration.login.my-client-2.provider=my-oauth-provider + spring.security.oauth2.client.registration.login.my-client-2.scope=email + spring.security.oauth2.client.registration.login.my-client-2.redirect-uri-template=http://localhost:8080/login/oauth2/code/my-client-2 + spring.security.oauth2.client.registration.login.my-client-2.client-authentication-method=basic + spring.security.oauth2.client.registration.login.my-client-2.authorization-grant-type=authorization_code +---- + By default, Spring Security's `OAuth2LoginAuthenticationFilter` only processes URLs matching `/login/oauth2/code/*`. If you want to customize the `redirect-uri-template` to use a different pattern, you need to provide configuration to process that custom pattern. @@ -3280,6 +3304,40 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { } ---- +The same properties are applicable to both servlet and reactive applications. + + +[[boot-features-security-oauth2-authorization-code-client-registration]] +===== OAuth2 Authorization Code client registration + +You can register multiple OAuth2 `authorization_code` clients under the +`spring.security.oauth2.client.registration.authorization-code` prefix, as shown in the following example: + +[source,properties,indent=0] +---- + spring.security.oauth2.client.registration.authorization-code.my-client-1.client-id=abcd + spring.security.oauth2.client.registration.authorization-code.my-client-1.client-secret=password + spring.security.oauth2.client.registration.authorization-code.my-client-1.client-name=Client for user scope + spring.security.oauth2.client.registration.authorization-code.my-client-1.provider=my-oauth-provider + spring.security.oauth2.client.registration.authorization-code.my-client-1.scope=user + spring.security.oauth2.client.registration.authorization-code.my-client-1.redirect-uri=http://my-redirect-uri.com + spring.security.oauth2.client.registration.authorization-code.my-client-1.client-authentication-method=basic + spring.security.oauth2.client.registration.authorization-code.my-client-1.authorization-grant-type=authorization_code + + spring.security.oauth2.client.registration.authorization-code.my-client-2.client-id=abcd + spring.security.oauth2.client.registration.authorization-code.my-client-2.client-secret=password + spring.security.oauth2.client.registration.authorization-code.my-client-2.client-name=Client for email scope + spring.security.oauth2.client.registration.authorization-code.my-client-2.provider=my-oauth-provider + spring.security.oauth2.client.registration.authorization-code.my-client-2.scope=email + spring.security.oauth2.client.registration.authorization-code.my-client-2.redirect-uri=http://my-redirect-uri.com + spring.security.oauth2.client.registration.authorization-code.my-client-2.client-authentication-method=basic + spring.security.oauth2.client.registration.authorization-code.my-client-2.authorization-grant-type=authorization_code +---- + + + +[[boot-features-security-oauth2-common-providers]] +===== OAuth2 client registration for common providers For common OAuth2 and OpenID providers, including Google, Github, Facebook, and Okta, we provide a set of provider defaults (`google`, `github`, `facebook`, and `okta`, respectively). @@ -3292,27 +3350,12 @@ In other words, the two configurations in the following example use the Google p [source,properties,indent=0] ---- - spring.security.oauth2.client.registration.my-client.client-id=abcd - spring.security.oauth2.client.registration.my-client.client-secret=password - spring.security.oauth2.client.registration.my-client.provider=google - - spring.security.oauth2.client.registration.google.client-id=abcd - spring.security.oauth2.client.registration.google.client-secret=password ----- + spring.security.oauth2.client.registration.login.my-client.client-id=abcd + spring.security.oauth2.client.registration.login.my-client.client-secret=password + spring.security.oauth2.client.registration.login.my-client.provider=google -For OpenID Connect providers that support https://openid.net/specs/openid-connect-discovery-1_0.html[OpenID Connect discovery], -the configuration can be further simplified. The provider needs to be configured with an `issuer-uri` which is the -URI that the it asserts as its Issuer Identifier. For example, if the -`issuer-uri` provided is "https://example.com", then an `OpenID Provider Configuration Request` -will be made to "https://example.com/.well-known/openid-configuration". The result is expected -to be an `OpenID Provider Configuration Response`. The following example shows how an OpenID Connect -Provider can be configured with the `issuer-uri`: - -[source,properties,indent=0] ----- - spring.security.oauth2.client.registration.oidc-provider.client-id=abcd - spring.security.oauth2.client.registration.oidc-provider.client-secret=password - spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/ + spring.security.oauth2.client.registration.login.google.client-id=abcd + spring.security.oauth2.client.registration.login.google.client-secret=password ---- diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml index 1a7bd711b3d5..f496449922ef 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml @@ -3,23 +3,32 @@ spring: oauth2: client: registration: - github-client-1: - client-id: ${APP-CLIENT-ID} - client-secret: ${APP-CLIENT-SECRET} - client-name: Github user - provider: github - scope: user - redirect-uri-template: http://localhost:8080/login/oauth2/code/github - github-client-2: - client-id: ${APP-CLIENT-ID} - client-secret: ${APP-CLIENT-SECRET} - client-name: Github email - provider: github - scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github - yahoo-oidc: - client-id: ${YAHOO-CLIENT-ID} - client-secret: ${YAHOO-CLIENT-SECRET} + login: + github-client-1: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github user + provider: github + scope: user + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + github-client-2: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github email + provider: github + scope: user:email + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + yahoo-oidc: + client-id: a + client-secret: b + authorization_code: + github-repos: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + scope: public_repo + redirect-uri: "{baseUrl}/github-repos" + provider: github + client-name: GitHub Repositories provider: yahoo-oidc: issuer-uri: https://api.login.yahoo.com/ \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java index 254dc3140561..590a19dfbb89 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/test/java/sample/oauth2/client/SampleOAuth2ClientApplicationTests.java @@ -53,7 +53,7 @@ public void everythingShouldRedirectToLogin() { } @Test - public void loginShouldHaveBothOAuthClientsToChooseFrom() { + public void loginShouldHaveBothOAuth2LoginClientsToChooseFrom() { ResponseEntity entity = this.restTemplate.getForEntity("/login", String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); @@ -62,4 +62,12 @@ public void loginShouldHaveBothOAuthClientsToChooseFrom() { assertThat(entity.getBody()).contains("/oauth2/authorization/github-client-2"); } + @Test + public void authorizationCodeClientIsPresent() { + ResponseEntity entity = this.restTemplate.getForEntity("/login", + String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(entity.getBody()).contains("/oauth2/authorization/github-repos"); + } + } diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml index 1a7bd711b3d5..abad05db7243 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -3,23 +3,24 @@ spring: oauth2: client: registration: - github-client-1: - client-id: ${APP-CLIENT-ID} - client-secret: ${APP-CLIENT-SECRET} - client-name: Github user - provider: github - scope: user - redirect-uri-template: http://localhost:8080/login/oauth2/code/github - github-client-2: - client-id: ${APP-CLIENT-ID} - client-secret: ${APP-CLIENT-SECRET} - client-name: Github email - provider: github - scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github - yahoo-oidc: - client-id: ${YAHOO-CLIENT-ID} - client-secret: ${YAHOO-CLIENT-SECRET} + login: + github-client-1: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github user + provider: github + scope: user + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + github-client-2: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github email + provider: github + scope: user:email + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + yahoo-oidc: + client-id: ${YAHOO-CLIENT-ID} + client-secret: ${YAHOO-CLIENT-SECRET} provider: yahoo-oidc: issuer-uri: https://api.login.yahoo.com/ \ No newline at end of file From a54898b8f56e0250ab8f2083a54f6fe50103b116 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 28 Aug 2018 13:56:03 -0700 Subject: [PATCH 474/701] Remove explicit call to `authorizationCodeGrant` See gh-13812 --- .../oauth2/client/servlet/OAuth2WebSecurityConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index caf65cae9e33..44acc664d700 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -61,7 +61,7 @@ static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAda @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().oauth2Login() - .and().oauth2Client().authorizationCodeGrant(); + .and().oauth2Client(); } } From a33e58fc45a5c9d2d6acbcf97e31add6191241ce Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 28 Aug 2018 15:40:54 -0700 Subject: [PATCH 475/701] Deprecate OAuth2 login redirect-uri-template This property is deprecated in favor of `spring.security.oauth2.client.registration.login.*.redirect-uri Closes gh-14226 --- .../oauth2/client/OAuth2ClientProperties.java | 18 ++++++++++++++---- ...ientPropertiesEnvironmentPostProcessor.java | 4 ++-- ...th2ClientPropertiesRegistrationAdapter.java | 2 +- ...ientPropertiesRegistrationAdapterTests.java | 6 +++--- .../main/asciidoc/spring-boot-features.adoc | 6 +++--- .../src/main/resources/application.yml | 4 ++-- .../src/main/resources/application.yml | 4 ++-- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java index 3c83728e4597..267d8220039f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientProperties.java @@ -106,14 +106,24 @@ public static class LoginClientRegistration extends BaseClientRegistration { /** * Redirect URI. May be left blank when using a pre-defined provider. */ - private String redirectUriTemplate; + private String redirectUri; + + public String getRedirectUri() { + return this.redirectUri; + } + + public void setRedirectUri(String redirectUri) { + this.redirectUri = redirectUri; + } + @Deprecated public String getRedirectUriTemplate() { - return this.redirectUriTemplate; + return getRedirectUri(); } - public void setRedirectUriTemplate(String redirectUriTemplate) { - this.redirectUriTemplate = redirectUriTemplate; + @Deprecated + public void setRedirectUriTemplate(String redirectUri) { + setRedirectUri(redirectUri); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java index 05a1a5ce71c0..e25ea4597aa7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesEnvironmentPostProcessor.java @@ -86,8 +86,8 @@ private void addProperties( source); addProperty(registrationId, "client-name", registration::getClientName, map, source); - addProperty(registrationId, "redirect-uri-template", - registration::getRedirectUriTemplate, map, source); + addProperty(registrationId, "redirect-uri-template", registration::getRedirectUri, + map, source); addProperty(registrationId, "authorization-grant-type", registration::getAuthorizationGrantType, map, source); addProperty(registrationId, "client-authentication-method", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index 59b433b215bd..ee1cd69cbcf3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -97,7 +97,7 @@ private static ClientRegistration getLoginClientRegistration(String registration Map providers) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); Builder builder = getBuilder(map, registrationId, properties, providers); - map.from(properties::getRedirectUriTemplate).to(builder::redirectUriTemplate); + map.from(properties::getRedirectUri).to(builder::redirectUriTemplate); return builder.build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 4e6b1cfac807..79d6cd8a6c7b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -78,7 +78,7 @@ public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() { login.setClientSecret("clientSecret"); login.setClientAuthenticationMethod("post"); login.setAuthorizationGrantType("authorization_code"); - login.setRedirectUriTemplate("http://example.com/redirect"); + login.setRedirectUri("http://example.com/redirect"); login.setScope(Collections.singleton("scope")); login.setClientName("clientName"); properties.getRegistration().getLogin().put("registration", login); @@ -155,7 +155,7 @@ public void getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt login.setClientSecret("clientSecret"); login.setClientAuthenticationMethod("post"); login.setAuthorizationGrantType("authorization_code"); - login.setRedirectUriTemplate("http://example.com/redirect"); + login.setRedirectUri("http://example.com/redirect"); login.setScope(Collections.singleton("scope")); login.setClientName("clientName"); properties.getRegistration().getLogin().put("registration", login); @@ -314,7 +314,7 @@ public void oidcProviderConfigurationWithCustomConfigurationOverridesProviderDef login.setClientId("clientId"); login.setClientSecret("clientSecret"); login.setClientAuthenticationMethod("post"); - login.setRedirectUriTemplate("http://example.com/redirect"); + login.setRedirectUri("http://example.com/redirect"); login.setScope(Collections.singleton("user")); Provider provider = new Provider(); provider.setIssuerUri(issuer); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 75c05c006d33..81071b108040 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3267,7 +3267,7 @@ You can register multiple Open ID Connect clients under the spring.security.oauth2.client.registration.login.my-client-1.client-name=Client for user scope spring.security.oauth2.client.registration.login.my-client-1.provider=my-oauth-provider spring.security.oauth2.client.registration.login.my-client-1.scope=user - spring.security.oauth2.client.registration.login.my-client-1.redirect-uri-template=http://localhost:8080/login/oauth2/code/my-client-1 + spring.security.oauth2.client.registration.login.my-client-1.redirect-uri=http://localhost:8080/login/oauth2/code/my-client-1 spring.security.oauth2.client.registration.login.my-client-1.client-authentication-method=basic spring.security.oauth2.client.registration.login.my-client-1.authorization-grant-type=authorization_code @@ -3276,13 +3276,13 @@ You can register multiple Open ID Connect clients under the spring.security.oauth2.client.registration.login.my-client-2.client-name=Client for email scope spring.security.oauth2.client.registration.login.my-client-2.provider=my-oauth-provider spring.security.oauth2.client.registration.login.my-client-2.scope=email - spring.security.oauth2.client.registration.login.my-client-2.redirect-uri-template=http://localhost:8080/login/oauth2/code/my-client-2 + spring.security.oauth2.client.registration.login.my-client-2.redirect-uri=http://localhost:8080/login/oauth2/code/my-client-2 spring.security.oauth2.client.registration.login.my-client-2.client-authentication-method=basic spring.security.oauth2.client.registration.login.my-client-2.authorization-grant-type=authorization_code ---- By default, Spring Security's `OAuth2LoginAuthenticationFilter` only processes URLs -matching `/login/oauth2/code/*`. If you want to customize the `redirect-uri-template` to +matching `/login/oauth2/code/*`. If you want to customize the `redirect-uri` to use a different pattern, you need to provide configuration to process that custom pattern. For example, for servlet applications, you can add your own `WebSecurityConfigurerAdapter` that resembles the following: diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml index f496449922ef..070e578fb30a 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml @@ -10,14 +10,14 @@ spring: client-name: Github user provider: github scope: user - redirect-uri-template: http://localhost:8080/login/oauth2/code/github + redirect-uri: http://localhost:8080/login/oauth2/code/github github-client-2: client-id: ${APP-CLIENT-ID} client-secret: ${APP-CLIENT-SECRET} client-name: Github email provider: github scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github + redirect-uri: http://localhost:8080/login/oauth2/code/github yahoo-oidc: client-id: a client-secret: b diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml index abad05db7243..77e1608d3eb2 100644 --- a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -10,14 +10,14 @@ spring: client-name: Github user provider: github scope: user - redirect-uri-template: http://localhost:8080/login/oauth2/code/github + redirect-uri: http://localhost:8080/login/oauth2/code/github github-client-2: client-id: ${APP-CLIENT-ID} client-secret: ${APP-CLIENT-SECRET} client-name: Github email provider: github scope: user:email - redirect-uri-template: http://localhost:8080/login/oauth2/code/github + redirect-uri: http://localhost:8080/login/oauth2/code/github yahoo-oidc: client-id: ${YAHOO-CLIENT-ID} client-secret: ${YAHOO-CLIENT-SECRET} From ae413c718d054c70141fd11b9480101f3b3dd1b8 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 28 Aug 2018 15:45:08 -0700 Subject: [PATCH 476/701] Reinstate placeholders --- .../src/main/resources/application.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml index 070e578fb30a..cef19f07115f 100644 --- a/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml +++ b/spring-boot-samples/spring-boot-sample-oauth2-client/src/main/resources/application.yml @@ -19,8 +19,8 @@ spring: scope: user:email redirect-uri: http://localhost:8080/login/oauth2/code/github yahoo-oidc: - client-id: a - client-secret: b + client-id: ${YAHOO-CLIENT-ID} + client-secret: ${YAHOO-CLIENT-SECRET} authorization_code: github-repos: client-id: ${APP-CLIENT-ID} From cfd0ab7646fcb8a5ea27fa573cc1429ad5734ef3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 29 Aug 2018 15:46:03 +0200 Subject: [PATCH 477/701] Remove `spring.cloud.enabled` property This commit removes an undocumented property and rename the Spring Cloud Service Connectors auto-configuration. Closes gh-14219 --- ... CloudServiceConnectorsAutoConfiguration.java} | 15 ++++++--------- .../boot/autoconfigure/cloud/package-info.java | 4 ++-- .../src/main/resources/META-INF/spring.factories | 2 +- ...dServiceConnectorsAutoConfigurationTests.java} | 11 ++++++----- 4 files changed, 15 insertions(+), 17 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/{CloudAutoConfiguration.java => CloudServiceConnectorsAutoConfiguration.java} (78%) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/{CloudAutoConfigurationTests.java => CloudServiceConnectorsAutoConfigurationTests.java} (83%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java similarity index 78% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java index 721504a5e7e9..e6bf27202eb1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.Cloud; import org.springframework.cloud.app.ApplicationInstanceInfo; import org.springframework.cloud.config.java.CloudScan; @@ -31,28 +30,26 @@ import org.springframework.core.Ordered; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Cloud. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Cloud Service Connectors. *

    - * Activates when there is no bean of type {@link Cloud} is configured in the context, the - * {@link Cloud} type (this spring-cloud) is on the classpath, and the "cloud" profile is + * Activates when there is no bean of type {@link Cloud} and the "cloud" profile is * active. *

    * Once in effect, the auto-configuration is the equivalent of adding the * {@link CloudScan} annotation in one of the configuration file. Specifically, it adds a * bean for each service bound to the application and one for - * {@link ApplicationInstanceInfo} + * {@link ApplicationInstanceInfo}. * * @author Ramnivas Laddad * @since 1.2.0 */ @Configuration @Profile("cloud") -@AutoConfigureOrder(CloudAutoConfiguration.ORDER) +@AutoConfigureOrder(CloudServiceConnectorsAutoConfiguration.ORDER) @ConditionalOnClass(CloudScanConfiguration.class) @ConditionalOnMissingBean(Cloud.class) -@ConditionalOnProperty(prefix = "spring.cloud", name = "enabled", havingValue = "true", matchIfMissing = true) @Import(CloudScanConfiguration.class) -public class CloudAutoConfiguration { +public class CloudServiceConnectorsAutoConfiguration { // Cloud configuration needs to happen early (before data, mongo etc.) public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 20; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/package-info.java index ef80e68c1b52..efe9c3f08a85 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for Spring Cloud Connectors. + * Auto-configuration for Spring Cloud Service Connectors. */ package org.springframework.boot.autoconfigure.cloud; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 4cc1a3bf9fd6..946adfbdc204 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -27,7 +27,7 @@ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ -org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ +org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfigurationTests.java similarity index 83% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfigurationTests.java index 27c65147b347..34649b8326fc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,11 +32,11 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link CloudAutoConfiguration}. + * Tests for {@link CloudServiceConnectorsAutoConfiguration}. * * @author Phillip Webb */ -public class CloudAutoConfigurationTests { +public class CloudServiceConnectorsAutoConfigurationTests { @Test public void testOrder() { @@ -47,9 +47,10 @@ public void testOrder() { classNames.add(DataSourceAutoConfiguration.class.getName()); classNames.add(MongoRepositoriesAutoConfiguration.class.getName()); classNames.add(JpaRepositoriesAutoConfiguration.class.getName()); - classNames.add(CloudAutoConfiguration.class.getName()); + classNames.add(CloudServiceConnectorsAutoConfiguration.class.getName()); List ordered = sorter.getInPriorityOrder(classNames); - assertThat(ordered.get(0)).isEqualTo(CloudAutoConfiguration.class.getName()); + assertThat(ordered.get(0)) + .isEqualTo(CloudServiceConnectorsAutoConfiguration.class.getName()); } } From 46c30d01e95964c4ae66a63c6a60e2cf00118e19 Mon Sep 17 00:00:00 2001 From: asomov Date: Tue, 28 Aug 2018 15:22:43 +0200 Subject: [PATCH 478/701] Upgrade to SnakeYAML 1.23 Closes gh-14224 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../org/springframework/boot/env/OriginTrackedYamlLoader.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8868b75aaa4a..5955482a7cb9 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -152,7 +152,7 @@ 4.2.1 4.0.1 1.7.25 - 1.21 + 1.23 7.4.0 5.1.0.BUILD-SNAPSHOT 2.1.0.M2 diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedYamlLoader.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedYamlLoader.java index 9132e0e19dab..83020910005a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedYamlLoader.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedYamlLoader.java @@ -124,7 +124,7 @@ private static class KeyScalarNode extends ScalarNode { KeyScalarNode(ScalarNode node) { super(node.getTag(), node.getValue(), node.getStartMark(), node.getEndMark(), - node.getStyle()); + node.getScalarStyle()); } public static NodeTuple get(NodeTuple nodeTuple) { From d91c71b508ed9632984b953ef3977507222f689e Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 29 Aug 2018 16:52:05 -0700 Subject: [PATCH 479/701] Deprecate secure flag on @WebMvcTest Closes gh-14227 --- .../web/servlet/AutoConfigureMockMvc.java | 2 ++ .../servlet/MockMvcWebDriverAutoConfiguration.java | 14 +++++++++++++- .../test/autoconfigure/web/servlet/WebMvcTest.java | 2 ++ ...ationAdvancedConfigurationIntegrationTests.java | 2 +- .../WebMvcTestAllControllersIntegrationTests.java | 4 +++- .../WebMvcTestConverterIntegrationTests.java | 4 +++- ...estCustomDispatcherServletIntegrationTests.java | 4 +++- .../mockmvc/WebMvcTestHateoasIntegrationTests.java | 4 +++- .../WebMvcTestMessageSourceIntegrationTests.java | 4 +++- .../WebMvcTestOneControllerIntegrationTests.java | 4 +++- .../WebMvcTestPageableIntegrationTests.java | 4 +++- .../WebMvcTestPrintAlwaysIntegrationTests.java | 4 +++- .../WebMvcTestPrintDefaultIntegrationTests.java | 4 +++- ...vcTestPrintDefaultOverrideIntegrationTests.java | 4 +++- .../WebMvcTestPrintOverrideIntegrationTests.java | 4 +++- .../WebMvcTestWebClientIntegrationTests.java | 4 +++- ...vcTestWebDriverCustomScopeIntegrationTests.java | 2 +- .../WebMvcTestWebDriverIntegrationTests.java | 4 +++- 18 files changed, 58 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java index 3052e63a92b5..a8723f957786 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java @@ -89,7 +89,9 @@ * If Spring Security's {@link MockMvc} support should be auto-configured when it is * on the classpath. Defaults to {@code true}. * @return if Spring Security's MockMvc support is auto-configured + * @deprecated since 2.1.0 in favor of Spring Security's testing support */ + @Deprecated boolean secure() default true; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java index 157cab99048b..6aceeedbca2d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.test.autoconfigure.web.servlet; +import java.util.concurrent.Executors; + import com.gargoylesoftware.htmlunit.BrowserVersion; import org.openqa.selenium.WebDriver; import org.openqa.selenium.htmlunit.HtmlUnitDriver; @@ -29,8 +31,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; +import org.springframework.util.ClassUtils; /** * Auto-configuration for Selenium {@link WebDriver} MockMVC integration. @@ -46,6 +50,8 @@ public class MockMvcWebDriverAutoConfiguration { private final Environment environment; + private static final String SECURITY_CONTEXT_EXECUTOR = "org.springframework.security.concurrent.DelegatingSecurityContextExecutor"; + MockMvcWebDriverAutoConfiguration(Environment environment) { this.environment = environment; } @@ -63,7 +69,13 @@ public MockMvcHtmlUnitDriverBuilder mockMvcHtmlUnitDriverBuilder(MockMvc mockMvc @ConditionalOnMissingBean(WebDriver.class) @ConditionalOnBean(MockMvcHtmlUnitDriverBuilder.class) public HtmlUnitDriver htmlUnitDriver(MockMvcHtmlUnitDriverBuilder builder) { - return builder.build(); + HtmlUnitDriver driver = builder.build(); + if (ClassUtils.isPresent(SECURITY_CONTEXT_EXECUTOR, + getClass().getClassLoader())) { + driver.setExecutor(new DelegatingSecurityContextExecutor( + Executors.newSingleThreadExecutor())); + } + return driver; } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java index 49550a6c539a..d87377abd6e5 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java @@ -143,7 +143,9 @@ * If Spring Security's {@link MockMvc} support should be auto-configured when it is * on the classpath. Defaults to {@code true}. * @return if Spring Security's MockMvc support is auto-configured + * @deprecated since 2.1.0 in favor of Spring Security's testing support */ + @Deprecated @AliasFor(annotation = AutoConfigureMockMvc.class) boolean secure() default true; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 315111744a40..005051de6a63 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -49,7 +49,7 @@ * @author Eddú Meléndez */ @RunWith(SpringRunner.class) -@WebMvcTest(controllers = RestDocsTestController.class, secure = false) +@WebMvcTest(controllers = RestDocsTestController.class) @AutoConfigureRestDocs public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java index 65417a243300..2a37aa6af13c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.web.servlet.error.ErrorAttributes; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -42,7 +43,8 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser public class WebMvcTestAllControllersIntegrationTests { @Rule diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java index 759782d7594d..9b4aa5fd5d77 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -36,7 +37,8 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) -@WebMvcTest(controllers = ExampleController2.class, secure = false) +@WebMvcTest(controllers = ExampleController2.class) +@WithMockUser public class WebMvcTestConverterIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java index dfc6fa94a7a4..ee10d72ad4fa 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -36,7 +37,8 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser @TestPropertySource(properties = { "spring.mvc.throw-exception-if-no-handler-found=true", "spring.mvc.static-path-pattern=/static/**" }) public class WebMvcTestCustomDispatcherServletIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java index 5c8b2a1403e8..4783c84244db 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.HttpHeaders; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -34,7 +35,8 @@ * @author Andy Wilkinson */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser public class WebMvcTestHateoasIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java index b931a5fd3828..39ebd92bba9b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java @@ -25,6 +25,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.ApplicationContext; import org.springframework.context.MessageSource; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -36,7 +37,8 @@ * @author Andy Wilkinson */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser @TestPropertySource(properties = "spring.messages.basename=web-test-messages") public class WebMvcTestMessageSourceIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java index f46ec61f3627..398b136f8322 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -34,7 +35,8 @@ * @author Phillip Webb */ @RunWith(SpringRunner.class) -@WebMvcTest(controllers = ExampleController2.class, secure = false) +@WebMvcTest(controllers = ExampleController2.class) +@WithMockUser public class WebMvcTestOneControllerIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java index cdb2651e35ac..1193abf2007a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPageableIntegrationTests.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -34,7 +35,8 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser public class WebMvcTestPageableIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java index 8a8148e0935e..1adb567e4527 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -39,7 +40,8 @@ */ @RunWith(SpringRunner.class) @WebMvcTest -@AutoConfigureMockMvc(secure = false, printOnlyOnFailure = false) +@WithMockUser +@AutoConfigureMockMvc(printOnlyOnFailure = false) public class WebMvcTestPrintAlwaysIntegrationTests { @Rule diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java index 319550f4eb9f..0e4e74a6c68e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -35,7 +36,8 @@ */ @RunWith(WebMvcTestPrintDefaultRunner.class) @WebMvcTest -@AutoConfigureMockMvc(secure = false) +@WithMockUser +@AutoConfigureMockMvc public class WebMvcTestPrintDefaultIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java index a064cc2b5d8a..86b88493a97f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -38,7 +39,8 @@ * @author Phillip Webb */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser @TestPropertySource(properties = "spring.test.mockmvc.print=NONE") public class WebMvcTestPrintDefaultOverrideIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java index e033ad0c8701..a6595f2e5ff9 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java @@ -25,6 +25,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrint; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -40,7 +41,8 @@ */ @RunWith(SpringRunner.class) @WebMvcTest -@AutoConfigureMockMvc(secure = false, print = MockMvcPrint.NONE) +@WithMockUser +@AutoConfigureMockMvc(print = MockMvcPrint.NONE) public class WebMvcTestPrintOverrideIntegrationTests { @Rule diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java index 15d3c7cdc63a..cf4fa74aa15f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; @@ -33,7 +34,8 @@ * @author Phillip Webb */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser public class WebMvcTestWebClientIntegrationTests { @Autowired diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java index 7f0f1f600b52..9e9a59d3b643 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java @@ -41,7 +41,7 @@ * @author Phillip Webb */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class WebMvcTestWebDriverCustomScopeIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java index 1d1f74cfcdf0..7d508cc4391a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.util.ReflectionTestUtils; @@ -39,7 +40,8 @@ * @author Phillip Webb */ @RunWith(SpringRunner.class) -@WebMvcTest(secure = false) +@WebMvcTest +@WithMockUser @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class WebMvcTestWebDriverIntegrationTests { From 0384a88b57b70c2ad73f84447a87429ae0d83edf Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 30 Aug 2018 15:43:17 -0700 Subject: [PATCH 480/701] Include web security config classes in @WebMvcTest Security config classes are not included when the secure flag is set to false. Closes gh-6514 --- .../autoconfigure/web/servlet/WebMvcTest.java | 4 ++- .../web/servlet/WebMvcTypeExcludeFilter.java | 32 +++++++++++++++++++ .../servlet/WebMvcTypeExcludeFilterTests.java | 28 ++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java index d87377abd6e5..f1fe4ba56d30 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.java @@ -141,7 +141,9 @@ /** * If Spring Security's {@link MockMvc} support should be auto-configured when it is - * on the classpath. Defaults to {@code true}. + * on the classpath. Also determines if + * {@link org.springframework.security.config.annotation.web.WebSecurityConfigurer} + * classes should be included in the application context. Defaults to {@code true}. * @return if Spring Security's MockMvc support is auto-configured * @deprecated since 2.1.0 in favor of Spring Security's testing support */ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java index ce53327a556a..a74ef88efeaa 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java @@ -33,6 +33,7 @@ import org.springframework.core.convert.converter.GenericConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.stereotype.Controller; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -42,9 +43,12 @@ * {@link TypeExcludeFilter} for {@link WebMvcTest @WebMvcTest}. * * @author Phillip Webb + * @author Madhura Bhave */ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { + private static final String SECURITY_CONFIGURER = "org.springframework.security.config.annotation.web.WebSecurityConfigurer"; + private static final Set> DEFAULT_INCLUDES; static { @@ -63,6 +67,18 @@ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); } + private static final Set> DEFAULT_INCLUDES_AND_SECURITY_CONFIGURER; + + static { + Set> includes = new LinkedHashSet<>(DEFAULT_INCLUDES); + try { + includes.add(ClassUtils.forName(SECURITY_CONFIGURER, null)); + } + catch (Exception ex) { + } + DEFAULT_INCLUDES_AND_SECURITY_CONFIGURER = Collections.unmodifiableSet(includes); + } + private static final Set> DEFAULT_INCLUDES_AND_CONTROLLER; static { @@ -71,6 +87,16 @@ class WebMvcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { DEFAULT_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes); } + private static final Set> DEFAULT_INCLUDES_SECURITY_CONFIGURER_AND_CONTROLLER; + + static { + Set> includes = new LinkedHashSet<>( + DEFAULT_INCLUDES_AND_SECURITY_CONFIGURER); + includes.add(Controller.class); + DEFAULT_INCLUDES_SECURITY_CONFIGURER_AND_CONTROLLER = Collections + .unmodifiableSet(includes); + } + private final WebMvcTest annotation; WebMvcTypeExcludeFilter(Class testClass) { @@ -101,6 +127,12 @@ protected boolean isUseDefaultFilters() { @Override protected Set> getDefaultIncludes() { + if (this.annotation.secure()) { + if (ObjectUtils.isEmpty(this.annotation.controllers())) { + return DEFAULT_INCLUDES_SECURITY_CONFIGURER_AND_CONTROLLER; + } + return DEFAULT_INCLUDES_AND_SECURITY_CONFIGURER; + } if (ObjectUtils.isEmpty(this.annotation.controllers())) { return DEFAULT_INCLUDES_AND_CONTROLLER; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java index 03da0a936246..a082bd6a69e0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilterTests.java @@ -26,6 +26,7 @@ import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; @@ -54,6 +55,7 @@ public void matchWhenHasNoControllers() throws Exception { assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse(); } @Test @@ -67,6 +69,7 @@ public void matchWhenHasController() throws Exception { assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse(); } @Test @@ -80,6 +83,7 @@ public void matchNotUsingDefaultFilters() throws Exception { assertThat(excludes(filter, ExampleMessageConverter.class)).isTrue(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isTrue(); } @Test @@ -106,6 +110,21 @@ public void matchWithExcludeFilter() throws Exception { assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse(); + } + + @Test + public void matchWhenSecureFalse() throws Exception { + WebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter( + WithSecureFalse.class); + assertThat(excludes(filter, Controller1.class)).isFalse(); + assertThat(excludes(filter, Controller2.class)).isFalse(); + assertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse(); + assertThat(excludes(filter, ExampleWeb.class)).isFalse(); + assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse(); + assertThat(excludes(filter, ExampleService.class)).isTrue(); + assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isTrue(); } private boolean excludes(WebMvcTypeExcludeFilter filter, Class type) @@ -140,6 +159,11 @@ static class WithExcludeFilter { } + @WebMvcTest(secure = false) + static class WithSecureFalse { + + } + @Controller static class Controller1 { @@ -173,4 +197,8 @@ static class ExampleRepository { } + static class ExampleWebSecurityConfigurer extends WebSecurityConfigurerAdapter { + + } + } From 8f946260d26323286903072f27015a0db49ae55a Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 30 Aug 2018 16:56:37 -0700 Subject: [PATCH 481/701] Update copyright year for changed files --- .../test/autoconfigure/web/servlet/AutoConfigureMockMvc.java | 2 +- .../web/servlet/MockMvcWebDriverAutoConfiguration.java | 2 +- .../mockmvc/WebMvcTestAllControllersIntegrationTests.java | 2 +- .../servlet/mockmvc/WebMvcTestConverterIntegrationTests.java | 2 +- .../WebMvcTestCustomDispatcherServletIntegrationTests.java | 2 +- .../web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java | 2 +- .../mockmvc/WebMvcTestMessageSourceIntegrationTests.java | 2 +- .../mockmvc/WebMvcTestOneControllerIntegrationTests.java | 2 +- .../servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java | 2 +- .../servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java | 2 +- .../mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java | 2 +- .../mockmvc/WebMvcTestPrintOverrideIntegrationTests.java | 2 +- .../servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java | 2 +- .../mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java | 2 +- .../servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java index a8723f957786..fd61d7600838 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java index 6aceeedbca2d..55319f2c1eb0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/MockMvcWebDriverAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java index 2a37aa6af13c..24b1256eea59 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestAllControllersIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java index 9b4aa5fd5d77..c18c564e486d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestConverterIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java index ee10d72ad4fa..3d4a4fdddb9e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java index 4783c84244db..035359b134c9 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestHateoasIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java index 39ebd92bba9b..623d759a10c3 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestMessageSourceIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java index 398b136f8322..1cf2c38026ae 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestOneControllerIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java index 1adb567e4527..210598792177 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java index 0e4e74a6c68e..9f34d2215512 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java index 86b88493a97f..965bbf50886d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java index a6595f2e5ff9..4ef9d3bf65d4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java index cf4fa74aa15f..b1efd6a87e4d 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebClientIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java index 9e9a59d3b643..a578861f0d80 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverCustomScopeIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java index 7d508cc4391a..2fae1a01f93b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestWebDriverIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. From b16927ce9107dbce7721901ae3f29934b64c2e55 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 30 Aug 2018 18:55:02 -0700 Subject: [PATCH 482/701] Add @WithMockUser to tests See gh-14227 --- ...sAutoConfigurationAdvancedConfigurationIntegrationTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 005051de6a63..010603cabc75 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -30,6 +30,7 @@ import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.FileSystemUtils; @@ -50,6 +51,7 @@ */ @RunWith(SpringRunner.class) @WebMvcTest(controllers = RestDocsTestController.class) +@WithMockUser @AutoConfigureRestDocs public class MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests { From 2fc557a5a90d32fb2cf6ebe2491b031a72507dd3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 31 Aug 2018 11:53:51 +0200 Subject: [PATCH 483/701] Improve WebSocket documentation for reactive applications Closes gh-14069 --- .../spring-boot-dependencies/pom.xml | 6 ++++++ .../src/main/asciidoc/spring-boot-features.adoc | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5955482a7cb9..d94377363477 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -93,6 +93,7 @@ 2.2 1.3 2.0.1.Final + 1.1 1.1.6 3.0.4 3.3.2.Final @@ -1069,6 +1070,11 @@ validation-api ${javax-validation.version} + + javax.websocket + javax.websocket-api + ${javax-websocket.version} + javax.xml.bind jaxb-api diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 81071b108040..1b1043342064 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -7709,7 +7709,20 @@ Undertow. If you deploy a war file to a standalone container, Spring Boot assume container is responsible for the configuration of its WebSocket support. Spring Framework provides {spring-reference}web.html#websocket[rich WebSocket support] -that can be easily accessed through the `spring-boot-starter-websocket` module. +for MVC web applications that can be easily accessed through the +`spring-boot-starter-websocket` module. + +WebSocket support is also available for +{spring-reference}web-reactive.html#webflux-websocket[reactive web applications] and +requires to include the WebSocket API alongside `spring-boot-starter-webflux`: + +[source,xml,indent=0,subs="verbatim,quotes,attributes"] +---- + + javax.websocket + javax.websocket-api + +---- From 7bee9dfc2202bc37116d8e4511f6301d82c5becd Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 31 Aug 2018 14:02:20 +0200 Subject: [PATCH 484/701] Harmonize HTTP client metrics This commit harmonizes the auto-configurations for RestTemplate and WebClient in a single `HttpClientMetricsAutoConfiguration`. Doing so allows to give a better scope for the shared `MeterFilter`. As a result`WebClientMetricsAutoConfiguration` has moved to the `client` package. Closes gh-14269 --- ...> HttpClientMetricsAutoConfiguration.java} | 38 +++--------- .../RestTemplateMetricsConfiguration.java | 61 +++++++++++++++++++ .../WebClientMetricsConfiguration.java} | 25 ++------ .../main/resources/META-INF/spring.factories | 3 +- .../metrics/test/MetricsIntegrationTests.java | 4 +- .../metrics/test/MetricsRun.java | 6 +- ...estTemplateMetricsConfigurationTests.java} | 8 +-- .../WebClientMetricsConfigurationTests.java} | 11 ++-- 8 files changed, 90 insertions(+), 66 deletions(-) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/{RestTemplateMetricsAutoConfiguration.java => HttpClientMetricsAutoConfiguration.java} (61%) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/{reactive/WebClientMetricsAutoConfiguration.java => client/WebClientMetricsConfiguration.java} (60%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/{RestTemplateMetricsAutoConfigurationTests.java => RestTemplateMetricsConfigurationTests.java} (95%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/{reactive/WebClientMetricsAutoConfigurationTests.java => client/WebClientMetricsConfigurationTests.java} (93%) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/HttpClientMetricsAutoConfiguration.java similarity index 61% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/HttpClientMetricsAutoConfiguration.java index 694d65144c87..5c269941b810 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/HttpClientMetricsAutoConfiguration.java @@ -23,62 +23,44 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.OnlyOnceLoggingDenyMeterFilter; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; -import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; -import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer; -import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; -import org.springframework.web.client.RestTemplate; /** - * {@link EnableAutoConfiguration Auto-configuration} for {@link RestTemplate}-related - * metrics. + * {@link EnableAutoConfiguration Auto-configuration} for HTTP client-related metrics. * * @author Jon Schneider * @author Phillip Webb - * @since 2.0.0 + * @author Stephane Nicoll + * @since 2.1.0 */ @Configuration -@AutoConfigureAfter({ MetricsAutoConfiguration.class, RestTemplateAutoConfiguration.class, +@AutoConfigureAfter({ MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }) -@ConditionalOnClass(RestTemplate.class) +@ConditionalOnClass(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class) -public class RestTemplateMetricsAutoConfiguration { +@Import({ RestTemplateMetricsConfiguration.class, WebClientMetricsConfiguration.class }) +public class HttpClientMetricsAutoConfiguration { private final MetricsProperties properties; - public RestTemplateMetricsAutoConfiguration(MetricsProperties properties) { + public HttpClientMetricsAutoConfiguration(MetricsProperties properties) { this.properties = properties; } - @Bean - @ConditionalOnMissingBean(RestTemplateExchangeTagsProvider.class) - public DefaultRestTemplateExchangeTagsProvider restTemplateTagConfigurer() { - return new DefaultRestTemplateExchangeTagsProvider(); - } - - @Bean - public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer( - MeterRegistry meterRegistry, - RestTemplateExchangeTagsProvider restTemplateTagConfigurer) { - return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer, - this.properties.getWeb().getClient().getRequestsMetricName()); - } - @Bean @Order(0) public MeterFilter metricsHttpClientUriTagFilter() { String metricName = this.properties.getWeb().getClient().getRequestsMetricName(); MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(() -> String .format("Reached the maximum number of URI tags for '%s'. Are you using " - + "'uriVariables' on RestTemplate calls?", metricName)); + + "'uriVariables'?", metricName)); return MeterFilter.maximumAllowableTags(metricName, "uri", this.properties.getWeb().getClient().getMaxUriTags(), denyFilter); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java new file mode 100644 index 000000000000..0225d834be8d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.web.client; + +import io.micrometer.core.instrument.MeterRegistry; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; +import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; +import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer; +import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + * Configure the instrumentation of {@link RestTemplate}. + * + * @author Jon Schneider + * @author Phillip Webb + */ +@Configuration +@ConditionalOnClass(RestTemplate.class) +class RestTemplateMetricsConfiguration { + + private final MetricsProperties properties; + + RestTemplateMetricsConfiguration(MetricsProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean(RestTemplateExchangeTagsProvider.class) + public DefaultRestTemplateExchangeTagsProvider restTemplateTagConfigurer() { + return new DefaultRestTemplateExchangeTagsProvider(); + } + + @Bean + public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer( + MeterRegistry meterRegistry, + RestTemplateExchangeTagsProvider restTemplateTagConfigurer) { + return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer, + this.properties.getWeb().getClient().getRequestsMetricName()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfiguration.java similarity index 60% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfiguration.java index c156497214e0..fcf19f52c5ec 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfiguration.java @@ -14,46 +14,29 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.metrics.web.reactive; +package org.springframework.boot.actuate.autoconfigure.metrics.web.client; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; -import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; import org.springframework.boot.actuate.metrics.web.reactive.client.DefaultWebClientExchangeTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.client.MetricsWebClientCustomizer; import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; /** - * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of - * {@link org.springframework.web.reactive.function.client.WebClient}. - *

    - * This is reusing the {@link io.micrometer.core.instrument.config.MeterFilter} defined in - * {@link RestTemplateMetricsAutoConfiguration} for limiting the cardinality of "uri" - * tags. + * Configure the instrumentation of {@link WebClient}. * * @author Brian Clozel - * @since 2.1.0 + * @author Stephane Nicoll */ @Configuration @ConditionalOnClass(WebClient.class) -@AutoConfigureAfter({ MetricsAutoConfiguration.class, - SimpleMetricsExportAutoConfiguration.class }) -@AutoConfigureBefore(WebClientAutoConfiguration.class) -@ConditionalOnBean(MeterRegistry.class) -public class WebClientMetricsAutoConfiguration { +class WebClientMetricsConfiguration { @Bean @ConditionalOnMissingBean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 94fac42c97e4..5bc207067474 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -52,8 +52,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetri org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebClientMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat.TomcatMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java index 08a688e54df4..60f5e5b04771 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java @@ -39,7 +39,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; import org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter; @@ -143,7 +143,7 @@ public void metricsFilterRegisteredForAsyncDispatches() { RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class, - RestTemplateMetricsAutoConfiguration.class, + HttpClientMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, RestTemplateAutoConfiguration.class, WebMvcAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index dfd8e7bf8a2d..a53f206e967e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -38,8 +38,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebClientMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -78,8 +77,7 @@ public final class MetricsRun { RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class, - RestTemplateMetricsAutoConfiguration.class, - WebClientMetricsAutoConfiguration.class, + HttpClientMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class); private MetricsRun() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java similarity index 95% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java index 9b85a821d2d2..bd8f1a7a8fe2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java @@ -37,12 +37,12 @@ import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; /** - * Tests for {@link RestTemplateMetricsAutoConfiguration}. + * Tests for {@link RestTemplateMetricsConfiguration}. * * @author Stephane Nicoll * @author Jon Schneider */ -public class RestTemplateMetricsAutoConfigurationTests { +public class RestTemplateMetricsConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()).withConfiguration( @@ -82,8 +82,8 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { assertThat(registry.get("http.client.requests").meters()).hasSize(2); assertThat(this.out.toString()).contains( "Reached the maximum number of URI tags for 'http.client.requests'."); - assertThat(this.out.toString()).contains( - "Are you using 'uriVariables' on RestTemplate calls?"); + assertThat(this.out.toString()) + .contains("Are you using 'uriVariables'?"); }); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java similarity index 93% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java index d32efe9c64b7..0d23febf7caf 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebClientMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.actuate.autoconfigure.metrics.web.reactive; +package org.springframework.boot.actuate.autoconfigure.metrics.web.client; import io.micrometer.core.instrument.MeterRegistry; import org.junit.Before; @@ -42,11 +42,11 @@ import static org.mockito.Mockito.mock; /** - * Tests for {@link WebClientMetricsAutoConfiguration} + * Tests for {@link WebClientMetricsConfiguration} * * @author Brian Clozel */ -public class WebClientMetricsAutoConfigurationTests { +public class WebClientMetricsConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()) @@ -103,9 +103,10 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { } assertThat(registry.get("http.client.requests").meters()) .hasSize(maxUriTags); + assertThat(this.out.toString()).contains( + "Reached the maximum number of URI tags for 'http.client.requests'."); assertThat(this.out.toString()) - .contains("Reached the maximum number of URI tags " - + "for 'http.client.requests'"); + .contains("Are you using 'uriVariables'?"); }); } From 4634811c7c71d5837327bd3db1e9359197c15f0d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 31 Aug 2018 14:44:46 +0200 Subject: [PATCH 485/701] Polish --- ...RestTemplateMetricsConfigurationTests.java | 38 +++++---- .../WebClientMetricsConfigurationTests.java | 82 +++++++++++-------- 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java index bd8f1a7a8fe2..fa3b797652d6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java @@ -55,9 +55,8 @@ public class RestTemplateMetricsConfigurationTests { public void restTemplateCreatedWithBuilderIsInstrumented() { this.contextRunner.run((context) -> { MeterRegistry registry = context.getBean(MeterRegistry.class); - RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class) - .build(); - validateRestTemplate(restTemplate, registry); + RestTemplateBuilder builder = context.getBean(RestTemplateBuilder.class); + validateRestTemplate(builder, registry); }); } @@ -65,11 +64,10 @@ public void restTemplateCreatedWithBuilderIsInstrumented() { public void restTemplateCanBeCustomizedManually() { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(MetricsRestTemplateCustomizer.class); - RestTemplate restTemplate = new RestTemplateBuilder() - .customizers(context.getBean(MetricsRestTemplateCustomizer.class)) - .build(); + RestTemplateBuilder customBuilder = new RestTemplateBuilder() + .customizers(context.getBean(MetricsRestTemplateCustomizer.class)); MeterRegistry registry = context.getBean(MeterRegistry.class); - validateRestTemplate(restTemplate, registry); + validateRestTemplate(customBuilder, registry); }); } @@ -96,8 +94,8 @@ public void shouldNotDenyNorLogIfMaxUrisIsNotReached() { assertThat(registry.get("http.client.requests").meters()).hasSize(3); assertThat(this.out.toString()).doesNotContain( "Reached the maximum number of URI tags for 'http.client.requests'."); - assertThat(this.out.toString()).doesNotContain( - "Are you using 'uriVariables' on RestTemplate calls?"); + assertThat(this.out.toString()) + .doesNotContain("Are you using 'uriVariables'?"); }); } @@ -115,13 +113,23 @@ private MeterRegistry getInitializedMeterRegistry( return registry; } - private void validateRestTemplate(RestTemplate restTemplate, MeterRegistry registry) { - MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate); - server.expect(requestTo("/test")).andRespond(withStatus(HttpStatus.OK)); + private void validateRestTemplate(RestTemplateBuilder builder, + MeterRegistry registry) { + RestTemplate restTemplate = mockRestTemplate(builder); assertThat(registry.find("http.client.requests").meter()).isNull(); - assertThat(restTemplate.getForEntity("/test", Void.class).getStatusCode()) - .isEqualTo(HttpStatus.OK); - registry.get("http.client.requests").meter(); + assertThat(restTemplate + .getForEntity("/projects/{project}", Void.class, "spring-boot") + .getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(registry.get("http.client.requests").tags("uri", "/projects/{project}") + .meter()).isNotNull(); + } + + private RestTemplate mockRestTemplate(RestTemplateBuilder builder) { + RestTemplate restTemplate = builder.build(); + MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate); + server.expect(requestTo("/projects/spring-boot")) + .andRespond(withStatus(HttpStatus.OK)); + return restTemplate; } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java index 0d23febf7caf..ef3c05647b33 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java @@ -17,16 +17,15 @@ package org.springframework.boot.actuate.autoconfigure.metrics.web.client; import io.micrometer.core.instrument.MeterRegistry; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import reactor.core.publisher.Mono; -import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.metrics.web.reactive.client.WebClientExchangeTagsProvider; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.context.annotation.Bean; @@ -45,36 +44,23 @@ * Tests for {@link WebClientMetricsConfiguration} * * @author Brian Clozel + * @author Stephane Nicoll */ public class WebClientMetricsConfigurationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()) .withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class)); - private ClientHttpConnector connector; - @Rule public OutputCapture out = new OutputCapture(); - @Before - public void setup() { - this.connector = mock(ClientHttpConnector.class); - given(this.connector.connect(any(), any(), any())) - .willReturn(Mono.just(new MockClientHttpResponse(HttpStatus.OK))); - } - @Test public void webClientCreatedWithBuilderIsInstrumented() { this.contextRunner.run((context) -> { - WebClient.Builder builder = context.getBean(WebClient.Builder.class); - WebClient webClient = builder.clientConnector(this.connector).build(); MeterRegistry registry = context.getBean(MeterRegistry.class); - assertThat(registry.find("http.client.requests").meter()).isNull(); - webClient.get().uri("http://example.org/projects/{project}", "spring-boot") - .exchange().block(); - assertThat(registry.find("http.client.requests") - .tags("uri", "/projects/{project}").meter()).isNotNull(); + WebClient.Builder builder = context.getBean(WebClient.Builder.class); + validateWebClient(builder, registry); }); } @@ -89,20 +75,10 @@ public void shouldNotOverrideCustomTagsProvider() { @Test public void afterMaxUrisReachedFurtherUrisAreDenied() { this.contextRunner - .withPropertyValues("management.metrics.web.client.max-uri-tags=10") + .withPropertyValues("management.metrics.web.client.max-uri-tags=2") .run((context) -> { - WebClient.Builder builder = context.getBean(WebClient.Builder.class); - WebClient webClient = builder.clientConnector(this.connector).build(); - MetricsProperties properties = context - .getBean(MetricsProperties.class); - int maxUriTags = properties.getWeb().getClient().getMaxUriTags(); - MeterRegistry registry = context.getBean(MeterRegistry.class); - for (int i = 0; i < maxUriTags + 10; i++) { - webClient.get().uri("http://example.org/projects/" + i).exchange() - .block(); - } - assertThat(registry.get("http.client.requests").meters()) - .hasSize(maxUriTags); + MeterRegistry registry = getInitializedMeterRegistry(context); + assertThat(registry.get("http.client.requests").meters()).hasSize(2); assertThat(this.out.toString()).contains( "Reached the maximum number of URI tags for 'http.client.requests'."); assertThat(this.out.toString()) @@ -110,8 +86,48 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { }); } + @Test + public void shouldNotDenyNorLogIfMaxUrisIsNotReached() { + this.contextRunner + .withPropertyValues("management.metrics.web.client.max-uri-tags=5") + .run((context) -> { + MeterRegistry registry = getInitializedMeterRegistry(context); + assertThat(registry.get("http.client.requests").meters()).hasSize(3); + assertThat(this.out.toString()).doesNotContain( + "Reached the maximum number of URI tags for 'http.client.requests'."); + assertThat(this.out.toString()) + .doesNotContain("Are you using 'uriVariables'?"); + }); + } + + private MeterRegistry getInitializedMeterRegistry( + AssertableApplicationContext context) { + WebClient webClient = mockWebClient(context.getBean(WebClient.Builder.class)); + MeterRegistry registry = context.getBean(MeterRegistry.class); + for (int i = 0; i < 3; i++) { + webClient.get().uri("http://example.org/projects/" + i).exchange().block(); + } + return registry; + } + + private void validateWebClient(WebClient.Builder builder, MeterRegistry registry) { + WebClient webClient = mockWebClient(builder); + assertThat(registry.find("http.client.requests").meter()).isNull(); + webClient.get().uri("http://example.org/projects/{project}", "spring-boot") + .exchange().block(); + assertThat(registry.find("http.client.requests") + .tags("uri", "/projects/{project}").meter()).isNotNull(); + } + + private WebClient mockWebClient(WebClient.Builder builder) { + ClientHttpConnector connector = mock(ClientHttpConnector.class); + given(connector.connect(any(), any(), any())) + .willReturn(Mono.just(new MockClientHttpResponse(HttpStatus.OK))); + return builder.clientConnector(connector).build(); + } + @Configuration - protected static class CustomTagsProviderConfig { + static class CustomTagsProviderConfig { @Bean public WebClientExchangeTagsProvider customTagsProvider() { From f3dbd946dec9e10e2737ef7113fefb38c862f609 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 31 Aug 2018 12:47:25 -0700 Subject: [PATCH 486/701] Document how to test secure mockmvc tests See gh-14227 --- .../src/main/asciidoc/howto.adoc | 25 +++++++++++++++++++ .../main/asciidoc/spring-boot-features.adoc | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index dcb83cc372f2..e1322a023081 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1417,6 +1417,31 @@ For more detail, see the following sections: +[[howto-use-test-with-spring-security]] +== Testing With Spring Security +Spring Security provides support for running tests as a specific user. +For example, the test in the snippet below will run with an authenticated user +that has the `ADMIN` role. + +[source,java,indent=0] +---- + @Test + @WithMockUser(roles="ADMIN") + public void requestProtectedUrlWithUser() throws Exception { + mvc + .perform(get("/")) + ... + } +---- + +Spring Security provides comprehensive integration with Spring MVC Test and +this can also be used when testing controllers using the `@WebMvcTest` slice and `MockMvc`. + +For additional details on Spring Security's testing support, refer to Spring Security's +https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#test[reference documentation]). + + + [[howto-jersey]] == Jersey diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1b1043342064..4c6c1b2ca06e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6886,6 +6886,11 @@ that the driver exits after each test and that a new instance is injected. If yo not want this behavior, you can add `@Scope("singleton")` to your `WebDriver` `@Bean` definition. +If you have Spring Security on the classpath, `@WebMvcTest` will also scan `WebSecurityConfigurer` +beans. Instead of disabling security completely for such tests, you can use Spring Security's test support. +More details on how to use Spring Security's `MockMvc` support can be found in +this _<>_ how-to section. + TIP: Sometimes writing Spring MVC tests is not enough; Spring Boot can help you run <>. From d510bc71b1b5dc2a4bf8aeb5940c58c24e8e2aae Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sat, 1 Sep 2018 00:01:46 +0900 Subject: [PATCH 487/701] Polish Closes gh-14271 --- .../boot/autoconfigure/kafka/KafkaProperties.java | 2 +- .../oauth2/client/ClientsConfiguredCondition.java | 4 ++-- .../kafka/KafkaAutoConfigurationTests.java | 8 ++++---- ...uth2ClientPropertiesRegistrationAdapterTests.java | 2 +- .../error/BasicErrorControllerIntegrationTests.java | 12 +++++------- .../asciidoc/appendix-application-properties.adoc | 6 +++--- .../spring-boot-docs/src/main/asciidoc/howto.adoc | 4 ++-- .../src/main/asciidoc/spring-boot-features.adoc | 6 +++--- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index d06d7e1ca0c1..763054dd48a6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -669,7 +669,7 @@ public static class Streams { /** * Comma-delimited list of host:port pairs to use for establishing the initial - * connection to the Kafka cluster. Overrides the global property, for streams. + * connections to the Kafka cluster. Overrides the global property, for streams. */ private List bootstrapServers; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java index fac1ca580d1e..1d9cdd80b607 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -41,7 +41,7 @@ public class ClientsConfiguredCondition extends SpringBootCondition { private static final Bindable> STRING_LOGIN_REGISTRATION_MAP = Bindable .mapOf(String.class, OAuth2ClientProperties.LoginClientRegistration.class); - private static final Bindable> STRING_AUTHORIZATIONCODE_REGISTRATION_MAP = Bindable + private static final Bindable> STRING_AUTHORIZATION_CODE_REGISTRATION_MAP = Bindable .mapOf(String.class, OAuth2ClientProperties.AuthorizationCodeClientRegistration.class); @@ -71,7 +71,7 @@ private Map getRegistrati Map authCodeClientRegistrations = Binder .get(environment) .bind("spring.security.oauth2.client.registration.authorizationcode", - STRING_AUTHORIZATIONCODE_REGISTRATION_MAP) + STRING_AUTHORIZATION_CODE_REGISTRATION_MAP) .orElse(Collections.emptyMap()); registrations.putAll(loginClientRegistrations); registrations.putAll(authCodeClientRegistrations); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index 1a4881334d9a..f5262c3a3169 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -307,7 +307,7 @@ public void streamsProperties() { Properties configs = context.getBean( KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, KafkaStreamsConfiguration.class).asProperties(); - assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + assertThat(configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo("localhost:9092, localhost:9093"); assertThat( configs.get(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG)) @@ -357,7 +357,7 @@ public void streamsApplicationIdUsesMainApplicationNameByDefault() { Properties configs = context.getBean( KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, KafkaStreamsConfiguration.class).asProperties(); - assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + assertThat(configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo("localhost:9092, localhost:9093"); assertThat(configs.get(StreamsConfig.APPLICATION_ID_CONFIG)) .isEqualTo("my-test-app"); @@ -376,7 +376,7 @@ public void streamsWithCustomKafkaConfiguration() { Properties configs = context.getBean( KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, KafkaStreamsConfiguration.class).asProperties(); - assertThat(configs.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG)) + assertThat(configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo("localhost:9094, localhost:9095"); assertThat(configs.get(StreamsConfig.APPLICATION_ID_CONFIG)) .isEqualTo("test-id"); @@ -628,7 +628,7 @@ protected static class TestKafkaStreamsConfiguration { @Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) public KafkaStreamsConfiguration kafkaStreamsConfiguration() { Map streamsProperties = new HashMap<>(); - streamsProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + streamsProperties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9094, localhost:9095"); streamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, "test-id"); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java index 79d6cd8a6c7b..700f08019e3b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapterTests.java @@ -236,7 +236,7 @@ public void getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationI } @Test - public void getClientRegistrationsWhenAuhtorizationCodeClientShouldAdapt() { + public void getClientRegistrationsWhenAuthorizationCodeClientShouldAdapt() { OAuth2ClientProperties properties = new OAuth2ClientProperties(); OAuth2ClientProperties.AuthorizationCodeClientRegistration registration = new OAuth2ClientProperties.AuthorizationCodeClientRegistration(); registration.setClientId("clientId"); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java index 429d8ff33182..474727646c78 100755 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java @@ -26,7 +26,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -96,25 +95,24 @@ public void testErrorForMachineClient() { @Test public void testErrorForMachineClientTraceParamTrue() { - errorForMachineClientOnTraceParam(() -> createUrl("?trace=true"), true); + errorForMachineClientOnTraceParam("?trace=true", true); } @Test public void testErrorForMachineClientTraceParamFalse() { - errorForMachineClientOnTraceParam(() -> createUrl("?trace=false"), false); + errorForMachineClientOnTraceParam("?trace=false", false); } @Test public void testErrorForMachineClientTraceParamAbsent() { - errorForMachineClientOnTraceParam(() -> createUrl(""), false); + errorForMachineClientOnTraceParam("", false); } @SuppressWarnings("rawtypes") - private void errorForMachineClientOnTraceParam(Supplier url, - boolean expectedTrace) { + private void errorForMachineClientOnTraceParam(String path, boolean expectedTrace) { load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-trace-param"); - ResponseEntity entity = new TestRestTemplate().getForEntity(url.get(), + ResponseEntity entity = new TestRestTemplate().getForEntity(createUrl(path), Map.class); assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", IllegalStateException.class, "Expected!", "/"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 5499c0761db6..b24fb70352e3 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -549,7 +549,7 @@ content into your application. Rather, pick only the properties that you need. spring.flyway.baseline-description= # spring.flyway.baseline-on-migrate= # spring.flyway.baseline-version=1 # Version to start migration - spring.flyway.batch = # + spring.flyway.batch= # spring.flyway.check-location=true # Whether to check that migration scripts location exists. spring.flyway.clean-disabled= # spring.flyway.clean-on-validation-error= # @@ -1106,9 +1106,9 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.ssl.trust-store-location= # Location of the trust store file. spring.kafka.ssl.trust-store-password= # Store password for the trust store file. spring.kafka.ssl.trust-store-type= # Type of the trust store. - spring.kafka.streams.application-id = # Kafka streams application.id property; default spring.application.name. + spring.kafka.streams.application-id= # Kafka streams application.id property; default spring.application.name. spring.kafka.streams.auto-startup=true # Whether or not to auto-start the streams factory bean. - spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connection to the Kafka cluster. Overrides the global property, for streams. + spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connections to the Kafka cluster. Overrides the global property, for streams. spring.kafka.streams.cache-max-bytes-buffering= # Maximum number of memory bytes to be used for buffering across all threads. spring.kafka.streams.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.streams.properties.*= # Additional Kafka properties used to configure the streams. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index e1322a023081..aa2da58b05ae 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1326,7 +1326,7 @@ source for more details. [[howto-switch-off-the-spring-mvc-dispatcherservlet]] === Switch Off the Spring MVC DispatcherServlet -By default, All content is served from the root of your application (`/`) down. If you +By default, all content is served from the root of your application (`/`). If you would rather map to a different path, you can configure one as follows: [source,properties,indent=0,subs="verbatim"] @@ -1334,7 +1334,7 @@ would rather map to a different path, you can configure one as follows: spring.mvc.servlet.path=/acme ---- -If you have additional servlets you can declare a `@Bean` of type `Servlet` or +If you have additional servlets you can declare a `@Bean` of type `Servlet` or `ServletRegistrationBean` for each and Spring Boot will register them transparently to the container. Because servlets are registered that way, they can be mapped to a sub-context of the `DispatcherServlet` without invoking it. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 4c6c1b2ca06e..097b25fdd4a3 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5701,12 +5701,12 @@ reference the auto-configured `KafkaTransactionManager` bean. ==== Kafka Streams Spring for Apache Kafka provides a factory bean to create a `StreamsBuilder` object and manage the lifecycle of its streams. Spring Boot auto-configures the required -`KafkaStreamsConfiguration` bean as long as `kafka-streams` in on the classpath and kafka -streams is enabled via the `@EnableKafkaStreams` annotation. +`KafkaStreamsConfiguration` bean as long as `kafka-streams` is on the classpath and Kafka +Streams is enabled via the `@EnableKafkaStreams` annotation. Enabling Kafka Streams means that the application id and bootstrap servers must be set. The former can be configured using `spring.kafka.streams.application-id`, defaulting to -`spring.application.name` if not set. The later can be set globally or +`spring.application.name` if not set. The latter can be set globally or specifically overridden just for streams. Several additional properties are available using dedicated properties; other arbitrary From 11f0f668ff3ec0fdcb4f0586a31181597dd25393 Mon Sep 17 00:00:00 2001 From: artsiom Date: Thu, 30 Aug 2018 13:43:02 +0300 Subject: [PATCH 488/701] Throw an exception on invalid syntax in SPRING_APPLICATION_JSON Closes gh-14251 --- ...ApplicationJsonEnvironmentPostProcessor.java | 17 ++++++----------- ...cationJsonEnvironmentPostProcessorTests.java | 9 +++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java index 3570a4202647..6508b9cafa3b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java @@ -50,6 +50,7 @@ * @author Dave Syer * @author Phillip Webb * @author Madhura Bhave + * @author Artsiom Yudovin * @since 1.3.0 */ public class SpringApplicationJsonEnvironmentPostProcessor @@ -97,17 +98,11 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, private void processJson(ConfigurableEnvironment environment, JsonPropertyValue propertyValue) { - try { - JsonParser parser = JsonParserFactory.getJsonParser(); - Map map = parser.parseMap(propertyValue.getJson()); - if (!map.isEmpty()) { - addJsonPropertySource(environment, - new JsonPropertySource(propertyValue, flatten(map))); - } - } - catch (Exception ex) { - logger.warn("Cannot parse JSON for spring.application.json: " - + propertyValue.getJson(), ex); + JsonParser parser = JsonParserFactory.getJsonParser(); + Map map = parser.parseMap(propertyValue.getJson()); + if (!map.isEmpty()) { + addJsonPropertySource(environment, + new JsonPropertySource(propertyValue, flatten(map))); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java index b485853eaab2..574ffe8ba142 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java @@ -16,8 +16,11 @@ package org.springframework.boot.env; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.boot.json.JsonParseException; import org.springframework.boot.origin.PropertySourceOrigin; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; @@ -32,15 +35,21 @@ * @author Dave Syer * @author Madhura Bhave * @author Phillip Webb + * @author Artsiom Yudovin */ public class SpringApplicationJsonEnvironmentPostProcessorTests { + @Rule + public ExpectedException expected = ExpectedException.none(); + private SpringApplicationJsonEnvironmentPostProcessor processor = new SpringApplicationJsonEnvironmentPostProcessor(); private ConfigurableEnvironment environment = new StandardEnvironment(); @Test public void error() { + this.expected.expect(JsonParseException.class); + this.expected.expectMessage("Cannot parse JSON"); assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json=foo:bar"); From 3dfece779cd68e029fab18296dec0b7271ed261f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 3 Sep 2018 14:10:30 +0200 Subject: [PATCH 489/701] Upgrade to Kotlin 1.2.61 Closes gh-14290 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d94377363477..0f4063295aca 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -119,7 +119,7 @@ 4.12 5.3.0-RC1 2.0.0 - 1.2.60 + 1.2.61 5.1.0.M1 3.6.2 2.11.1 From 5427d778fe5f3d1fe723bc098204474603dc09a7 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 4 Sep 2018 06:27:26 +0900 Subject: [PATCH 490/701] Polish Closes gh-14293 --- .../data/mongo/MongoDataAutoConfiguration.java | 5 +++-- .../orm/jpa/HibernateJpaConfiguration.java | 2 +- .../mongo/MongoAutoConfigurationTests.java | 17 ++++++----------- .../boot/json/JacksonJsonParser.java | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index cfbe4b1b7a53..265209c15a20 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -185,8 +185,9 @@ public MongoDbFactory withSession(ClientSession session) { } /** - * Check if either a {@link com.mongodb.MongoClient} or - * {@link com.mongodb.client.MongoClient} bean is available. + * Check if either a {@link MongoClient com.mongodb.MongoClient} or + * {@link com.mongodb.client.MongoClient com.mongodb.client.MongoClient} bean is + * available. */ static class AnyMongoClientAvailable extends AnyNestedCondition { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index d9a6433ab462..64b189196072 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -220,7 +220,7 @@ private Object getNoJtaPlatformManager() { // Continue searching } } - throw new IllegalStateException("No available JtaPlatform candidates amongst" + throw new IllegalStateException("No available JtaPlatform candidates amongst " + Arrays.toString(NO_JTA_PLATFORM_CLASSES)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index b86757f85330..7823151052c6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -50,26 +50,22 @@ public void clientExists() { @Test public void optionsAdded() { - this.contextRunner.withPropertyValues("spring.data.mongodb.host:localhost") - .withUserConfiguration(OptionsConfig.class) + this.contextRunner.withUserConfiguration(OptionsConfig.class) .run((context) -> assertThat(context.getBean(MongoClient.class) .getMongoClientOptions().getSocketTimeout()).isEqualTo(300)); } @Test public void optionsAddedButNoHost() { - this.contextRunner - .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") - .withUserConfiguration(OptionsConfig.class) + this.contextRunner.withUserConfiguration(OptionsConfig.class) .run((context) -> assertThat(context.getBean(MongoClient.class) .getMongoClientOptions().getSocketTimeout()).isEqualTo(300)); } @Test public void optionsSslConfig() { - this.contextRunner - .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") - .withUserConfiguration(SslOptionsConfig.class).run((context) -> { + this.contextRunner.withUserConfiguration(SslOptionsConfig.class) + .run((context) -> { assertThat(context).hasSingleBean(MongoClient.class); MongoClient mongo = context.getBean(MongoClient.class); MongoClientOptions options = mongo.getMongoClientOptions(); @@ -81,9 +77,8 @@ public void optionsSslConfig() { @Test public void doesNotCreateMongoClientWhenAlreadyDefined() { - this.contextRunner - .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") - .withUserConfiguration(FallbackMongoClientConfig.class).run((context) -> { + this.contextRunner.withUserConfiguration(FallbackMongoClientConfig.class) + .run((context) -> { assertThat(context).doesNotHaveBean(MongoClient.class); assertThat(context) .hasSingleBean(com.mongodb.client.MongoClient.class); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java index 11f13e757b0a..4da38e6353d5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java @@ -37,7 +37,7 @@ public class JacksonJsonParser extends AbstractJsonParser { private ObjectMapper objectMapper; // Late binding /** - * Creates a instance with the specified {@link ObjectMapper}. + * Creates an instance with the specified {@link ObjectMapper}. * @param objectMapper the object mapper to use */ public JacksonJsonParser(ObjectMapper objectMapper) { From dbbb378650bd5db287bb77b4156930b77603fc25 Mon Sep 17 00:00:00 2001 From: qct Date: Tue, 28 Aug 2018 12:26:45 +0000 Subject: [PATCH 491/701] Align max HTTP header size configuration See gh-14234 --- .../autoconfigure/web/ServerProperties.java | 11 +++++++---- .../JettyWebServerFactoryCustomizer.java | 5 +++-- .../NettyWebServerFactoryCustomizer.java | 16 ++++++++++++++++ .../TomcatWebServerFactoryCustomizer.java | 13 ++++++++----- .../UndertowWebServerFactoryCustomizer.java | 4 +++- .../web/ServerPropertiesTests.java | 4 +++- .../JettyWebServerFactoryCustomizerTests.java | 18 ++++++++++++++++++ .../appendix-application-properties.adoc | 4 ++-- 8 files changed, 60 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 4a344584a028..5ec885ad78be 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -53,6 +53,7 @@ * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy + * @author Chentao Qu */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -81,9 +82,9 @@ public class ServerProperties { private String serverHeader; /** - * Maximum size, in bytes, of the HTTP message header. + * Maximum size of the HTTP message header. */ - private int maxHttpHeaderSize = 0; // bytes + private DataSize maxHttpHeaderSize = DataSize.ofKiloBytes(8L); /** * Time that connectors wait for another HTTP request before closing the connection. @@ -141,11 +142,11 @@ public void setServerHeader(String serverHeader) { this.serverHeader = serverHeader; } - public int getMaxHttpHeaderSize() { + public DataSize getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } - public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { + public void setMaxHttpHeaderSize(DataSize maxHttpHeaderSize) { this.maxHttpHeaderSize = maxHttpHeaderSize; } @@ -327,7 +328,9 @@ public static class Tomcat { /** * Maximum size, in bytes, of the HTTP message header. + * @deprecated since 2.1.0 in favor of {@link ServerProperties#maxHttpHeaderSize} */ + @Deprecated private int maxHttpHeaderSize = 0; /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java index c50a111c57e1..5dab73bd8363 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java @@ -36,6 +36,7 @@ import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; +import org.springframework.util.unit.DataSize; /** * Customization for Jetty-specific features common for both Servlet and Reactive servers. @@ -73,7 +74,8 @@ public void customize(ConfigurableJettyWebServerFactory factory) { .to(factory::setAcceptors); propertyMapper.from(jettyProperties::getSelectors).whenNonNull() .to(factory::setSelectors); - propertyMapper.from(properties::getMaxHttpHeaderSize).when(this::isPositive) + propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(jettyProperties::getMaxHttpPostSize).when(this::isPositive) @@ -133,7 +135,6 @@ public void customize(Server server) { private void customize(HttpConfiguration.ConnectionFactory factory) { HttpConfiguration configuration = factory.getHttpConfiguration(); configuration.setRequestHeaderSize(maxHttpHeaderSize); - configuration.setResponseHeaderSize(maxHttpHeaderSize); } }); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java index 74ff91f6834c..eb226513c307 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java @@ -18,15 +18,19 @@ import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.cloud.CloudPlatform; +import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; +import org.springframework.util.unit.DataSize; /** * Customization for Netty-specific features. * * @author Brian Clozel + * @author Chentao Qu * @since 2.1.0 */ public class NettyWebServerFactoryCustomizer @@ -51,6 +55,11 @@ public int getOrder() { public void customize(NettyReactiveWebServerFactory factory) { factory.setUseForwardHeaders( getOrDeduceUseForwardHeaders(this.serverProperties, this.environment)); + PropertyMapper propertyMapper = PropertyMapper.get(); + propertyMapper.from(this.serverProperties::getMaxHttpHeaderSize).whenNonNull() + .asInt(DataSize::toBytes) + .to((maxHttpRequestHeaderSize) -> customizeMaxHttpHeaderSize(factory, + maxHttpRequestHeaderSize)); } private boolean getOrDeduceUseForwardHeaders(ServerProperties serverProperties, @@ -62,4 +71,11 @@ private boolean getOrDeduceUseForwardHeaders(ServerProperties serverProperties, return platform != null && platform.isUsingForwardHeaders(); } + private void customizeMaxHttpHeaderSize(NettyReactiveWebServerFactory factory, + Integer maxHttpHeaderSize) { + factory.addServerCustomizers((NettyServerCustomizer) (httpServer) -> httpServer + .httpRequestDecoder((httpRequestDecoderSpec) -> httpRequestDecoderSpec + .maxHeaderSize(maxHttpHeaderSize))); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 06a4dc21fcf2..72a166dd29f0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -48,6 +48,7 @@ * @author Stephane Nicoll * @author Phillip Webb * @author Artsiom Yudovin + * @author Chentao Qu * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer implements @@ -84,7 +85,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { tomcatProperties.getMaxThreads())); propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive) .to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads)); - propertyMapper.from(this::determineMaxHttpHeaderSize).when(this::isPositive) + propertyMapper.from(this::determineMaxHttpHeaderSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull() @@ -114,10 +116,11 @@ private boolean isPositive(int value) { return value > 0; } - private int determineMaxHttpHeaderSize() { - return (this.serverProperties.getMaxHttpHeaderSize() > 0) - ? this.serverProperties.getMaxHttpHeaderSize() - : this.serverProperties.getTomcat().getMaxHttpHeaderSize(); + private DataSize determineMaxHttpHeaderSize() { + return isPositive(this.serverProperties.getTomcat().getMaxHttpHeaderSize()) + ? DataSize + .ofBytes(this.serverProperties.getTomcat().getMaxHttpHeaderSize()) + : this.serverProperties.getMaxHttpHeaderSize(); } private void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java index 985128cfd3d4..c08ef547db40 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java @@ -27,6 +27,7 @@ import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; +import org.springframework.util.unit.DataSize; /** * Customization for Undertow-specific features common for both Servlet and Reactive @@ -83,7 +84,8 @@ public void customize(ConfigurableUndertowWebServerFactory factory) { .to(factory::setAccessLogRotate); propertyMapper.from(this::getOrDeduceUseForwardHeaders) .to(factory::setUseForwardHeaders); - propertyMapper.from(properties::getMaxHttpHeaderSize).when(this::isPositive) + propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(undertowProperties::getMaxHttpPostSize).when(this::isPositive) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 771c3b646caa..592d47421308 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -29,6 +29,7 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.MapConfigurationPropertySource; +import org.springframework.util.unit.DataSize; import static org.assertj.core.api.Assertions.assertThat; @@ -136,7 +137,8 @@ public void testCustomizeUriEncoding() { @Test public void testCustomizeHeaderSize() { bind("server.max-http-header-size", "9999"); - assertThat(this.properties.getMaxHttpHeaderSize()).isEqualTo(9999); + assertThat(this.properties.getMaxHttpHeaderSize()) + .isEqualTo(DataSize.ofBytes(9999)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizerTests.java index 1899eab287bd..a81312e5df8e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizerTests.java @@ -21,6 +21,9 @@ import java.util.Locale; import java.util.TimeZone; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConfiguration.ConnectionFactory; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.RequestLog; import org.junit.Before; @@ -140,6 +143,21 @@ public void setUseForwardHeaders() { verify(factory).setUseForwardHeaders(true); } + @Test + public void customizeMaxHttpHeaderSize() { + bind("server.max-http-header-size=2048"); + JettyWebServer server = customizeAndGetServer(); + for (Connector connector : server.getServer().getConnectors()) { + connector.getConnectionFactories().stream() + .filter((factory) -> factory instanceof ConnectionFactory) + .forEach((cf) -> { + ConnectionFactory factory = (ConnectionFactory) cf; + HttpConfiguration configuration = factory.getHttpConfiguration(); + assertThat(configuration.getRequestHeaderSize()).isEqualTo(2048); + }); + } + } + private void bind(String... inlinedProperties) { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b24fb70352e3..56873a0e15b4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -207,7 +207,7 @@ content into your application. Rather, pick only the properties that you need. server.jetty.accesslog.time-zone=GMT # Timezone of the request log. server.jetty.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post or put content. server.jetty.selectors= # Number of selector threads to use. - server.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. + server.max-http-header-size=8KB # Maximum size of the HTTP message header. server.port=8080 # Server HTTP port. server.server-header= # Value to use for the Server response header (if empty, no header is sent). server.use-forward-headers= # Whether X-Forwarded-* headers should be applied to the HttpRequest. @@ -265,7 +265,7 @@ content into your application. Rather, pick only the properties that you need. 172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3} # Regular expression matching trusted IP addresses. server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time. - server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. + server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. Deprecated, use server.max-http-header-size instead. server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content. server.tomcat.max-swallow-size=2MB # Maximum amount of request body to swallow. server.tomcat.max-threads=0 # Maximum number of worker threads. From 8771b34c159c85f5eb2b480dc3e0176a6de5398b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Sep 2018 10:51:54 +0200 Subject: [PATCH 492/701] Polish "Align max HTTP header size configuration" Closes gh-14234 --- .../autoconfigure/web/ServerProperties.java | 16 +++++++++------- .../TomcatWebServerFactoryCustomizer.java | 1 + .../web/ServerPropertiesTests.java | 11 +++++++++-- .../TomcatWebServerFactoryCustomizerTests.java | 18 ++++++++++++++++++ .../appendix-application-properties.adoc | 1 - 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 5ec885ad78be..ccefe488db2e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -29,6 +29,7 @@ import java.util.TimeZone; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.convert.DurationUnit; import org.springframework.boot.web.server.Compression; @@ -84,7 +85,7 @@ public class ServerProperties { /** * Maximum size of the HTTP message header. */ - private DataSize maxHttpHeaderSize = DataSize.ofKiloBytes(8L); + private DataSize maxHttpHeaderSize = DataSize.ofKiloBytes(8); /** * Time that connectors wait for another HTTP request before closing the connection. @@ -328,9 +329,7 @@ public static class Tomcat { /** * Maximum size, in bytes, of the HTTP message header. - * @deprecated since 2.1.0 in favor of {@link ServerProperties#maxHttpHeaderSize} */ - @Deprecated private int maxHttpHeaderSize = 0; /** @@ -496,10 +495,17 @@ public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } + @Deprecated + @DeprecatedConfigurationProperty(replacement = "server.max-http-header-size") public int getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } + @Deprecated + public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { + this.maxHttpHeaderSize = maxHttpHeaderSize; + } + public DataSize getMaxSwallowSize() { return this.maxSwallowSize; } @@ -508,10 +514,6 @@ public void setMaxSwallowSize(DataSize maxSwallowSize) { this.maxSwallowSize = maxSwallowSize; } - public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { - this.maxHttpHeaderSize = maxHttpHeaderSize; - } - public int getAcceptCount() { return this.acceptCount; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 72a166dd29f0..3bf75348d208 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -116,6 +116,7 @@ private boolean isPositive(int value) { return value > 0; } + @SuppressWarnings("deprecation") private DataSize determineMaxHttpHeaderSize() { return isPositive(this.serverProperties.getTomcat().getMaxHttpHeaderSize()) ? DataSize diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 592d47421308..0b4b3276dc0d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -136,9 +136,16 @@ public void testCustomizeUriEncoding() { @Test public void testCustomizeHeaderSize() { - bind("server.max-http-header-size", "9999"); + bind("server.max-http-header-size", "1MB"); assertThat(this.properties.getMaxHttpHeaderSize()) - .isEqualTo(DataSize.ofBytes(9999)); + .isEqualTo(DataSize.ofMegaBytes(1)); + } + + @Test + public void testCustomizeHeaderSizeUseBytesByDefault() { + bind("server.max-http-header-size", "1024"); + assertThat(this.properties.getMaxHttpHeaderSize()) + .isEqualTo(DataSize.ofKiloBytes(1)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index 165f99f3e888..60687e555be5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -121,6 +121,24 @@ public void customMaxHttpPostSize() { .isEqualTo(10000)); } + @Test + public void customMaxHttpHeaderSize() { + bind("server.max-http-header-size=1KB"); + customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server + .getTomcat().getConnector().getProtocolHandler()).getMaxHttpHeaderSize()) + .isEqualTo(DataSize.ofKiloBytes(1).toBytes())); + } + + @Test + @Deprecated + public void customMaxHttpHeaderSizeWithDeprecatedProperty() { + bind("server.max-http-header-size=4KB", + "server.tomcat.max-http-header-size=1024"); + customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server + .getTomcat().getConnector().getProtocolHandler()).getMaxHttpHeaderSize()) + .isEqualTo(DataSize.ofKiloBytes(1).toBytes())); + } + @Test public void customMaxSwallowSize() { bind("server.tomcat.max-swallow-size=10MB"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 56873a0e15b4..ad6cdfe920bd 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -265,7 +265,6 @@ content into your application. Rather, pick only the properties that you need. 172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3} # Regular expression matching trusted IP addresses. server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time. - server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header. Deprecated, use server.max-http-header-size instead. server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content. server.tomcat.max-swallow-size=2MB # Maximum amount of request body to swallow. server.tomcat.max-threads=0 # Maximum number of worker threads. From cb7de2a9636005103436ee3343afda1fed853cc4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Sep 2018 11:04:22 +0200 Subject: [PATCH 493/701] Allow binding number to DataSize Closes gh-14294 --- .../convert/ApplicationConversionService.java | 1 + .../convert/NumberToDataSizeConverter.java | 49 +++++++++++ .../NumberToDataSizeConverterTests.java | 88 +++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDataSizeConverter.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java index 89b18c956a34..83ad9a07dedf 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java @@ -100,6 +100,7 @@ public static void addApplicationConverters(ConverterRegistry registry) { registry.addConverter(new NumberToDurationConverter()); registry.addConverter(new DurationToNumberConverter()); registry.addConverter(new StringToDataSizeConverter()); + registry.addConverter(new NumberToDataSizeConverter()); registry.addConverterFactory(new StringToEnumIgnoringCaseConverterFactory()); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDataSizeConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDataSizeConverter.java new file mode 100644 index 000000000000..4ff0f31614a9 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDataSizeConverter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2018 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.convert; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.util.unit.DataSize; + +/** + * {@link Converter} to convert from a {@link Number} to a {@link DataSize}. + * + * @author Stephane Nicoll + * @see DataSizeUnit + */ +final class NumberToDataSizeConverter implements GenericConverter { + + private final StringToDataSizeConverter delegate = new StringToDataSizeConverter(); + + @Override + public Set getConvertibleTypes() { + return Collections.singleton(new ConvertiblePair(Number.class, DataSize.class)); + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, + TypeDescriptor targetType) { + return this.delegate.convert((source != null) ? source.toString() : null, + TypeDescriptor.valueOf(String.class), targetType); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java new file mode 100644 index 000000000000..925a083eeb62 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2018 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.convert; + +import java.util.Collections; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link NumberToDataSizeConverter}. + * + * @author Stephane Nicoll + */ +@RunWith(Parameterized.class) +public class NumberToDataSizeConverterTests { + + private final ConversionService conversionService; + + public NumberToDataSizeConverterTests(String name, + ConversionService conversionService) { + this.conversionService = conversionService; + } + + @Test + public void convertWhenSimpleWithoutSuffixShouldReturnDataSize() { + assertThat(convert(10)).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert(+10)).isEqualTo(DataSize.ofBytes(10)); + assertThat(convert(-10)).isEqualTo(DataSize.ofBytes(-10)); + } + + @Test + public void convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize() { + assertThat(convert(10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert(+10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert(-10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(-10)); + } + + private DataSize convert(Integer source) { + return this.conversionService.convert(source, DataSize.class); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private DataSize convert(Integer source, DataUnit defaultUnit) { + TypeDescriptor targetType = mock(TypeDescriptor.class); + if (defaultUnit != null) { + DataSizeUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation( + Collections.singletonMap("value", defaultUnit), DataSizeUnit.class, + null); + given(targetType.getAnnotation(DataSizeUnit.class)) + .willReturn(unitAnnotation); + } + given(targetType.getType()).willReturn((Class) DataSize.class); + return (DataSize) this.conversionService.convert(source, + TypeDescriptor.forObject(source), targetType); + } + + @Parameterized.Parameters(name = "{0}") + public static Iterable conversionServices() { + return new ConversionServiceParameters(new NumberToDataSizeConverter()); + } + +} From c0e45b7333b932766c6242be08e309bfb12905f9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Sep 2018 14:09:57 +0200 Subject: [PATCH 494/701] Adapt to Spring Framework API change --- .../autoconfigure/web/ServerProperties.java | 4 +- .../web/servlet/MultipartProperties.java | 4 +- .../web/ServerPropertiesTests.java | 4 +- ...TomcatWebServerFactoryCustomizerTests.java | 6 +-- ...spatcherServletAutoConfigurationTests.java | 4 +- .../properties/bind/AppIoProperties.java | 2 +- .../javac/JavaCompilerFieldValuesParser.java | 8 ++-- .../AbstractFieldValuesProcessorTests.java | 8 ++-- .../fieldvalues/FieldValues.java | 8 ++-- .../ConfigurationPropertiesTests.java | 4 +- .../NumberToDataSizeConverterTests.java | 6 +-- .../StringToDataSizeConverterTests.java | 38 +++++++++---------- .../servlet/MultipartConfigFactoryTests.java | 8 ++-- 13 files changed, 52 insertions(+), 52 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index ccefe488db2e..8706a4cc6529 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -85,7 +85,7 @@ public class ServerProperties { /** * Maximum size of the HTTP message header. */ - private DataSize maxHttpHeaderSize = DataSize.ofKiloBytes(8); + private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8); /** * Time that connectors wait for another HTTP request before closing the connection. @@ -335,7 +335,7 @@ public static class Tomcat { /** * Maximum amount of request body to swallow. */ - private DataSize maxSwallowSize = DataSize.ofMegaBytes(2); + private DataSize maxSwallowSize = DataSize.ofMegabytes(2); /** * Whether requests to the context root should be redirected by appending a / to diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java index 8a43adbd2fae..aa50aafb3b06 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java @@ -64,13 +64,13 @@ public class MultipartProperties { * Max file size. */ @DataSizeUnit(DataUnit.MEGABYTES) - private DataSize maxFileSize = DataSize.ofMegaBytes(1); + private DataSize maxFileSize = DataSize.ofMegabytes(1); /** * Max request size. */ @DataSizeUnit(DataUnit.MEGABYTES) - private DataSize maxRequestSize = DataSize.ofMegaBytes(10); + private DataSize maxRequestSize = DataSize.ofMegabytes(10); /** * Threshold after which files are written to disk. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 0b4b3276dc0d..e442224a4038 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -138,14 +138,14 @@ public void testCustomizeUriEncoding() { public void testCustomizeHeaderSize() { bind("server.max-http-header-size", "1MB"); assertThat(this.properties.getMaxHttpHeaderSize()) - .isEqualTo(DataSize.ofMegaBytes(1)); + .isEqualTo(DataSize.ofMegabytes(1)); } @Test public void testCustomizeHeaderSizeUseBytesByDefault() { bind("server.max-http-header-size", "1024"); assertThat(this.properties.getMaxHttpHeaderSize()) - .isEqualTo(DataSize.ofKiloBytes(1)); + .isEqualTo(DataSize.ofKilobytes(1)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index 60687e555be5..4460a789a037 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -126,7 +126,7 @@ public void customMaxHttpHeaderSize() { bind("server.max-http-header-size=1KB"); customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server .getTomcat().getConnector().getProtocolHandler()).getMaxHttpHeaderSize()) - .isEqualTo(DataSize.ofKiloBytes(1).toBytes())); + .isEqualTo(DataSize.ofKilobytes(1).toBytes())); } @Test @@ -136,7 +136,7 @@ public void customMaxHttpHeaderSizeWithDeprecatedProperty() { "server.tomcat.max-http-header-size=1024"); customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server .getTomcat().getConnector().getProtocolHandler()).getMaxHttpHeaderSize()) - .isEqualTo(DataSize.ofKiloBytes(1).toBytes())); + .isEqualTo(DataSize.ofKilobytes(1).toBytes())); } @Test @@ -144,7 +144,7 @@ public void customMaxSwallowSize() { bind("server.tomcat.max-swallow-size=10MB"); customizeAndRunServer((server) -> assertThat(((AbstractHttp11Protocol) server .getTomcat().getConnector().getProtocolHandler()).getMaxSwallowSize()) - .isEqualTo(DataSize.ofMegaBytes(10).toBytes())); + .isEqualTo(DataSize.ofMegabytes(10).toBytes())); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java index 0e61098a80a2..ca24fde48f81 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfigurationTests.java @@ -213,8 +213,8 @@ protected static class MultipartConfiguration { @Bean public MultipartConfigElement multipartConfig() { MultipartConfigFactory factory = new MultipartConfigFactory(); - factory.setMaxFileSize(DataSize.ofKiloBytes(128)); - factory.setMaxRequestSize(DataSize.ofKiloBytes(128)); + factory.setMaxFileSize(DataSize.ofKilobytes(128)); + factory.setMaxRequestSize(DataSize.ofKilobytes(128)); return factory.createMultipartConfig(); } diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java index 3b7f3fec228a..4730bde51cc6 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/context/properties/bind/AppIoProperties.java @@ -31,7 +31,7 @@ public class AppIoProperties { @DataSizeUnit(DataUnit.MEGABYTES) - private DataSize bufferSize = DataSize.ofMegaBytes(2); + private DataSize bufferSize = DataSize.ofMegabytes(2); private DataSize sizeThreshold = DataSize.ofBytes(512); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java index bb0a061ba903..782d0ce439e1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java @@ -123,10 +123,10 @@ private static class FieldCollector implements TreeVisitor { static { Map values = new HashMap<>(); values.put("Bytes", "B"); - values.put("KiloBytes", "KB"); - values.put("MegaBytes", "MB"); - values.put("GigaBytes", "GB"); - values.put("TeraBytes", "TB"); + values.put("Kilobytes", "KB"); + values.put("Megabytes", "MB"); + values.put("Gigabytes", "GB"); + values.put("Terabytes", "TB"); DATA_SIZE_SUFFIX = Collections.unmodifiableMap(values); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java index 3031a93f5c70..18594f027eed 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java @@ -97,10 +97,10 @@ public void getFieldValues() throws Exception { assertThat(values.get("durationDays")).isEqualTo("50d"); assertThat(values.get("dataSizeNone")).isNull(); assertThat(values.get("dataSizeBytes")).isEqualTo("5B"); - assertThat(values.get("dataSizeKiloBytes")).isEqualTo("10KB"); - assertThat(values.get("dataSizeMegaBytes")).isEqualTo("20MB"); - assertThat(values.get("dataSizeGigaBytes")).isEqualTo("30GB"); - assertThat(values.get("dataSizeTeraBytes")).isEqualTo("40TB"); + assertThat(values.get("dataSizeKilobytes")).isEqualTo("10KB"); + assertThat(values.get("dataSizeMegabytes")).isEqualTo("20MB"); + assertThat(values.get("dataSizeGigabytes")).isEqualTo("30GB"); + assertThat(values.get("dataSizeTerabytes")).isEqualTo("40TB"); } @SupportedAnnotationTypes({ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java index 493bc7185f8b..c6503d845605 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java @@ -128,12 +128,12 @@ public class FieldValues { private DataSize dataSizeBytes = DataSize.ofBytes(5); - private DataSize dataSizeKiloBytes = DataSize.ofKiloBytes(10); + private DataSize dataSizeKilobytes = DataSize.ofKilobytes(10); - private DataSize dataSizeMegaBytes = DataSize.ofMegaBytes(20); + private DataSize dataSizeMegabytes = DataSize.ofMegabytes(20); - private DataSize dataSizeGigaBytes = DataSize.ofGigaBytes(30); + private DataSize dataSizeGigabytes = DataSize.ofGigabytes(30); - private DataSize dataSizeTeraBytes = DataSize.ofTeraBytes(40); + private DataSize dataSizeTerabytes = DataSize.ofTerabytes(40); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java index 55d3f4a67b00..5957c0ade6f3 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java @@ -774,8 +774,8 @@ public void loadWhenBindingCurrentDirectoryToFileShouldBind() { public void loadWhenBindingToDataSizeShouldBind() { load(DataSizeProperties.class, "test.size=10GB", "test.another-size=5"); DataSizeProperties bean = this.context.getBean(DataSizeProperties.class); - assertThat(bean.getSize()).isEqualTo(DataSize.ofGigaBytes(10)); - assertThat(bean.getAnotherSize()).isEqualTo(DataSize.ofKiloBytes(5)); + assertThat(bean.getSize()).isEqualTo(DataSize.ofGigabytes(10)); + assertThat(bean.getAnotherSize()).isEqualTo(DataSize.ofKilobytes(5)); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java index 925a083eeb62..fc60e8ee0a58 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java @@ -56,9 +56,9 @@ public void convertWhenSimpleWithoutSuffixShouldReturnDataSize() { @Test public void convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize() { - assertThat(convert(10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); - assertThat(convert(+10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); - assertThat(convert(-10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(-10)); + assertThat(convert(10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10)); + assertThat(convert(+10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10)); + assertThat(convert(-10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(-10)); } private DataSize convert(Integer source) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java index a97bc4604aa7..52b11d6b208e 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java @@ -57,31 +57,31 @@ public void convertWhenSimpleBytesShouldReturnDataSize() { } @Test - public void convertWhenSimpleKiloBytesShouldReturnDataSize() { - assertThat(convert("10KB")).isEqualTo(DataSize.ofKiloBytes(10)); - assertThat(convert("+10KB")).isEqualTo(DataSize.ofKiloBytes(10)); - assertThat(convert("-10KB")).isEqualTo(DataSize.ofKiloBytes(-10)); + public void convertWhenSimpleKilobytesShouldReturnDataSize() { + assertThat(convert("10KB")).isEqualTo(DataSize.ofKilobytes(10)); + assertThat(convert("+10KB")).isEqualTo(DataSize.ofKilobytes(10)); + assertThat(convert("-10KB")).isEqualTo(DataSize.ofKilobytes(-10)); } @Test - public void convertWhenSimpleMegaBytesShouldReturnDataSize() { - assertThat(convert("10MB")).isEqualTo(DataSize.ofMegaBytes(10)); - assertThat(convert("+10MB")).isEqualTo(DataSize.ofMegaBytes(10)); - assertThat(convert("-10MB")).isEqualTo(DataSize.ofMegaBytes(-10)); + public void convertWhenSimpleMegabytesShouldReturnDataSize() { + assertThat(convert("10MB")).isEqualTo(DataSize.ofMegabytes(10)); + assertThat(convert("+10MB")).isEqualTo(DataSize.ofMegabytes(10)); + assertThat(convert("-10MB")).isEqualTo(DataSize.ofMegabytes(-10)); } @Test - public void convertWhenSimpleGigaBytesShouldReturnDataSize() { - assertThat(convert("10GB")).isEqualTo(DataSize.ofGigaBytes(10)); - assertThat(convert("+10GB")).isEqualTo(DataSize.ofGigaBytes(10)); - assertThat(convert("-10GB")).isEqualTo(DataSize.ofGigaBytes(-10)); + public void convertWhenSimpleGigabytesShouldReturnDataSize() { + assertThat(convert("10GB")).isEqualTo(DataSize.ofGigabytes(10)); + assertThat(convert("+10GB")).isEqualTo(DataSize.ofGigabytes(10)); + assertThat(convert("-10GB")).isEqualTo(DataSize.ofGigabytes(-10)); } @Test - public void convertWhenSimpleTeraBytesShouldReturnDataSize() { - assertThat(convert("10TB")).isEqualTo(DataSize.ofTeraBytes(10)); - assertThat(convert("+10TB")).isEqualTo(DataSize.ofTeraBytes(10)); - assertThat(convert("-10TB")).isEqualTo(DataSize.ofTeraBytes(-10)); + public void convertWhenSimpleTerabytesShouldReturnDataSize() { + assertThat(convert("10TB")).isEqualTo(DataSize.ofTerabytes(10)); + assertThat(convert("+10TB")).isEqualTo(DataSize.ofTerabytes(10)); + assertThat(convert("-10TB")).isEqualTo(DataSize.ofTerabytes(-10)); } @Test @@ -93,11 +93,11 @@ public void convertWhenSimpleWithoutSuffixShouldReturnDataSize() { @Test public void convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize() { - assertThat(convert("10", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKiloBytes(10)); + assertThat(convert("10", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10)); assertThat(convert("+10", DataUnit.KILOBYTES)) - .isEqualTo(DataSize.ofKiloBytes(10)); + .isEqualTo(DataSize.ofKilobytes(10)); assertThat(convert("-10", DataUnit.KILOBYTES)) - .isEqualTo(DataSize.ofKiloBytes(-10)); + .isEqualTo(DataSize.ofKilobytes(-10)); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java index fbad220d1531..04d17310c411 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/MultipartConfigFactoryTests.java @@ -74,8 +74,8 @@ public void createWithStringSizes() { public void createWithDataSizes() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize(DataSize.ofBytes(1)); - factory.setMaxRequestSize(DataSize.ofKiloBytes(2)); - factory.setFileSizeThreshold(DataSize.ofMegaBytes(3)); + factory.setMaxRequestSize(DataSize.ofKilobytes(2)); + factory.setFileSizeThreshold(DataSize.ofMegabytes(3)); MultipartConfigElement config = factory.createMultipartConfig(); assertThat(config.getMaxFileSize()).isEqualTo(1L); assertThat(config.getMaxRequestSize()).isEqualTo(2 * 1024L); @@ -86,8 +86,8 @@ public void createWithDataSizes() { public void createWithNegativeDataSizes() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize(DataSize.ofBytes(-1)); - factory.setMaxRequestSize(DataSize.ofKiloBytes(-2)); - factory.setFileSizeThreshold(DataSize.ofMegaBytes(-3)); + factory.setMaxRequestSize(DataSize.ofKilobytes(-2)); + factory.setFileSizeThreshold(DataSize.ofMegabytes(-3)); MultipartConfigElement config = factory.createMultipartConfig(); assertThat(config.getMaxFileSize()).isEqualTo(-1L); assertThat(config.getMaxRequestSize()).isEqualTo(-1); From 1ceb076035ac68369ddb7f68485ee23b61d8ea20 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Sep 2018 15:04:02 +0200 Subject: [PATCH 495/701] Harmonize Metrics test This commit harmonizes metrics test to rely on `MetricRun.simple()` rather than configuring a simple `MeterRegistry` manually. Rather than applying related auto-configurations automatically, `MetricsRun` only enable the absolute minimum. See gh-14255 --- .../RabbitMetricsAutoConfigurationTests.java | 4 +- .../CacheMetricsAutoConfigurationTests.java | 3 +- .../metrics/test/MetricsRun.java | 26 +++----- ...RestTemplateMetricsConfigurationTests.java | 5 +- .../WebClientMetricsConfigurationTests.java | 3 +- .../WebFluxMetricsAutoConfigurationTests.java | 8 +-- .../WebMvcMetricsAutoConfigurationTests.java | 63 +++++++------------ 7 files changed, 44 insertions(+), 68 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsAutoConfigurationTests.java index 29bb34b9a9c1..9578549ccfc1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/amqp/RabbitMetricsAutoConfigurationTests.java @@ -34,8 +34,8 @@ public class RabbitMetricsAutoConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .with(MetricsRun.simple()) - .withConfiguration(AutoConfigurations.of(RabbitAutoConfiguration.class)); + .with(MetricsRun.simple()).withConfiguration(AutoConfigurations.of( + RabbitAutoConfiguration.class, RabbitMetricsAutoConfiguration.class)); @Test public void autoConfiguredConnectionFactoryIsInstrumented() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java index b70cca7fe6be..b5bcc75aa047 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/cache/CacheMetricsAutoConfigurationTests.java @@ -37,7 +37,8 @@ public class CacheMetricsAutoConfigurationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()).withUserConfiguration(CachingConfiguration.class) - .withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class, + CacheMetricsAutoConfiguration.class)); @Test public void autoConfiguredCacheManagerIsInstrumented() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index a53f206e967e..34b3c0ef41b7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -23,8 +23,6 @@ import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaMetricsExportAutoConfiguration; @@ -36,12 +34,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.AbstractApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.util.Assert; @@ -73,12 +67,8 @@ public final class MetricsRun { } private static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of( - MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class, - RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, - DataSourcePoolMetricsAutoConfiguration.class, - HibernateMetricsAutoConfiguration.class, - HttpClientMetricsAutoConfiguration.class, - WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class); + MetricsAutoConfiguration.class, + CompositeMeterRegistryAutoConfiguration.class); private MetricsRun() { } @@ -88,7 +78,7 @@ private MetricsRun() { * implementation. * @return the function to apply */ - public static Function simple() { + public static > Function simple() { return limitedTo(SimpleMetricsExportAutoConfiguration.class); } @@ -98,18 +88,18 @@ public static Function simpl * @param exportAutoConfigurations the export auto-configurations to include * @return the function to apply */ - public static Function limitedTo( + public static > Function limitedTo( Class... exportAutoConfigurations) { return (contextRunner) -> apply(contextRunner, exportAutoConfigurations); } - private static ApplicationContextRunner apply(ApplicationContextRunner contextRunner, - Class[] exportAutoConfigurations) { + private static > T apply( + T contextRunner, Class[] exportAutoConfigurations) { for (Class configuration : exportAutoConfigurations) { Assert.state(EXPORT_AUTO_CONFIGURATIONS.contains(configuration), () -> "Unknown export auto-configuration " + configuration.getName()); } - return contextRunner + return (T) contextRunner .withPropertyValues("management.metrics.use-global-registry=false") .withConfiguration(AUTO_CONFIGURATIONS) .withConfiguration(AutoConfigurations.of(exportAutoConfigurations)); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java index fa3b797652d6..5e7a19ed8379 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java @@ -45,8 +45,9 @@ public class RestTemplateMetricsConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .with(MetricsRun.simple()).withConfiguration( - AutoConfigurations.of(RestTemplateAutoConfiguration.class)); + .with(MetricsRun.simple()) + .withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class, + HttpClientMetricsAutoConfiguration.class)); @Rule public OutputCapture out = new OutputCapture(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java index ef3c05647b33..9bd52cda77ad 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/WebClientMetricsConfigurationTests.java @@ -50,7 +50,8 @@ public class WebClientMetricsConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.simple()) - .withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(WebClientAutoConfiguration.class, + HttpClientMetricsAutoConfiguration.class)); @Rule public OutputCapture out = new OutputCapture(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java index ff970367fc44..747f6f1db825 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/reactive/WebFluxMetricsAutoConfigurationTests.java @@ -20,8 +20,7 @@ import org.junit.Rule; import org.junit.Test; -import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; import org.springframework.boot.actuate.metrics.web.reactive.server.DefaultWebFluxTagsProvider; import org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter; @@ -47,9 +46,8 @@ public class WebFluxMetricsAutoConfigurationTests { private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, - SimpleMetricsExportAutoConfiguration.class, - WebFluxMetricsAutoConfiguration.class)); + .with(MetricsRun.simple()).withConfiguration( + AutoConfigurations.of(WebFluxMetricsAutoConfiguration.class)); @Rule public OutputCapture output = new OutputCapture(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfigurationTests.java index 354f6671cda1..1999bd4c22bc 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/servlet/WebMvcMetricsAutoConfigurationTests.java @@ -26,11 +26,11 @@ import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Rule; import org.junit.Test; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.web.TestController; import org.springframework.boot.actuate.metrics.web.servlet.DefaultWebMvcTagsProvider; import org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter; @@ -60,7 +60,7 @@ public class WebMvcMetricsAutoConfigurationTests { private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withConfiguration( + .with(MetricsRun.simple()).withConfiguration( AutoConfigurations.of(WebMvcMetricsAutoConfiguration.class)); @Rule @@ -68,25 +68,27 @@ public class WebMvcMetricsAutoConfigurationTests { @Test public void backsOffWhenMeterRegistryIsMissing() { - this.contextRunner.run((context) -> assertThat(context) - .doesNotHaveBean(WebMvcMetricsAutoConfiguration.class)); + new WebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(WebMvcMetricsAutoConfiguration.class)) + .run((context) -> assertThat(context) + .doesNotHaveBean(WebMvcTagsProvider.class)); } @Test public void definesTagsProviderAndFilterWhenMeterRegistryIsPresent() { - this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class) - .run((context) -> { - assertThat(context).hasSingleBean(DefaultWebMvcTagsProvider.class); - assertThat(context).hasSingleBean(FilterRegistrationBean.class); - assertThat(context.getBean(FilterRegistrationBean.class).getFilter()) - .isInstanceOf(WebMvcMetricsFilter.class); - }); + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(DefaultWebMvcTagsProvider.class); + assertThat(context).hasSingleBean(FilterRegistrationBean.class); + assertThat(context.getBean(FilterRegistrationBean.class).getFilter()) + .isInstanceOf(WebMvcMetricsFilter.class); + }); } @Test public void tagsProviderBacksOff() { - this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class, - TagsProviderConfiguration.class).run((context) -> { + this.contextRunner.withUserConfiguration(TagsProviderConfiguration.class) + .run((context) -> { assertThat(context).doesNotHaveBean(DefaultWebMvcTagsProvider.class); assertThat(context).hasSingleBean(TestWebMvcTagsProvider.class); }); @@ -94,23 +96,18 @@ public void tagsProviderBacksOff() { @Test public void filterRegistrationHasExpectedDispatcherTypesAndOrder() { - this.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class) - .run((context) -> { - FilterRegistrationBean registration = context - .getBean(FilterRegistrationBean.class); - assertThat(registration).hasFieldOrPropertyWithValue( - "dispatcherTypes", - EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC)); - assertThat(registration.getOrder()) - .isEqualTo(Ordered.HIGHEST_PRECEDENCE + 1); - }); + this.contextRunner.run((context) -> { + FilterRegistrationBean registration = context + .getBean(FilterRegistrationBean.class); + assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", + EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC)); + assertThat(registration.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE + 1); + }); } @Test public void afterMaxUrisReachedFurtherUrisAreDenied() { - this.contextRunner - .withUserConfiguration(TestController.class, - MeterRegistryConfiguration.class) + this.contextRunner.withUserConfiguration(TestController.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, WebMvcAutoConfiguration.class)) .withPropertyValues("management.metrics.web.server.max-uri-tags=2") @@ -125,9 +122,7 @@ public void afterMaxUrisReachedFurtherUrisAreDenied() { @Test public void shouldNotDenyNorLogIfMaxUrisIsNotReached() { - this.contextRunner - .withUserConfiguration(TestController.class, - MeterRegistryConfiguration.class) + this.contextRunner.withUserConfiguration(TestController.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, WebMvcAutoConfiguration.class)) .withPropertyValues("management.metrics.web.server.max-uri-tags=5") @@ -154,16 +149,6 @@ private MeterRegistry getInitializedMeterRegistry( return context.getBean(MeterRegistry.class); } - @Configuration - static class MeterRegistryConfiguration { - - @Bean - public MeterRegistry meterRegistry() { - return new SimpleMeterRegistry(); - } - - } - @Configuration static class TagsProviderConfiguration { From 3e745eefc010bac4eba83e99ef92e8d7efab1f2b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Sep 2018 15:18:54 +0200 Subject: [PATCH 496/701] Upgrade to Spring Batch 4.1.0.M3 Closes gh-14296 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0f4063295aca..06a47ea13cb7 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 7.4.0 5.1.0.BUILD-SNAPSHOT 2.1.0.M2 - 4.1.0.M2 + 4.1.0.M3 2.0.2.RELEASE Lovelace-RC2 0.25.0.RELEASE From 2af8a9617b4a67b41fd1fcdfc98a86548af01596 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 4 Sep 2018 15:37:39 +0200 Subject: [PATCH 497/701] Revert temporary workaround for reactor resources This switches back the Reactor resources on global by default. See gh-14058 See SPR-17199 --- .../function/client/ClientHttpConnectorConfiguration.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java index 78493c20b714..4e28a1c20c42 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java @@ -47,9 +47,7 @@ public static class ReactorNetty { @Bean @ConditionalOnMissingBean public ReactorResourceFactory reactorResourceFactory() { - ReactorResourceFactory factory = new ReactorResourceFactory(); - factory.setGlobalResources(false); - return factory; + return new ReactorResourceFactory(); } @Bean From 8ee4775820726d8f73f248761ceb390d72dbc9c6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 4 Sep 2018 20:46:35 +0100 Subject: [PATCH 498/701] Polish --- .../metrics/OnlyOnceLoggingDenyMeterFilter.java | 6 ++++-- .../CloudFoundryWebFluxEndpointIntegrationTests.java | 7 ------- .../actuate/autoconfigure/metrics/test/MetricsRun.java | 1 + .../autoconfigure/security/SecurityDataConfiguration.java | 4 +--- .../security/oauth2/client/ClientsConfiguredCondition.java | 2 +- .../data/redis/RedisAutoConfigurationTests.java | 4 ++-- .../embedded/TomcatWebServerFactoryCustomizerTests.java | 1 + .../boot/docs/kafka/KafkaStreamsBeanExample.java | 2 +- .../autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java | 1 + .../servlet/SpringBootMockMvcBuilderCustomizerTests.java | 2 +- .../LombokAccessLevelOverwriteDefaultProperties.java | 1 + .../env/SpringApplicationJsonEnvironmentPostProcessor.java | 6 ------ 12 files changed, 14 insertions(+), 23 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java index 3538a6f2a5e0..cad3250c8f4e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java @@ -20,6 +20,7 @@ import java.util.function.Supplier; import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Meter.Id; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; import org.slf4j.Logger; @@ -28,7 +29,8 @@ import org.springframework.util.Assert; /** - * {@link MeterFilter} to log only once a warning message and deny {@link Meter.Id}. + * {@link MeterFilter} to log only once a warning message and deny a {@link Meter} + * {@link Id}. * * @author Jon Schneider * @author Dmytro Nosan @@ -49,7 +51,7 @@ public OnlyOnceLoggingDenyMeterFilter(Supplier message) { } @Override - public MeterFilterReply accept(Meter.Id id) { + public MeterFilterReply accept(Id id) { if (this.logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) { this.logger.warn(this.message.get()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java index 9e6ae48cfc2c..f868ccecdfc9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java @@ -167,13 +167,6 @@ public void linksToOtherEndpointsWithRestrictedAccess() { .jsonPath("_links.test-part").doesNotExist())); } - private AnnotationConfigReactiveWebServerApplicationContext createApplicationContext( - Class... config) { - AnnotationConfigReactiveWebServerApplicationContext context = new AnnotationConfigReactiveWebServerApplicationContext(); - context.register(config); - return context; - } - private ContextConsumer withWebTestClient( Consumer clientConsumer) { return (context) -> { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index 34b3c0ef41b7..21c92c888dc8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -93,6 +93,7 @@ private MetricsRun() { return (contextRunner) -> apply(contextRunner, exportAutoConfigurations); } + @SuppressWarnings("unchecked") private static > T apply( T contextRunner, Class[] exportAutoConfigurations) { for (Class configuration : exportAutoConfigurations) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityDataConfiguration.java index dee1f62aa35c..969f0b35771f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityDataConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityDataConfiguration.java @@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.repository.query.spi.EvaluationContextExtensionSupport; import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; /** @@ -30,8 +29,7 @@ * @since 1.3 */ @Configuration -@ConditionalOnClass({ SecurityEvaluationContextExtension.class, - EvaluationContextExtensionSupport.class }) +@ConditionalOnClass(SecurityEvaluationContextExtension.class) public class SecurityDataConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java index 1d9cdd80b607..63ca5eb9a037 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -63,7 +63,7 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, private Map getRegistrations( Environment environment) { - Map registrations = new HashMap(); + Map registrations = new HashMap<>(); Map loginClientRegistrations = Binder .get(environment).bind("spring.security.oauth2.client.registration.login", STRING_LOGIN_REGISTRATION_MAP) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 658d2f31eb7f..c48bd3f2f7c3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -159,8 +159,8 @@ public void testRedisConfigurationWithPool() { LettuceConnectionFactory cf = context .getBean(LettuceConnectionFactory.class); assertThat(cf.getHostName()).isEqualTo("foo"); - GenericObjectPoolConfig poolConfig = getPoolingClientConfiguration(cf) - .getPoolConfig(); + GenericObjectPoolConfig poolConfig = getPoolingClientConfiguration( + cf).getPoolConfig(); assertThat(poolConfig.getMinIdle()).isEqualTo(1); assertThat(poolConfig.getMaxIdle()).isEqualTo(4); assertThat(poolConfig.getMaxTotal()).isEqualTo(16); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index 4460a789a037..30cfca3e0d2f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -166,6 +166,7 @@ public void customRemoteIpValve() { assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1"); } + @SuppressWarnings("unchecked") @Test public void customStaticResourceAllowCaching() { bind("server.tomcat.resource.allow-caching=false"); diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java index d9ddf5f19540..886b68656733 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/kafka/KafkaStreamsBeanExample.java @@ -42,7 +42,7 @@ static class KafkaStreamsExampleConfiguration { @Bean public KStream kStream(StreamsBuilder streamsBuilder) { KStream stream = streamsBuilder.stream("ks1In"); - stream.map((k, v) -> new KeyValue(k, v.toUpperCase())).to("ks1Out", + stream.map((k, v) -> new KeyValue<>(k, v.toUpperCase())).to("ks1Out", Produced.with(Serdes.Integer(), new JsonSerde<>())); return stream; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java index a74ef88efeaa..cb59cdf061f1 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTypeExcludeFilter.java @@ -126,6 +126,7 @@ protected boolean isUseDefaultFilters() { } @Override + @SuppressWarnings("deprecation") protected Set> getDefaultIncludes() { if (this.annotation.secure()) { if (ObjectUtils.isEmpty(this.annotation.controllers())) { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java index e281e3f02ceb..2946d513d520 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizerTests.java @@ -56,7 +56,7 @@ public void customizeShouldAddFilters() { DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(context); this.customizer = new SpringBootMockMvcBuilderCustomizer(context); this.customizer.customize(builder); - FilterRegistrationBean registrationBean = (FilterRegistrationBean) context + FilterRegistrationBean registrationBean = (FilterRegistrationBean) context .getBean("filterRegistrationBean"); Filter testFilter = (Filter) context.getBean("testFilter"); Filter otherTestFilter = registrationBean.getFilter(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDefaultProperties.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDefaultProperties.java index cd67459cf539..115fcb028a05 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDefaultProperties.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDefaultProperties.java @@ -33,6 +33,7 @@ @ConfigurationProperties(prefix = "accesslevel.overwrite.default") public class LombokAccessLevelOverwriteDefaultProperties { + @SuppressWarnings("unused") private String name0; @Getter(AccessLevel.PUBLIC) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java index 6508b9cafa3b..c7c0f153d502 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessor.java @@ -21,9 +21,6 @@ import java.util.Map; import java.util.Objects; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.boot.SpringApplication; import org.springframework.boot.json.JsonParser; import org.springframework.boot.json.JsonParserFactory; @@ -74,9 +71,6 @@ public class SpringApplicationJsonEnvironmentPostProcessor */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 5; - private static final Log logger = LogFactory - .getLog(SpringApplicationJsonEnvironmentPostProcessor.class); - private int order = DEFAULT_ORDER; @Override From 59b5c54489466758ca4260be41ad3ad4336459f3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 4 Sep 2018 15:21:06 -0700 Subject: [PATCH 499/701] Upgrade to Rabbit AMQP Client to 5.4.0 Closes gh-14303 --- .../autoconfigure/amqp/RabbitAutoConfiguration.java | 12 +----------- .../boot/autoconfigure/amqp/RabbitProperties.java | 9 ++++----- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- spring-boot-samples/spring-boot-sample-amqp/pom.xml | 1 - 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index ff3ec812538b..17edff75658c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -18,7 +18,6 @@ import java.time.Duration; import java.util.List; -import java.util.Objects; import com.rabbitmq.client.Channel; @@ -42,7 +41,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.util.ReflectionUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}. @@ -93,11 +91,6 @@ public class RabbitAutoConfiguration { @ConditionalOnMissingBean(ConnectionFactory.class) protected static class RabbitConnectionFactoryCreator { - // Only available in rabbitmq-java-client 5.4.0 + - private static final boolean CAN_ENABLE_HOSTNAME_VERIFICATION = ReflectionUtils - .findMethod(com.rabbitmq.client.ConnectionFactory.class, - "enableHostnameVerification") != null; - @Bean public CachingConnectionFactory rabbitConnectionFactory( RabbitProperties properties, @@ -149,11 +142,8 @@ private RabbitConnectionFactoryBean getRabbitConnectionFactoryBean( map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase); map.from(ssl::isValidateServerCertificate).to((validate) -> factory .setSkipServerCertificateValidation(!validate)); - map.from(ssl::getVerifyHostname).when(Objects::nonNull) + map.from(ssl::getVerifyHostname) .to(factory::setEnableHostnameVerification); - if (ssl.getVerifyHostname() == null && CAN_ENABLE_HOSTNAME_VERIFICATION) { - factory.setEnableHostnameVerification(true); - } } map.from(properties::getConnectionTimeout).whenNonNull() .asInt(Duration::toMillis).to(factory::setConnectionTimeout); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index 44a9157f3abd..1a6cc3ffee92 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -356,10 +356,9 @@ public static class Ssl { private boolean validateServerCertificate = true; /** - * Whether to enable hostname verification. Requires AMQP client 4.8 or above and - * defaults to true when a suitable client version is used. + * Whether to enable hostname verification. */ - private Boolean verifyHostname; + private boolean verifyHostname = true; public boolean isEnabled() { return this.enabled; @@ -433,11 +432,11 @@ public void setValidateServerCertificate(boolean validateServerCertificate) { this.validateServerCertificate = validateServerCertificate; } - public Boolean getVerifyHostname() { + public boolean getVerifyHostname() { return this.verifyHostname; } - public void setVerifyHostname(Boolean verifyHostname) { + public void setVerifyHostname(boolean verifyHostname) { this.verifyHostname = verifyHostname; } diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5a9c101c4e90..3539d84cedde 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -141,7 +141,7 @@ 42.2.4 2.3.0 4.2.1 - 5.3.0 + 5.4.0 Californium-M2 3.1.1 1.0.2 diff --git a/spring-boot-samples/spring-boot-sample-amqp/pom.xml b/spring-boot-samples/spring-boot-sample-amqp/pom.xml index c6a66a610081..ab7de9b2a42e 100644 --- a/spring-boot-samples/spring-boot-sample-amqp/pom.xml +++ b/spring-boot-samples/spring-boot-sample-amqp/pom.xml @@ -14,7 +14,6 @@ Spring Boot AMQP Sample ${basedir}/../.. - 5.4.0 From 75937f5b5c1450b6f7af1211d52f9e9787df6f70 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 4 Sep 2018 16:03:23 -0700 Subject: [PATCH 500/701] Make jmsListenerContainerFactory @ConditionalOnSingleCandidate Closes gh-12700 --- .../jms/JmsAnnotationDrivenConfiguration.java | 2 ++ .../jms/JmsAutoConfigurationTests.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java index 6354e4d84156..9d77cb4d8202 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.annotation.EnableJms; @@ -73,6 +74,7 @@ public DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryC } @Bean + @ConditionalOnSingleCandidate(ConnectionFactory.class) @ConditionalOnMissingBean(name = "jmsListenerContainerFactory") public DefaultJmsListenerContainerFactory jmsListenerContainerFactory( DefaultJmsListenerContainerFactoryConfigurer configurer, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java index 2d3f6dfdbaa2..8ef062aff677 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java @@ -149,6 +149,13 @@ public void testJmsListenerContainerFactoryBackOff() { SimpleJmsListenerContainerFactory.class)); } + @Test + public void jmsListenerContainerFactoryWhenMultipleConnectionFactoryBeansShouldBackOff() { + this.contextRunner.withUserConfiguration(TestConfiguration10.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(JmsListenerContainerFactory.class)); + } + @Test public void testJmsListenerContainerFactoryWithCustomSettings() { this.contextRunner.withUserConfiguration(EnableJmsConfiguration.class) @@ -572,6 +579,21 @@ JmsListenerContainerFactory customListenerContainerFactory( } + @Configuration + protected static class TestConfiguration10 { + + @Bean + public ConnectionFactory connectionFactory1() { + return new ActiveMQConnectionFactory(); + } + + @Bean + public ConnectionFactory connectionFactory2() { + return new ActiveMQConnectionFactory(); + } + + } + @Configuration @EnableJms protected static class EnableJmsConfiguration { From 49c760d275b6fd6745000ab3ab6c06875162c6ee Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Wed, 5 Sep 2018 01:22:56 +0900 Subject: [PATCH 501/701] Update @since tag This commit updates @since tag in CloudServiceConnectorsAutoConfiguration as it has been renamed in cfd0ab7646fcb8a5ea27fa573cc1429ad5734ef3. Closes gh-14297 --- .../cloud/CloudServiceConnectorsAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java index e6bf27202eb1..3b5a8d44b884 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cloud/CloudServiceConnectorsAutoConfiguration.java @@ -41,7 +41,7 @@ * {@link ApplicationInstanceInfo}. * * @author Ramnivas Laddad - * @since 1.2.0 + * @since 2.1.0 */ @Configuration @Profile("cloud") From 5df75e74ae9705fc6252f7f66ef431371f793021 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 09:31:38 +0200 Subject: [PATCH 502/701] Update property description --- .../src/main/asciidoc/appendix-application-properties.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index c2e0fb4bdc8f..4c6e40a6a706 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1173,7 +1173,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.ssl.trust-store-password= # Password used to access the trust store. spring.rabbitmq.ssl.trust-store-type=JKS # Trust store type. spring.rabbitmq.ssl.validate-server-certificate=true # Whether to enable server side certificate validation. - spring.rabbitmq.ssl.verify-hostname= # Whether to enable hostname verification. Requires AMQP client 4.8 or above and defaults to true when a suitable client version is used. + spring.rabbitmq.ssl.verify-hostname=true # Whether to enable hostname verification. spring.rabbitmq.template.exchange= # Name of the default exchange to use for send operations. spring.rabbitmq.template.mandatory= # Whether to enable mandatory messages. spring.rabbitmq.template.queue= # Name of the default queue to receive messages from when none is specified explicitly. From 45204d7ee08b0b51c17e8193b0b7055fc79ddd24 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 10:35:28 +0200 Subject: [PATCH 503/701] Harmonize JAXB version in dependency management Closes gh-14308 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 3539d84cedde..4b6a943c995b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -62,7 +62,7 @@ 2.3.28 6.3.2 3.0.0 - 2.4.0-b180725.0644 + 2.3.0.1 2.5.2 2.8.5 1.4.197 From 21bc3d3ba5b908bff28dfd4133e82ec8742d5793 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 5 Sep 2018 11:54:31 +0100 Subject: [PATCH 504/701] Remove redundant Java 9 and 10 profile that adds JAXB API dependency Closes gh-14309 --- .../spring-boot-sample-webservices/pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/spring-boot-samples/spring-boot-sample-webservices/pom.xml b/spring-boot-samples/spring-boot-sample-webservices/pom.xml index 3d7b088b5c96..721f95394214 100644 --- a/spring-boot-samples/spring-boot-sample-webservices/pom.xml +++ b/spring-boot-samples/spring-boot-sample-webservices/pom.xml @@ -48,18 +48,6 @@ - - java9-10 - - [9,10] - - - - javax.xml.bind - jaxb-api - - - java11+ From 5c86f9eca41af9e6b2dc6d2d2bb9a7e3a1368fcd Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 4 Sep 2018 16:40:43 +0000 Subject: [PATCH 505/701] Add Health details using maps See gh-14305 --- .../boot/actuate/health/Health.java | 15 ++++- .../boot/actuate/health/HealthTests.java | 65 ++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java index da277125ff14..9f29e9fa0ebe 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -47,6 +47,7 @@ * * @author Christian Dupuis * @author Phillip Webb + * @author Michael Pratt * @since 1.1.0 */ @JsonInclude(Include.NON_EMPTY) @@ -229,6 +230,18 @@ public Builder withDetail(String key, Object value) { return this; } + /** + * Add details from the given {@code details} map into existing details. Keys from + * the given map will replace any existing keys if there are duplicates. + * @param details map of details + * @return this {@link Builder} instance + */ + public Builder withDetails(Map details) { + Assert.notNull(details, "Details must not be null"); + this.details.putAll(details); + return this; + } + /** * Set status to {@link Status#UNKNOWN} status. * @return this {@link Builder} instance diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java index 70fc98e56a5d..d7b5c9ecf368 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -17,6 +17,8 @@ package org.springframework.boot.actuate.health; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import org.junit.Rule; import org.junit.Test; @@ -28,6 +30,7 @@ * Tests for {@link Health}. * * @author Phillip Webb + * @author Michael Pratt */ public class HealthTests { @@ -89,6 +92,66 @@ public void withDetails() { assertThat(health.getDetails().get("c")).isEqualTo("d"); } + @Test + public void withDetailsMap() { + Map details = new LinkedHashMap<>(); + details.put("a", "b"); + details.put("c", "d"); + + Health.Builder builder = Health.up(); + builder.withDetails(details); + + Health health = builder.build(); + assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails().get("c")).isEqualTo("d"); + } + + @Test + public void withDetailsMapDuplicateKeys() { + Map details = new LinkedHashMap<>(); + details.put("a", "b"); + details.put("c", "d"); + details.put("a", "e"); + + Health.Builder builder = Health.up(); + builder.withDetails(details); + + Health health = builder.build(); + assertThat(health.getDetails().get("a")).isEqualTo("e"); + assertThat(health.getDetails().get("c")).isEqualTo("d"); + } + + @Test + public void withMultipleDetailsMaps() { + Map details1 = new LinkedHashMap<>(); + details1.put("a", "b"); + details1.put("c", "d"); + + Map details2 = new LinkedHashMap<>(); + details2.put("1", "2"); + + Health.Builder builder = Health.up(); + builder.withDetails(details1); + builder.withDetails(details2); + + Health health = builder.build(); + assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails().get("c")).isEqualTo("d"); + assertThat(health.getDetails().get("1")).isEqualTo("2"); + } + + @Test + public void mixWithDetailsUsage() { + Map details = new LinkedHashMap<>(); + details.put("a", "b"); + + Health.Builder builder = Health.up().withDetails(details).withDetail("c", "d"); + + Health health = builder.build(); + assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails().get("c")).isEqualTo("d"); + } + @Test public void unknownWithDetails() { Health health = new Health.Builder().unknown().withDetail("a", "b").build(); From ca8be3f6bd40ca3353ba3fc7d2e634eb853e2941 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 13:34:02 +0200 Subject: [PATCH 506/701] Polish "Add Health details using maps" Closes gh-14305 --- .../boot/actuate/health/Health.java | 5 +- .../boot/actuate/health/HealthTests.java | 50 ++++--------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java index 9f29e9fa0ebe..f38645d49534 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Health.java @@ -231,10 +231,11 @@ public Builder withDetail(String key, Object value) { } /** - * Add details from the given {@code details} map into existing details. Keys from - * the given map will replace any existing keys if there are duplicates. + * Record details from the given {@code details} map. Keys from the given map + * replace any existing keys if there are duplicates. * @param details map of details * @return this {@link Builder} instance + * @since 2.1.0 */ public Builder withDetails(Map details) { Assert.notNull(details, "Details must not be null"); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java index d7b5c9ecf368..60f3651e92d4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java @@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link Health}. @@ -97,59 +98,30 @@ public void withDetailsMap() { Map details = new LinkedHashMap<>(); details.put("a", "b"); details.put("c", "d"); - - Health.Builder builder = Health.up(); - builder.withDetails(details); - - Health health = builder.build(); - assertThat(health.getDetails().get("a")).isEqualTo("b"); - assertThat(health.getDetails().get("c")).isEqualTo("d"); + Health health = Health.up().withDetails(details).build(); + assertThat(health.getDetails()).containsOnly(entry("a", "b"), entry("c", "d")); } @Test public void withDetailsMapDuplicateKeys() { Map details = new LinkedHashMap<>(); - details.put("a", "b"); details.put("c", "d"); details.put("a", "e"); - - Health.Builder builder = Health.up(); - builder.withDetails(details); - - Health health = builder.build(); - assertThat(health.getDetails().get("a")).isEqualTo("e"); - assertThat(health.getDetails().get("c")).isEqualTo("d"); + Health health = Health.up().withDetail("a", "b").withDetails(details).build(); + assertThat(health.getDetails()).containsOnly(entry("a", "e"), entry("c", "d")); } @Test - public void withMultipleDetailsMaps() { + public void withDetailsMultipleMaps() { Map details1 = new LinkedHashMap<>(); details1.put("a", "b"); details1.put("c", "d"); - Map details2 = new LinkedHashMap<>(); - details2.put("1", "2"); - - Health.Builder builder = Health.up(); - builder.withDetails(details1); - builder.withDetails(details2); - - Health health = builder.build(); - assertThat(health.getDetails().get("a")).isEqualTo("b"); - assertThat(health.getDetails().get("c")).isEqualTo("d"); - assertThat(health.getDetails().get("1")).isEqualTo("2"); - } - - @Test - public void mixWithDetailsUsage() { - Map details = new LinkedHashMap<>(); - details.put("a", "b"); - - Health.Builder builder = Health.up().withDetails(details).withDetail("c", "d"); - - Health health = builder.build(); - assertThat(health.getDetails().get("a")).isEqualTo("b"); - assertThat(health.getDetails().get("c")).isEqualTo("d"); + details1.put("a", "e"); + details1.put("1", "2"); + Health health = Health.up().withDetails(details1).withDetails(details2).build(); + assertThat(health.getDetails()).containsOnly(entry("a", "e"), entry("c", "d"), + entry("1", "2")); } @Test From 7ff41e7c8c7fd160d8fa97400ebbce707093e064 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 13:39:51 +0200 Subject: [PATCH 507/701] Polish --- .../boot/actuate/health/HealthTests.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java index 60f3651e92d4..057703cb3ded 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthTests.java @@ -32,6 +32,7 @@ * * @author Phillip Webb * @author Michael Pratt + * @author Stephane Nicoll */ public class HealthTests { @@ -57,7 +58,7 @@ public void createWithDetails() { Health health = new Health.Builder(Status.UP, Collections.singletonMap("a", "b")) .build(); assertThat(health.getStatus()).isEqualTo(Status.UP); - assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails()).containsOnly(entry("a", "b")); } @Test @@ -80,17 +81,15 @@ public void withException() { RuntimeException ex = new RuntimeException("bang"); Health health = new Health.Builder(Status.UP, Collections.singletonMap("a", "b")) .withException(ex).build(); - assertThat(health.getDetails().get("a")).isEqualTo("b"); - assertThat(health.getDetails().get("error")) - .isEqualTo("java.lang.RuntimeException: bang"); + assertThat(health.getDetails()).containsOnly(entry("a", "b"), + entry("error", "java.lang.RuntimeException: bang")); } @Test public void withDetails() { Health health = new Health.Builder(Status.UP, Collections.singletonMap("a", "b")) .withDetail("c", "d").build(); - assertThat(health.getDetails().get("a")).isEqualTo("b"); - assertThat(health.getDetails().get("c")).isEqualTo("d"); + assertThat(health.getDetails()).containsOnly(entry("a", "b"), entry("c", "d")); } @Test @@ -128,7 +127,7 @@ public void withDetailsMultipleMaps() { public void unknownWithDetails() { Health health = new Health.Builder().unknown().withDetail("a", "b").build(); assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN); - assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails()).containsOnly(entry("a", "b")); } @Test @@ -142,7 +141,7 @@ public void unknown() { public void upWithDetails() { Health health = new Health.Builder().up().withDetail("a", "b").build(); assertThat(health.getStatus()).isEqualTo(Status.UP); - assertThat(health.getDetails().get("a")).isEqualTo("b"); + assertThat(health.getDetails()).containsOnly(entry("a", "b")); } @Test @@ -157,8 +156,8 @@ public void downWithException() { RuntimeException ex = new RuntimeException("bang"); Health health = Health.down(ex).build(); assertThat(health.getStatus()).isEqualTo(Status.DOWN); - assertThat(health.getDetails().get("error")) - .isEqualTo("java.lang.RuntimeException: bang"); + assertThat(health.getDetails()) + .containsOnly(entry("error", "java.lang.RuntimeException: bang")); } @Test From 5f56adc334fe588de74dd2e508bb69ed164989d1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 14:17:31 +0200 Subject: [PATCH 508/701] Add activation API to WebServices samples on Java 11+ Closes gh-14308 --- spring-boot-project/spring-boot-dependencies/pom.xml | 6 ++++++ spring-boot-samples/spring-boot-sample-webservices/pom.xml | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4b6a943c995b..155fd071e937 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -81,6 +81,7 @@ 2.12 2.9.6 3.0.8 + 1.2.0 1.3.2 1.1.0 2.3.0 @@ -1010,6 +1011,11 @@ undertow-websockets-jsr ${undertow.version} + + javax.activation + javax.activation-api + ${javax-activation.version} + javax.annotation javax.annotation-api diff --git a/spring-boot-samples/spring-boot-sample-webservices/pom.xml b/spring-boot-samples/spring-boot-sample-webservices/pom.xml index 721f95394214..4d865b0c7b95 100644 --- a/spring-boot-samples/spring-boot-sample-webservices/pom.xml +++ b/spring-boot-samples/spring-boot-sample-webservices/pom.xml @@ -54,6 +54,10 @@ [11,) + + javax.activation + javax.activation-api + org.glassfish.jaxb jaxb-runtime From 577976751389d9d0da78fbfa59caef106e326b87 Mon Sep 17 00:00:00 2001 From: artsiom Date: Tue, 4 Sep 2018 19:26:22 +0300 Subject: [PATCH 509/701] Make it possible to disable the BackgroundPreinitializer See gh-14298 --- .../BackgroundPreinitializer.java | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java index 968dda42f423..0dabb8d3b1a5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java @@ -38,10 +38,12 @@ /** * {@link ApplicationListener} to trigger early initialization in a background thread of - * time consuming tasks. + * time consuming tasks. Set property spring.backgroundpreinitializer.ignore=true for + * disable background preinitializer. * * @author Phillip Webb * @author Andy Wilkinson + * @author Artsiom Yudovin * @since 1.3.0 */ @Order(LoggingApplicationListener.DEFAULT_ORDER + 1) @@ -55,9 +57,11 @@ public class BackgroundPreinitializer @Override public void onApplicationEvent(SpringApplicationEvent event) { - if (event instanceof ApplicationStartingEvent - && preinitializationStarted.compareAndSet(false, true)) { - performPreinitialization(); + if (!Boolean.getBoolean("spring.backgroundpreinitializer.ignore")) { + if (event instanceof ApplicationStartingEvent + && preinitializationStarted.compareAndSet(false, true)) { + this.background(this.performPreinitialization()); + } } if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) @@ -71,31 +75,9 @@ public void onApplicationEvent(SpringApplicationEvent event) { } } - private void performPreinitialization() { + private void background(Runnable runnable) { try { - Thread thread = new Thread(new Runnable() { - - @Override - public void run() { - runSafely(new ConversionServiceInitializer()); - runSafely(new ValidationInitializer()); - runSafely(new MessageConverterInitializer()); - runSafely(new MBeanFactoryInitializer()); - runSafely(new JacksonInitializer()); - runSafely(new CharsetInitializer()); - preinitializationComplete.countDown(); - } - - public void runSafely(Runnable runnable) { - try { - runnable.run(); - } - catch (Throwable ex) { - // Ignore - } - } - - }, "background-preinit"); + Thread thread = new Thread(runnable, "background-preinit"); thread.start(); } catch (Exception ex) { @@ -106,6 +88,32 @@ public void runSafely(Runnable runnable) { } } + private Runnable performPreinitialization() { + return new Runnable() { + + @Override + public void run() { + runSafely(new ConversionServiceInitializer()); + runSafely(new ValidationInitializer()); + runSafely(new MessageConverterInitializer()); + runSafely(new MBeanFactoryInitializer()); + runSafely(new JacksonInitializer()); + runSafely(new CharsetInitializer()); + preinitializationComplete.countDown(); + } + + public void runSafely(Runnable runnable) { + try { + runnable.run(); + } + catch (Throwable ex) { + // Ignore + } + } + + }; + } + /** * Early initializer for Spring MessageConverters. */ From 304c6a02ba9a526f9a2bbbd944ba47a4003f874c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 14:09:14 +0200 Subject: [PATCH 510/701] Polish "Make it possible to disable the BackgroundPreinitializer" Closes gh-14298 --- .../BackgroundPreinitializer.java | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java index 0dabb8d3b1a5..6566b819e65f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java @@ -38,8 +38,11 @@ /** * {@link ApplicationListener} to trigger early initialization in a background thread of - * time consuming tasks. Set property spring.backgroundpreinitializer.ignore=true for - * disable background preinitializer. + * time consuming tasks. + *

    + * Set the {@value IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME} system property to + * {@code true} to disable this mechanism and let such initialization happen in the + * foreground. * * @author Phillip Webb * @author Andy Wilkinson @@ -50,6 +53,15 @@ public class BackgroundPreinitializer implements ApplicationListener { + /** + * System property that instructs Spring Boot how to run pre initialization. When the + * property is set to {@code true}, no pre intialization happens and each item is + * initialized in the foreground as it needs to. When the property is {@code false} + * (default), pre initialization runs in a separate thread in the background. + * @since 2.1.0 + */ + public static final String IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME = "spring.backgroundpreinitializer.ignore"; + private static final AtomicBoolean preinitializationStarted = new AtomicBoolean( false); @@ -57,11 +69,10 @@ public class BackgroundPreinitializer @Override public void onApplicationEvent(SpringApplicationEvent event) { - if (!Boolean.getBoolean("spring.backgroundpreinitializer.ignore")) { - if (event instanceof ApplicationStartingEvent - && preinitializationStarted.compareAndSet(false, true)) { - this.background(this.performPreinitialization()); - } + if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME) + && event instanceof ApplicationStartingEvent + && preinitializationStarted.compareAndSet(false, true)) { + performPreinitialization(); } if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) @@ -75,9 +86,31 @@ public void onApplicationEvent(SpringApplicationEvent event) { } } - private void background(Runnable runnable) { + private void performPreinitialization() { try { - Thread thread = new Thread(runnable, "background-preinit"); + Thread thread = new Thread(new Runnable() { + + @Override + public void run() { + runSafely(new ConversionServiceInitializer()); + runSafely(new ValidationInitializer()); + runSafely(new MessageConverterInitializer()); + runSafely(new MBeanFactoryInitializer()); + runSafely(new JacksonInitializer()); + runSafely(new CharsetInitializer()); + preinitializationComplete.countDown(); + } + + public void runSafely(Runnable runnable) { + try { + runnable.run(); + } + catch (Throwable ex) { + // Ignore + } + } + + }, "background-preinit"); thread.start(); } catch (Exception ex) { @@ -88,32 +121,6 @@ private void background(Runnable runnable) { } } - private Runnable performPreinitialization() { - return new Runnable() { - - @Override - public void run() { - runSafely(new ConversionServiceInitializer()); - runSafely(new ValidationInitializer()); - runSafely(new MessageConverterInitializer()); - runSafely(new MBeanFactoryInitializer()); - runSafely(new JacksonInitializer()); - runSafely(new CharsetInitializer()); - preinitializationComplete.countDown(); - } - - public void runSafely(Runnable runnable) { - try { - runnable.run(); - } - catch (Throwable ex) { - // Ignore - } - } - - }; - } - /** * Early initializer for Spring MessageConverters. */ From 7442e371547ff54317d1a747f28260c4a4adf0b8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 5 Sep 2018 14:21:52 +0100 Subject: [PATCH 511/701] Add JAXB API to Data JPA starter so it works out-of-the-box on Java 9+ Closes gh-14287 --- .../spring-boot-starter-data-jpa/pom.xml | 4 ++++ .../spring-boot-sample-data-jpa/pom.xml | 14 -------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml index 2e7ad504c597..b29903f6451b 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml @@ -38,6 +38,10 @@ javax.transaction javax.transaction-api + + javax.xml.bind + jaxb-api + org.springframework.data spring-data-jpa diff --git a/spring-boot-samples/spring-boot-sample-data-jpa/pom.xml b/spring-boot-samples/spring-boot-sample-data-jpa/pom.xml index 3d33c7cbb6b7..0cbadadf8bc8 100755 --- a/spring-boot-samples/spring-boot-sample-data-jpa/pom.xml +++ b/spring-boot-samples/spring-boot-sample-data-jpa/pom.xml @@ -45,18 +45,4 @@ - - - java9+ - - [9,) - - - - javax.xml.bind - jaxb-api - - - - From 86d87ad215efdf40fb2bf2a2039c69ae363191f0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 5 Sep 2018 14:26:51 +0100 Subject: [PATCH 512/701] Polish --- .../spring-boot-starter-data-jpa/pom.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml index 134d54560cdf..fa30536d1875 100644 --- a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jpa/pom.xml @@ -26,22 +26,20 @@ org.springframework.boot spring-boot-starter-jdbc + + javax.transaction + javax.transaction-api + org.hibernate hibernate-core - - jboss-transaction-api_1.2_spec - org.jboss.spec.javax.transaction + jboss-transaction-api_1.2_spec - - javax.transaction - javax.transaction-api - org.springframework.data spring-data-jpa From 40e574c3c2710f87b6453b285cc73a73e2ac0412 Mon Sep 17 00:00:00 2001 From: pankajtandon Date: Tue, 4 Sep 2018 23:06:41 -0400 Subject: [PATCH 513/701] Add reference to Stripe Payment Gateway Service starter See gh-14304 --- spring-boot-project/spring-boot-starters/README.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 9b7bed2ec7dd..a5d5b4014c86 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -139,6 +139,9 @@ do as they were designed before this was clarified. | SSH Daemon | https://github.com/anand1st/sshd-shell-spring-boot +| https://github.com/pankajtandon/stripe-starter[Stripe Payment Gateway Starter] +| https://github.com/pankajtandon/stripe-starter + | https://github.com/StripesFramework/stripes[Stripes] | https://github.com/juanpablo-santos/stripes-spring-boot From 9dec5811fb517d2c2e4140aee38766131a9fa07b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 5 Sep 2018 17:39:59 +0200 Subject: [PATCH 514/701] Polish "Add reference to Stripe Payment Gateway Service starter" Closes gh-14304 --- spring-boot-project/spring-boot-starters/README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index a5d5b4014c86..67cb5832b80d 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -139,7 +139,7 @@ do as they were designed before this was clarified. | SSH Daemon | https://github.com/anand1st/sshd-shell-spring-boot -| https://github.com/pankajtandon/stripe-starter[Stripe Payment Gateway Starter] +| https://github.com/stripe/stripe-java[Stripe API] | https://github.com/pankajtandon/stripe-starter | https://github.com/StripesFramework/stripes[Stripes] From c3de4c84f24b4eb8c16eb6434dfeebc6b007b178 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 5 Sep 2018 12:54:12 -0700 Subject: [PATCH 515/701] Polish --- ...DefaultEndpointObjectNameFactoryTests.java | 1 - .../http/codec/CodecsAutoConfiguration.java | 6 +- ...aStreamsAnnotationDrivenConfiguration.java | 7 +- .../task/TaskExecutionAutoConfiguration.java | 19 ++--- .../task/TaskSchedulingAutoConfiguration.java | 10 +-- .../main/asciidoc/spring-boot-features.adoc | 3 +- .../boot/task/TaskExecutorBuilder.java | 81 ++++++++----------- .../boot/task/TaskSchedulerBuilder.java | 65 ++++++--------- .../boot/task/TaskExecutorBuilderTests.java | 15 +--- .../boot/task/TaskSchedulerBuilderTests.java | 15 +--- 10 files changed, 88 insertions(+), 134 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java index 19522be10664..f7413707d241 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java @@ -101,7 +101,6 @@ private void assertUniqueObjectName() { public void generateObjectNameWithUniqueNamesDeprecatedPropertyMismatchMainProperty() { this.environment.setProperty("spring.jmx.unique-names", "false"); this.properties.setUniqueNames(true); - this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("spring.jmx.unique-names"); this.thrown.expectMessage("management.endpoints.jmx.unique-names"); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java index 3a1cb6f4692c..7e6ce073e280 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java @@ -72,10 +72,8 @@ static class LoggingCodecConfiguration { @Bean public CodecCustomizer loggingCodecCustomizer(InsightsProperties properties) { - return (configurer) -> { - configurer.defaultCodecs().enableLoggingRequestDetails( - properties.getWeb().isLogRequestDetails()); - }; + return (configurer) -> configurer.defaultCodecs().enableLoggingRequestDetails( + properties.getWeb().isLogRequestDetails()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java index 7e48a87ceed0..e6eeca66a859 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java @@ -56,15 +56,12 @@ public KafkaStreamsConfiguration defaultKafkaStreamsConfig(Environment environme Map streamsProperties = this.properties.buildStreamsProperties(); if (this.properties.getStreams().getApplicationId() == null) { String applicationName = environment.getProperty("spring.application.name"); - if (applicationName != null) { - streamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, - applicationName); - } - else { + if (applicationName == null) { throw new InvalidConfigurationPropertyValueException( "spring.kafka.streams.application-id", null, "This property is mandatory and fallback 'spring.application.name' is not set either."); } + streamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, applicationName); } return new KafkaStreamsConfiguration(streamsProperties); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java index 62709f5d0199..94c4dcbfafd5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.task; import java.util.concurrent.Executor; -import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -66,14 +65,16 @@ public TaskExecutionAutoConfiguration(TaskExecutionProperties properties, @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder() { TaskExecutionProperties.Pool pool = this.properties.getPool(); - return new TaskExecutorBuilder().queueCapacity(pool.getQueueCapacity()) - .corePoolSize(pool.getCoreSize()).maxPoolSize(pool.getMaxSize()) - .allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()) - .keepAlive(pool.getKeepAlive()) - .threadNamePrefix(this.properties.getThreadNamePrefix()) - .customizers(this.taskExecutorCustomizers.stream() - .collect(Collectors.toList())) - .taskDecorator(this.taskDecorator.getIfUnique()); + TaskExecutorBuilder builder = new TaskExecutorBuilder(); + builder = builder.queueCapacity(pool.getQueueCapacity()); + builder = builder.corePoolSize(pool.getCoreSize()); + builder = builder.maxPoolSize(pool.getMaxSize()); + builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()); + builder = builder.keepAlive(pool.getKeepAlive()); + builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix()); + builder = builder.customizers(this.taskExecutorCustomizers); + builder = builder.taskDecorator(this.taskDecorator.getIfUnique()); + return builder; } @Bean(name = APPLICATION_TASK_EXECUTOR_BEAN_NAME) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java index d31617ac9397..6c02a634277b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.task; -import java.util.stream.Collectors; - import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -55,9 +53,11 @@ public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { @ConditionalOnMissingBean public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider taskSchedulerCustomizers) { - return new TaskSchedulerBuilder().poolSize(properties.getPool().getSize()) - .threadNamePrefix(properties.getThreadNamePrefix()).customizers( - taskSchedulerCustomizers.stream().collect(Collectors.toList())); + TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); + builder = builder.poolSize(properties.getPool().getSize()); + builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); + builder = builder.customizers(taskSchedulerCustomizers); + return builder; } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1b7af6b51060..2c3904f86276 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5879,9 +5879,9 @@ The following code shows a typical example: ---- + [[boot-features-webclient-runtime]] === WebClient Runtime - Spring Boot will auto-detect which `ClientHttpConnector` to drive `WebClient`, depending on the libraries available on the application classpath. @@ -5901,6 +5901,7 @@ You can learn more about the options in the Spring Framework reference documentation]. + [[boot-features-webclient-customization]] === WebClient Customization There are three main approaches to `WebClient` customization, depending on how broadly you diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java index 2e959f286460..eced7b6f95c3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskExecutorBuilder.java @@ -18,7 +18,6 @@ import java.time.Duration; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; @@ -59,11 +58,9 @@ public class TaskExecutorBuilder { private final TaskDecorator taskDecorator; - private final Set taskExecutorCustomizers; + private final Set customizers; - public TaskExecutorBuilder(TaskExecutorCustomizer... taskExecutorCustomizers) { - Assert.notNull(taskExecutorCustomizers, - "TaskExecutorCustomizers must not be null"); + public TaskExecutorBuilder() { this.queueCapacity = null; this.corePoolSize = null; this.maxPoolSize = null; @@ -71,14 +68,13 @@ public TaskExecutorBuilder(TaskExecutorCustomizer... taskExecutorCustomizers) { this.keepAlive = null; this.threadNamePrefix = null; this.taskDecorator = null; - this.taskExecutorCustomizers = Collections.unmodifiableSet( - new LinkedHashSet<>(Arrays.asList(taskExecutorCustomizers))); + this.customizers = null; } - public TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, + private TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, Integer maxPoolSize, Boolean allowCoreThreadTimeOut, Duration keepAlive, String threadNamePrefix, TaskDecorator taskDecorator, - Set taskExecutorCustomizers) { + Set customizers) { this.queueCapacity = queueCapacity; this.corePoolSize = corePoolSize; this.maxPoolSize = maxPoolSize; @@ -86,7 +82,7 @@ public TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, this.keepAlive = keepAlive; this.threadNamePrefix = threadNamePrefix; this.taskDecorator = taskDecorator; - this.taskExecutorCustomizers = taskExecutorCustomizers; + this.customizers = customizers; } /** @@ -98,7 +94,7 @@ public TaskExecutorBuilder(Integer queueCapacity, Integer corePoolSize, public TaskExecutorBuilder queueCapacity(int queueCapacity) { return new TaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, - this.taskDecorator, this.taskExecutorCustomizers); + this.taskDecorator, this.customizers); } /** @@ -113,7 +109,7 @@ public TaskExecutorBuilder queueCapacity(int queueCapacity) { public TaskExecutorBuilder corePoolSize(int corePoolSize) { return new TaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, - this.taskDecorator, this.taskExecutorCustomizers); + this.taskDecorator, this.customizers); } /** @@ -128,7 +124,7 @@ public TaskExecutorBuilder corePoolSize(int corePoolSize) { public TaskExecutorBuilder maxPoolSize(int maxPoolSize) { return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, - this.taskDecorator, this.taskExecutorCustomizers); + this.taskDecorator, this.customizers); } /** @@ -140,7 +136,7 @@ public TaskExecutorBuilder maxPoolSize(int maxPoolSize) { public TaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, allowCoreThreadTimeOut, this.keepAlive, - this.threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + this.threadNamePrefix, this.taskDecorator, this.customizers); } /** @@ -151,7 +147,7 @@ public TaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut public TaskExecutorBuilder keepAlive(Duration keepAlive) { return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, keepAlive, - this.threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + this.threadNamePrefix, this.taskDecorator, this.customizers); } /** @@ -162,7 +158,7 @@ public TaskExecutorBuilder keepAlive(Duration keepAlive) { public TaskExecutorBuilder threadNamePrefix(String threadNamePrefix) { return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, - threadNamePrefix, this.taskDecorator, this.taskExecutorCustomizers); + threadNamePrefix, this.taskDecorator, this.customizers); } /** @@ -173,7 +169,7 @@ public TaskExecutorBuilder threadNamePrefix(String threadNamePrefix) { public TaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) { return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, - this.threadNamePrefix, taskDecorator, this.taskExecutorCustomizers); + this.threadNamePrefix, taskDecorator, this.customizers); } /** @@ -181,15 +177,13 @@ public TaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) { * applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order * that they were added after builder configuration has been applied. Setting this * value will replace any previously configured customizers. - * @param taskExecutorCustomizers the customizers to set + * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskExecutorCustomizer...) */ - public TaskExecutorBuilder customizers( - TaskExecutorCustomizer... taskExecutorCustomizers) { - Assert.notNull(taskExecutorCustomizers, - "TaskExecutorCustomizers must not be null"); - return customizers(Arrays.asList(taskExecutorCustomizers)); + public TaskExecutorBuilder customizers(TaskExecutorCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return customizers(Arrays.asList(customizers)); } /** @@ -197,52 +191,46 @@ public TaskExecutorBuilder customizers( * applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order * that they were added after builder configuration has been applied. Setting this * value will replace any previously configured customizers. - * @param taskExecutorCustomizers the customizers to set + * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskExecutorCustomizer...) */ - public TaskExecutorBuilder customizers( - Collection taskExecutorCustomizers) { - Assert.notNull(taskExecutorCustomizers, - "TaskExecutorCustomizers must not be null"); + public TaskExecutorBuilder customizers(Iterable customizers) { + Assert.notNull(customizers, "Customizers must not be null"); return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, - this.threadNamePrefix, this.taskDecorator, - Collections.unmodifiableSet(new LinkedHashSet( - taskExecutorCustomizers))); + this.threadNamePrefix, this.taskDecorator, append(null, customizers)); } /** * Add {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be applied * to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order that * they were added after builder configuration has been applied. - * @param taskExecutorCustomizers the customizers to add + * @param customizers the customizers to add * @return a new builder instance * @see #customizers(TaskExecutorCustomizer...) */ public TaskExecutorBuilder additionalCustomizers( - TaskExecutorCustomizer... taskExecutorCustomizers) { - Assert.notNull(taskExecutorCustomizers, - "TaskExecutorCustomizers must not be null"); - return additionalCustomizers(Arrays.asList(taskExecutorCustomizers)); + TaskExecutorCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return additionalCustomizers(Arrays.asList(customizers)); } /** * Add {@link TaskExecutorCustomizer TaskExecutorCustomizers} that should be applied * to the {@link ThreadPoolTaskExecutor}. Customizers are applied in the order that * they were added after builder configuration has been applied. - * @param taskExecutorCustomizers the customizers to add + * @param customizers the customizers to add * @return a new builder instance * @see #customizers(TaskExecutorCustomizer...) */ public TaskExecutorBuilder additionalCustomizers( - Collection taskExecutorCustomizers) { - Assert.notNull(taskExecutorCustomizers, - "TaskExecutorCustomizers must not be null"); + Iterable customizers) { + Assert.notNull(customizers, "Customizers must not be null"); return new TaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize, this.allowCoreThreadTimeOut, this.keepAlive, this.threadNamePrefix, this.taskDecorator, - append(this.taskExecutorCustomizers, taskExecutorCustomizers)); + append(this.customizers, customizers)); } /** @@ -288,18 +276,15 @@ public T configure(T taskExecutor) { map.from(this.threadNamePrefix).whenHasText() .to(taskExecutor::setThreadNamePrefix); map.from(this.taskDecorator).to(taskExecutor::setTaskDecorator); - - if (!CollectionUtils.isEmpty(this.taskExecutorCustomizers)) { - for (TaskExecutorCustomizer customizer : this.taskExecutorCustomizers) { - customizer.customize(taskExecutor); - } + if (!CollectionUtils.isEmpty(this.customizers)) { + this.customizers.forEach((customizer) -> customizer.customize(taskExecutor)); } return taskExecutor; } - private static Set append(Set set, Collection additions) { + private Set append(Set set, Iterable additions) { Set result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); - result.addAll(additions); + additions.forEach(result::add); return Collections.unmodifiableSet(result); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java index ed4f71916c7a..ca8b74613ce0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/task/TaskSchedulerBuilder.java @@ -17,7 +17,6 @@ package org.springframework.boot.task; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; @@ -45,22 +44,19 @@ public class TaskSchedulerBuilder { private final String threadNamePrefix; - private final Set taskSchedulerCustomizers; + private final Set customizers; - public TaskSchedulerBuilder(TaskSchedulerCustomizer... taskSchedulerCustomizers) { - Assert.notNull(taskSchedulerCustomizers, - "TaskSchedulerCustomizers must not be null"); + public TaskSchedulerBuilder() { this.poolSize = null; this.threadNamePrefix = null; - this.taskSchedulerCustomizers = Collections.unmodifiableSet( - new LinkedHashSet<>(Arrays.asList(taskSchedulerCustomizers))); + this.customizers = null; } public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix, Set taskSchedulerCustomizers) { this.poolSize = poolSize; this.threadNamePrefix = threadNamePrefix; - this.taskSchedulerCustomizers = taskSchedulerCustomizers; + this.customizers = taskSchedulerCustomizers; } /** @@ -70,7 +66,7 @@ public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix, */ public TaskSchedulerBuilder poolSize(int poolSize) { return new TaskSchedulerBuilder(poolSize, this.threadNamePrefix, - this.taskSchedulerCustomizers); + this.customizers); } /** @@ -80,7 +76,7 @@ public TaskSchedulerBuilder poolSize(int poolSize) { */ public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) { return new TaskSchedulerBuilder(this.poolSize, threadNamePrefix, - this.taskSchedulerCustomizers); + this.customizers); } /** @@ -88,15 +84,13 @@ public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) { * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the * order that they were added after builder configuration has been applied. Setting * this value will replace any previously configured customizers. - * @param taskSchedulerCustomizers the customizers to set + * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskSchedulerCustomizer...) */ - public TaskSchedulerBuilder customizers( - TaskSchedulerCustomizer... taskSchedulerCustomizers) { - Assert.notNull(taskSchedulerCustomizers, - "TaskSchedulerCustomizers must not be null"); - return customizers(Arrays.asList(taskSchedulerCustomizers)); + public TaskSchedulerBuilder customizers(TaskSchedulerCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return customizers(Arrays.asList(customizers)); } /** @@ -104,48 +98,44 @@ public TaskSchedulerBuilder customizers( * applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the * order that they were added after builder configuration has been applied. Setting * this value will replace any previously configured customizers. - * @param taskSchedulerCustomizers the customizers to set + * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(TaskSchedulerCustomizer...) */ public TaskSchedulerBuilder customizers( - Collection taskSchedulerCustomizers) { - Assert.notNull(taskSchedulerCustomizers, - "TaskSchedulerCustomizers must not be null"); + Iterable customizers) { + Assert.notNull(customizers, "Customizers must not be null"); return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, - Collections.unmodifiableSet(new LinkedHashSet( - taskSchedulerCustomizers))); + append(null, customizers)); } /** * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that * they were added after builder configuration has been applied. - * @param taskSchedulerCustomizers the customizers to add + * @param customizers the customizers to add * @return a new builder instance * @see #customizers(TaskSchedulerCustomizer...) */ public TaskSchedulerBuilder additionalCustomizers( - TaskSchedulerCustomizer... taskSchedulerCustomizers) { - Assert.notNull(taskSchedulerCustomizers, - "TaskSchedulerCustomizers must not be null"); - return additionalCustomizers(Arrays.asList(taskSchedulerCustomizers)); + TaskSchedulerCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return additionalCustomizers(Arrays.asList(customizers)); } /** * Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied * to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that * they were added after builder configuration has been applied. - * @param taskSchedulerCustomizers the customizers to add + * @param customizers the customizers to add * @return a new builder instance * @see #customizers(TaskSchedulerCustomizer...) */ public TaskSchedulerBuilder additionalCustomizers( - Collection taskSchedulerCustomizers) { - Assert.notNull(taskSchedulerCustomizers, - "TaskSchedulerCustomizers must not be null"); + Iterable customizers) { + Assert.notNull(customizers, "Customizers must not be null"); return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, - append(this.taskSchedulerCustomizers, taskSchedulerCustomizers)); + append(this.customizers, customizers)); } /** @@ -169,18 +159,15 @@ public T configure(T taskScheduler) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this.poolSize).to(taskScheduler::setPoolSize); map.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix); - - if (!CollectionUtils.isEmpty(this.taskSchedulerCustomizers)) { - for (TaskSchedulerCustomizer customizer : this.taskSchedulerCustomizers) { - customizer.customize(taskScheduler); - } + if (!CollectionUtils.isEmpty(this.customizers)) { + this.customizers.forEach((customizer) -> customizer.customize(taskScheduler)); } return taskScheduler; } - private static Set append(Set set, Collection additions) { + private Set append(Set set, Iterable additions) { Set result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); - result.addAll(additions); + additions.forEach(result::add); return Collections.unmodifiableSet(result); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java index 506fcaa7eb41..b373c8b811cc 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskExecutorBuilderTests.java @@ -47,13 +47,6 @@ public class TaskExecutorBuilderTests { private TaskExecutorBuilder builder = new TaskExecutorBuilder(); - @Test - public void createWhenCustomizersAreNullShouldThrowException() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); - new TaskExecutorBuilder((TaskExecutorCustomizer[]) null); - } - @Test public void poolSettingsShouldApply() { ThreadPoolTaskExecutor executor = this.builder.queueCapacity(10).corePoolSize(4) @@ -85,14 +78,14 @@ public void taskDecoratorShouldApply() { @Test public void customizersWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.customizers((TaskExecutorCustomizer[]) null); } @Test public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.customizers((Set) null); } @@ -135,14 +128,14 @@ public void customizersShouldReplaceExisting() { @Test public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.additionalCustomizers((TaskExecutorCustomizer[]) null); } @Test public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskExecutorCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.additionalCustomizers((Set) null); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java index 39a9a5bf632a..8ae498b207dc 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/task/TaskSchedulerBuilderTests.java @@ -43,13 +43,6 @@ public class TaskSchedulerBuilderTests { private TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); - @Test - public void createWhenCustomizersAreNullShouldThrowException() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); - new TaskSchedulerBuilder((TaskSchedulerCustomizer[]) null); - } - @Test public void poolSettingsShouldApply() { ThreadPoolTaskScheduler scheduler = this.builder.poolSize(4).build(); @@ -66,14 +59,14 @@ public void threadNamePrefixShouldApply() { @Test public void customizersWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.customizers((TaskSchedulerCustomizer[]) null); } @Test public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.customizers((Set) null); } @@ -108,14 +101,14 @@ public void customizersShouldReplaceExisting() { @Test public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.additionalCustomizers((TaskSchedulerCustomizer[]) null); } @Test public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); + this.thrown.expectMessage("Customizers must not be null"); this.builder.additionalCustomizers((Set) null); } From 8c34e053f53a62a403d2f308dea1558a9461c476 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 5 Sep 2018 13:09:03 -0700 Subject: [PATCH 516/701] Update copyright header of changed files --- .../cache/HazelcastJCacheCustomizationConfiguration.java | 2 +- .../data/AbstractRepositoryConfigurationSourceSupport.java | 2 +- .../data/jpa/JpaRepositoriesAutoConfigureRegistrar.java | 2 +- .../autoconfigure/jms/JmsAnnotationDrivenConfiguration.java | 2 +- .../boot/autoconfigure/condition/ConditionalOnClassTests.java | 2 +- .../boot/autoconfigure/jmx/JmxAutoConfigurationTests.java | 2 +- .../security/oauth2/client/OAuth2ClientPropertiesTests.java | 2 +- .../autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java | 2 +- .../web/reactive/webclient/ExampleController1.java | 2 +- .../webclient/WebFluxTestAllControllersIntegrationTests.java | 2 +- .../context/properties/source/AbstractPropertyMapperTests.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java index 4168f217d7e8..2b578fb91236 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/HazelcastJCacheCustomizationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/AbstractRepositoryConfigurationSourceSupport.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/AbstractRepositoryConfigurationSourceSupport.java index 7b77aaf79c90..dacaabace75a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/AbstractRepositoryConfigurationSourceSupport.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/AbstractRepositoryConfigurationSourceSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigureRegistrar.java index 72ccde37e63f..be6c84322b3a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigureRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigureRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java index 9d77cb4d8202..cd6fe22a89db 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java index ebbcbbe898c9..eae706fa930d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java index a5e7c9670201..ff689da62c41 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java index 0b8f9cbe2710..61c65485417c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java index d1650ac5cf04..29449209b642 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java index b70e319437c0..f4a3152a1f14 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/ExampleController1.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java index c51b909175f8..a87af480e3c4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java index be1c9059e56c..1e2f67b82a30 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. From a170bfcc76cfb47b1c94481ccd35509eaa619b74 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 6 Sep 2018 14:19:23 +0200 Subject: [PATCH 517/701] Deprecate micrometer meter's enabled flags This commit deprecates the few 'enabled' flags that control whether certain meter binders are registered in the context. Metrics auto-configuration for the JVM, Logback and System-related information have been moved to individual auto-configurations so that they can be excluded rather than using the now deprecated flag. This harmonizes our policy with regards to disabling behaviour, especially since other similar auto-configurations do not have such flag. Closes gh-13408 --- .../metrics/JvmMetricsAutoConfiguration.java | 71 ++++++ .../LogbackMetricsAutoConfiguration.java | 80 ++++++ .../metrics/MetricsAutoConfiguration.java | 103 -------- .../SystemMetricsAutoConfiguration.java | 66 +++++ ...itional-spring-configuration-metadata.json | 28 ++- .../main/resources/META-INF/spring.factories | 3 + .../JvmMetricsAutoConfigurationTests.java | 147 +++++++++++ .../LogbackMetricsAutoConfigurationTests.java | 74 ++++++ ...terRegistryConfigurerIntegrationTests.java | 4 +- .../metrics/MeterRegistryCustomizerTests.java | 4 +- .../MetricsAutoConfigurationTests.java | 237 ------------------ .../SystemMetricsAutoConfigurationTests.java | 144 +++++++++++ .../metrics/test/MetricsIntegrationTests.java | 6 +- .../appendix-application-properties.adoc | 5 - 14 files changed, 619 insertions(+), 353 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java new file mode 100644 index 000000000000..206a8b45e70e --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for JVM metrics. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Configuration +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnClass(MeterRegistry.class) +@ConditionalOnBean(MeterRegistry.class) +@ConditionalOnProperty(value = "management.metrics.binders.jvm.enabled", matchIfMissing = true) +public class JvmMetricsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public JvmGcMetrics jvmGcMetrics() { + return new JvmGcMetrics(); + } + + @Bean + @ConditionalOnMissingBean + public JvmMemoryMetrics jvmMemoryMetrics() { + return new JvmMemoryMetrics(); + } + + @Bean + @ConditionalOnMissingBean + public JvmThreadMetrics jvmThreadMetrics() { + return new JvmThreadMetrics(); + } + + @Bean + @ConditionalOnMissingBean + public ClassLoaderMetrics classLoaderMetrics() { + return new ClassLoaderMetrics(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfiguration.java new file mode 100644 index 000000000000..528bc94ea79d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfiguration.java @@ -0,0 +1,80 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import ch.qos.logback.classic.LoggerContext; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.logging.LogbackMetrics; +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.actuate.autoconfigure.metrics.LogbackMetricsAutoConfiguration.LogbackLoggingCondition; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +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.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +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.core.type.AnnotatedTypeMetadata; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Logback metrics. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Configuration +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnClass({ MeterRegistry.class, LoggerContext.class, LoggerFactory.class }) +@ConditionalOnBean(MeterRegistry.class) +@Conditional(LogbackLoggingCondition.class) +@ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", matchIfMissing = true) +public class LogbackMetricsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LogbackMetrics logbackMetrics() { + return new LogbackMetrics(); + } + + static class LogbackLoggingCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); + ConditionMessage.Builder message = ConditionMessage + .forCondition("LogbackLoggingCondition"); + if (loggerFactory instanceof LoggerContext) { + return ConditionOutcome.match( + message.because("ILoggerFactory is a Logback LoggerContext")); + } + return ConditionOutcome + .noMatch(message.because("ILoggerFactory is an instance of " + + loggerFactory.getClass().getCanonicalName())); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index 6ee92c677942..f7b63aba3e74 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -16,36 +16,18 @@ package org.springframework.boot.actuate.autoconfigure.metrics; -import ch.qos.logback.classic.LoggerContext; import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; -import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; -import io.micrometer.core.instrument.binder.logging.LogbackMetrics; -import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; -import io.micrometer.core.instrument.binder.system.ProcessorMetrics; -import io.micrometer.core.instrument.binder.system.UptimeMetrics; -import org.slf4j.ILoggerFactory; -import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; 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.core.annotation.Order; -import org.springframework.core.type.AnnotatedTypeMetadata; /** * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics. @@ -78,89 +60,4 @@ public PropertiesMeterFilter propertiesMeterFilter(MetricsProperties properties) return new PropertiesMeterFilter(properties); } - @Configuration - @ConditionalOnProperty(value = "management.metrics.binders.jvm.enabled", matchIfMissing = true) - static class JvmMeterBindersConfiguration { - - @Bean - @ConditionalOnMissingBean - public JvmGcMetrics jvmGcMetrics() { - return new JvmGcMetrics(); - } - - @Bean - @ConditionalOnMissingBean - public JvmMemoryMetrics jvmMemoryMetrics() { - return new JvmMemoryMetrics(); - } - - @Bean - @ConditionalOnMissingBean - public JvmThreadMetrics jvmThreadMetrics() { - return new JvmThreadMetrics(); - } - - @Bean - @ConditionalOnMissingBean - public ClassLoaderMetrics classLoaderMetrics() { - return new ClassLoaderMetrics(); - } - - } - - @Configuration - static class MeterBindersConfiguration { - - @Bean - @ConditionalOnClass(name = { "ch.qos.logback.classic.LoggerContext", - "org.slf4j.LoggerFactory" }) - @Conditional(LogbackLoggingCondition.class) - @ConditionalOnMissingBean - @ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", matchIfMissing = true) - public LogbackMetrics logbackMetrics() { - return new LogbackMetrics(); - } - - @Bean - @ConditionalOnProperty(value = "management.metrics.binders.uptime.enabled", matchIfMissing = true) - @ConditionalOnMissingBean - public UptimeMetrics uptimeMetrics() { - return new UptimeMetrics(); - } - - @Bean - @ConditionalOnProperty(value = "management.metrics.binders.processor.enabled", matchIfMissing = true) - @ConditionalOnMissingBean - public ProcessorMetrics processorMetrics() { - return new ProcessorMetrics(); - } - - @Bean - @ConditionalOnProperty(name = "management.metrics.binders.files.enabled", matchIfMissing = true) - @ConditionalOnMissingBean - public FileDescriptorMetrics fileDescriptorMetrics() { - return new FileDescriptorMetrics(); - } - - } - - static class LogbackLoggingCondition extends SpringBootCondition { - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); - ConditionMessage.Builder message = ConditionMessage - .forCondition("LogbackLoggingCondition"); - if (loggerFactory instanceof LoggerContext) { - return ConditionOutcome.match( - message.because("ILoggerFactory is a Logback LoggerContext")); - } - return ConditionOutcome - .noMatch(message.because("ILoggerFactory is an instance of " - + loggerFactory.getClass().getCanonicalName())); - } - - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfiguration.java new file mode 100644 index 000000000000..6d306ae1242f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; +import io.micrometer.core.instrument.binder.system.ProcessorMetrics; +import io.micrometer.core.instrument.binder.system.UptimeMetrics; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for system metrics. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +@Configuration +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnClass(MeterRegistry.class) +@ConditionalOnBean(MeterRegistry.class) +public class SystemMetricsAutoConfiguration { + + @Bean + @ConditionalOnProperty(value = "management.metrics.binders.uptime.enabled", matchIfMissing = true) + @ConditionalOnMissingBean + public UptimeMetrics uptimeMetrics() { + return new UptimeMetrics(); + } + + @Bean + @ConditionalOnProperty(value = "management.metrics.binders.processor.enabled", matchIfMissing = true) + @ConditionalOnMissingBean + public ProcessorMetrics processorMetrics() { + return new ProcessorMetrics(); + } + + @Bean + @ConditionalOnProperty(name = "management.metrics.binders.files.enabled", matchIfMissing = true) + @ConditionalOnMissingBean + public FileDescriptorMetrics fileDescriptorMetrics() { + return new FileDescriptorMetrics(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 46ebcb59a8e9..98bf401aac46 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -192,31 +192,49 @@ "name": "management.metrics.binders.files.enabled", "type": "java.lang.Boolean", "description": "Whether to enable files metrics.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "management.metrics.enable.process.files", + "reason": "Instead, filter 'process.files' metrics." + } }, { "name": "management.metrics.binders.jvm.enabled", "type": "java.lang.Boolean", "description": "Whether to enable JVM metrics.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "management.metrics.enable.jvm", + "reason": "Instead, disable JvmMetricsAutoConfiguration or filter 'jvm' metrics." + } }, { "name": "management.metrics.binders.logback.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Logback metrics.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "management.metrics.enable.logback", + "reason": "Instead, disable LogbackMetricsAutoConfiguration or filter 'logback' metrics." + } }, { "name": "management.metrics.binders.processor.enabled", "type": "java.lang.Boolean", "description": "Whether to enable processor metrics.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "reason": "Instead, filter 'system.cpu' and 'process.cpu' metrics." + } }, { "name": "management.metrics.binders.uptime.enabled", "type": "java.lang.Boolean", "description": "Whether to enable uptime metrics.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "reason": "Instead, filter 'process.uptime' and 'process.start.time' metrics." + } }, { "name": "management.metrics.export.jmx.enabled", diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 5bc207067474..0109c40f12fb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -34,8 +34,11 @@ org.springframework.boot.actuate.autoconfigure.mail.MailHealthIndicatorAutoConfi org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.JvmMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.LogbackMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.MetricsEndpointAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.SystemMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..9b38f54bb5fb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfigurationTests.java @@ -0,0 +1,147 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link JvmMetricsAutoConfiguration}. + * + * @author Andy Wilkinson + * @author Stephane Nicoll + */ +public class JvmMetricsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()) + .withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class)); + + @Test + public void autoConfiguresJvmMetrics() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(JvmGcMetrics.class).hasSingleBean(JvmMemoryMetrics.class) + .hasSingleBean(JvmThreadMetrics.class) + .hasSingleBean(ClassLoaderMetrics.class)); + } + + @Test + @Deprecated + public void allowsJvmMetricsToBeDisabled() { + this.contextRunner + .withPropertyValues("management.metrics.binders.jvm.enabled=false") + .run((context) -> assertThat(context).doesNotHaveBean(JvmGcMetrics.class) + .doesNotHaveBean(JvmMemoryMetrics.class) + .doesNotHaveBean(JvmThreadMetrics.class) + .doesNotHaveBean(ClassLoaderMetrics.class)); + } + + @Test + public void allowsCustomJvmGcMetricsToBeUsed() { + this.contextRunner.withUserConfiguration(CustomJvmGcMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) + .hasBean("customJvmGcMetrics") + .hasSingleBean(JvmMemoryMetrics.class) + .hasSingleBean(JvmThreadMetrics.class) + .hasSingleBean(ClassLoaderMetrics.class)); + } + + @Test + public void allowsCustomJvmMemoryMetricsToBeUsed() { + this.contextRunner + .withUserConfiguration(CustomJvmMemoryMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) + .hasSingleBean(JvmMemoryMetrics.class) + .hasBean("customJvmMemoryMetrics") + .hasSingleBean(JvmThreadMetrics.class) + .hasSingleBean(ClassLoaderMetrics.class)); + } + + @Test + public void allowsCustomJvmThreadMetricsToBeUsed() { + this.contextRunner + .withUserConfiguration(CustomJvmThreadMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) + .hasSingleBean(JvmMemoryMetrics.class) + .hasSingleBean(JvmThreadMetrics.class) + .hasSingleBean(ClassLoaderMetrics.class) + .hasBean("customJvmThreadMetrics")); + } + + @Test + public void allowsCustomClassLoaderMetricsToBeUsed() { + this.contextRunner + .withUserConfiguration(CustomClassLoaderMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) + .hasSingleBean(JvmMemoryMetrics.class) + .hasSingleBean(JvmThreadMetrics.class) + .hasSingleBean(ClassLoaderMetrics.class) + .hasBean("customClassLoaderMetrics")); + } + + @Configuration + static class CustomJvmGcMetricsConfiguration { + + @Bean + public JvmGcMetrics customJvmGcMetrics() { + return new JvmGcMetrics(); + } + + } + + @Configuration + static class CustomJvmMemoryMetricsConfiguration { + + @Bean + public JvmMemoryMetrics customJvmMemoryMetrics() { + return new JvmMemoryMetrics(); + } + + } + + @Configuration + static class CustomJvmThreadMetricsConfiguration { + + @Bean + public JvmThreadMetrics customJvmThreadMetrics() { + return new JvmThreadMetrics(); + } + + } + + @Configuration + static class CustomClassLoaderMetricsConfiguration { + + @Bean + public ClassLoaderMetrics customClassLoaderMetrics() { + return new ClassLoaderMetrics(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..131027140fbb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/LogbackMetricsAutoConfigurationTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.logging.LogbackMetrics; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LogbackMetricsAutoConfiguration}. + * + * @author Andy Wilkinson + * @author Stephane Nicoll + */ +public class LogbackMetricsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()).withConfiguration( + AutoConfigurations.of(LogbackMetricsAutoConfiguration.class)); + + @Test + public void autoConfiguresLogbackMetrics() { + this.contextRunner.run( + (context) -> assertThat(context).hasSingleBean(LogbackMetrics.class)); + } + + @Test + @Deprecated + public void allowsLogbackMetricsToBeDisabled() { + this.contextRunner + .withPropertyValues("management.metrics.binders.logback.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(LogbackMetrics.class)); + } + + @Test + public void allowsCustomLogbackMetricsToBeUsed() { + this.contextRunner.withUserConfiguration(CustomLogbackMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(LogbackMetrics.class) + .hasBean("customLogbackMetrics")); + } + + @Configuration + static class CustomLogbackMetricsConfiguration { + + @Bean + public LogbackMetrics customLogbackMetrics() { + return new LogbackMetrics(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerIntegrationTests.java index 3836341a5fed..cc97942fe4a1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerIntegrationTests.java @@ -23,6 +23,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; /** @@ -34,7 +35,8 @@ public class MeterRegistryConfigurerIntegrationTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.limitedTo(AtlasMetricsExportAutoConfiguration.class, - PrometheusMetricsExportAutoConfiguration.class)); + PrometheusMetricsExportAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class)); @Test public void binderMetricsAreSearchableFromTheComposite() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryCustomizerTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryCustomizerTests.java index f28198c46b30..8b685473c89a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryCustomizerTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryCustomizerTests.java @@ -24,6 +24,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -40,7 +41,8 @@ public class MeterRegistryCustomizerTests { private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .with(MetricsRun.limitedTo(AtlasMetricsExportAutoConfiguration.class, - PrometheusMetricsExportAutoConfiguration.class)); + PrometheusMetricsExportAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class)); @Test public void commonTagsAreAppliedToAutoConfiguredBinders() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java index d77645a4fbc7..16a4b796303e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java @@ -21,14 +21,6 @@ import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.binder.MeterBinder; -import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; -import io.micrometer.core.instrument.binder.logging.LogbackMetrics; -import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; -import io.micrometer.core.instrument.binder.system.ProcessorMetrics; -import io.micrometer.core.instrument.binder.system.UptimeMetrics; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Test; @@ -83,155 +75,6 @@ public void configuresMeterRegistries() { }); } - @Test - public void autoConfiguresJvmMetrics() { - this.contextRunner.run((context) -> assertThat(context) - .hasSingleBean(JvmGcMetrics.class).hasSingleBean(JvmMemoryMetrics.class) - .hasSingleBean(JvmThreadMetrics.class) - .hasSingleBean(ClassLoaderMetrics.class)); - } - - @Test - public void allowsJvmMetricsToBeDisabled() { - this.contextRunner - .withPropertyValues("management.metrics.binders.jvm.enabled=false") - .run((context) -> assertThat(context).doesNotHaveBean(JvmGcMetrics.class) - .doesNotHaveBean(JvmMemoryMetrics.class) - .doesNotHaveBean(JvmThreadMetrics.class) - .doesNotHaveBean(ClassLoaderMetrics.class)); - } - - @Test - public void allowsCustomJvmGcMetricsToBeUsed() { - this.contextRunner.withUserConfiguration(CustomJvmGcMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) - .hasBean("customJvmGcMetrics") - .hasSingleBean(JvmMemoryMetrics.class) - .hasSingleBean(JvmThreadMetrics.class) - .hasSingleBean(ClassLoaderMetrics.class)); - } - - @Test - public void allowsCustomJvmMemoryMetricsToBeUsed() { - this.contextRunner - .withUserConfiguration(CustomJvmMemoryMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) - .hasSingleBean(JvmMemoryMetrics.class) - .hasBean("customJvmMemoryMetrics") - .hasSingleBean(JvmThreadMetrics.class) - .hasSingleBean(ClassLoaderMetrics.class)); - } - - @Test - public void allowsCustomJvmThreadMetricsToBeUsed() { - this.contextRunner - .withUserConfiguration(CustomJvmThreadMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) - .hasSingleBean(JvmMemoryMetrics.class) - .hasSingleBean(JvmThreadMetrics.class) - .hasSingleBean(ClassLoaderMetrics.class) - .hasBean("customJvmThreadMetrics")); - } - - @Test - public void allowsCustomClassLoaderMetricsToBeUsed() { - this.contextRunner - .withUserConfiguration(CustomClassLoaderMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class) - .hasSingleBean(JvmMemoryMetrics.class) - .hasSingleBean(JvmThreadMetrics.class) - .hasSingleBean(ClassLoaderMetrics.class) - .hasBean("customClassLoaderMetrics")); - } - - @Test - public void autoConfiguresLogbackMetrics() { - this.contextRunner.run( - (context) -> assertThat(context).hasSingleBean(LogbackMetrics.class)); - } - - @Test - public void allowsLogbackMetricsToBeDisabled() { - this.contextRunner - .withPropertyValues("management.metrics.binders.logback.enabled=false") - .run((context) -> assertThat(context) - .doesNotHaveBean(LogbackMetrics.class)); - } - - @Test - public void allowsCustomLogbackMetricsToBeUsed() { - this.contextRunner.withUserConfiguration(CustomLogbackMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(LogbackMetrics.class) - .hasBean("customLogbackMetrics")); - } - - @Test - public void autoConfiguresUptimeMetrics() { - this.contextRunner - .run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class)); - } - - @Test - public void allowsUptimeMetricsToBeDisabled() { - this.contextRunner - .withPropertyValues("management.metrics.binders.uptime.enabled=false") - .run((context) -> assertThat(context) - .doesNotHaveBean(UptimeMetrics.class)); - } - - @Test - public void allowsCustomUptimeMetricsToBeUsed() { - this.contextRunner.withUserConfiguration(CustomUptimeMetricsConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class) - .hasBean("customUptimeMetrics")); - } - - @Test - public void autoConfiguresProcessorMetrics() { - this.contextRunner.run( - (context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class)); - } - - @Test - public void allowsProcessorMetricsToBeDisabled() { - this.contextRunner - .withPropertyValues("management.metrics.binders.processor.enabled=false") - .run((context) -> assertThat(context) - .doesNotHaveBean(ProcessorMetrics.class)); - } - - @Test - public void allowsCustomProcessorMetricsToBeUsed() { - this.contextRunner - .withUserConfiguration(CustomProcessorMetricsConfiguration.class) - .run((context) -> assertThat(context) - .hasSingleBean(ProcessorMetrics.class) - .hasBean("customProcessorMetrics")); - } - - @Test - public void autoConfiguresFileDescriptorMetrics() { - this.contextRunner.run((context) -> assertThat(context) - .hasSingleBean(FileDescriptorMetrics.class)); - } - - @Test - public void allowsFileDescriptorMetricsToBeDisabled() { - this.contextRunner - .withPropertyValues("management.metrics.binders.files.enabled=false") - .run((context) -> assertThat(context) - .doesNotHaveBean(FileDescriptorMetrics.class)); - } - - @Test - public void allowsCustomFileDescriptorMetricsToBeUsed() { - this.contextRunner - .withUserConfiguration(CustomFileDescriptorMetricsConfiguration.class) - .run((context) -> assertThat(context) - .hasSingleBean(FileDescriptorMetrics.class) - .hasBean("customFileDescriptorMetrics")); - } - @Configuration static class CustomClockConfiguration { @@ -264,84 +107,4 @@ MeterBinder meterBinder() { } - @Configuration - static class CustomJvmGcMetricsConfiguration { - - @Bean - JvmGcMetrics customJvmGcMetrics() { - return new JvmGcMetrics(); - } - - } - - @Configuration - static class CustomJvmMemoryMetricsConfiguration { - - @Bean - JvmMemoryMetrics customJvmMemoryMetrics() { - return new JvmMemoryMetrics(); - } - - } - - @Configuration - static class CustomJvmThreadMetricsConfiguration { - - @Bean - JvmThreadMetrics customJvmThreadMetrics() { - return new JvmThreadMetrics(); - } - - } - - @Configuration - static class CustomClassLoaderMetricsConfiguration { - - @Bean - ClassLoaderMetrics customClassLoaderMetrics() { - return new ClassLoaderMetrics(); - } - - } - - @Configuration - static class CustomLogbackMetricsConfiguration { - - @Bean - LogbackMetrics customLogbackMetrics() { - return new LogbackMetrics(); - } - - } - - @Configuration - static class CustomUptimeMetricsConfiguration { - - @Bean - UptimeMetrics customUptimeMetrics() { - return new UptimeMetrics(); - } - - } - - @Configuration - static class CustomProcessorMetricsConfiguration { - - @Bean - ProcessorMetrics customProcessorMetrics() { - return new ProcessorMetrics(); - } - - } - - @Configuration - static class CustomFileDescriptorMetricsConfiguration { - - @Bean - FileDescriptorMetrics customFileDescriptorMetrics() { - return new FileDescriptorMetrics(); - } - - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..a54736b4d963 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/SystemMetricsAutoConfigurationTests.java @@ -0,0 +1,144 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; +import io.micrometer.core.instrument.binder.system.ProcessorMetrics; +import io.micrometer.core.instrument.binder.system.UptimeMetrics; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SystemMetricsAutoConfiguration}. + * + * @author Andy Wilkinson + * @author Stephane Nicoll + */ +public class SystemMetricsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()).withConfiguration( + AutoConfigurations.of(SystemMetricsAutoConfiguration.class)); + + @Test + public void autoConfiguresUptimeMetrics() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class)); + } + + @Test + @Deprecated + public void allowsUptimeMetricsToBeDisabled() { + this.contextRunner + .withPropertyValues("management.metrics.binders.uptime.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(UptimeMetrics.class)); + } + + @Test + public void allowsCustomUptimeMetricsToBeUsed() { + this.contextRunner.withUserConfiguration(CustomUptimeMetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class) + .hasBean("customUptimeMetrics")); + } + + @Test + public void autoConfiguresProcessorMetrics() { + this.contextRunner.run( + (context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class)); + } + + @Test + @Deprecated + public void allowsProcessorMetricsToBeDisabled() { + this.contextRunner + .withPropertyValues("management.metrics.binders.processor.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(ProcessorMetrics.class)); + } + + @Test + public void allowsCustomProcessorMetricsToBeUsed() { + this.contextRunner + .withUserConfiguration(CustomProcessorMetricsConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(ProcessorMetrics.class) + .hasBean("customProcessorMetrics")); + } + + @Test + public void autoConfiguresFileDescriptorMetrics() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(FileDescriptorMetrics.class)); + } + + @Test + @Deprecated + public void allowsFileDescriptorMetricsToBeDisabled() { + this.contextRunner + .withPropertyValues("management.metrics.binders.files.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(FileDescriptorMetrics.class)); + } + + @Test + public void allowsCustomFileDescriptorMetricsToBeUsed() { + this.contextRunner + .withUserConfiguration(CustomFileDescriptorMetricsConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(FileDescriptorMetrics.class) + .hasBean("customFileDescriptorMetrics")); + } + + @Configuration + static class CustomUptimeMetricsConfiguration { + + @Bean + public UptimeMetrics customUptimeMetrics() { + return new UptimeMetrics(); + } + + } + + @Configuration + static class CustomProcessorMetricsConfiguration { + + @Bean + public ProcessorMetrics customProcessorMetrics() { + return new ProcessorMetrics(); + } + + } + + @Configuration + static class CustomFileDescriptorMetricsConfiguration { + + @Bean + public FileDescriptorMetrics customFileDescriptorMetrics() { + return new FileDescriptorMetrics(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java index 60f5e5b04771..82d97372c4ec 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java @@ -34,7 +34,9 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.metrics.JvmMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.SystemMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; @@ -140,7 +142,9 @@ public void metricsFilterRegisteredForAsyncDispatches() { @Configuration @ImportAutoConfiguration({ MetricsAutoConfiguration.class, - RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, + JvmMetricsAutoConfiguration.class, LogbackMetrics.class, + SystemMetricsAutoConfiguration.class, RabbitMetricsAutoConfiguration.class, + CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, HibernateMetricsAutoConfiguration.class, HttpClientMetricsAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 7ff503a85690..79ff56cd0aa4 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1373,11 +1373,6 @@ content into your application. Rather, pick only the properties that you need. management.info.git.mode=simple # Mode to use to expose git information. # METRICS - management.metrics.binders.files.enabled=true # Whether to enable files metrics. - management.metrics.binders.jvm.enabled=true # Whether to enable JVM metrics. - management.metrics.binders.logback.enabled=true # Whether to enable Logback metrics. - management.metrics.binders.processor.enabled=true # Whether to enable processor metrics. - management.metrics.binders.uptime.enabled=true # Whether to enable uptime metrics. management.metrics.distribution.percentiles-histogram.*= # Whether meter IDs starting with the specified name should publish percentile histograms. management.metrics.distribution.percentiles.*= # Specific computed non-aggregable percentiles to ship to the backend for meter IDs starting-with the specified name. management.metrics.distribution.sla.*= # Specific SLA boundaries for meter IDs starting-with the specified name. The longest match wins, the key `all` can also be used to configure all meters. From f3ece97d9dfcf86a619f29869da88e2468939b01 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 6 Sep 2018 15:31:28 +0200 Subject: [PATCH 518/701] Add spring-framework.version alias for spring.version Closes gh-12544 --- spring-boot-project/spring-boot-dependencies/pom.xml | 6 ++++-- spring-boot-project/spring-boot-docs/pom.xml | 8 ++++---- .../src/main/asciidoc/getting-started.adoc | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2730355dd292..e1b2777174aa 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -156,11 +156,13 @@ 1.7.25 1.23 7.4.0 + 5.1.0.BUILD-SNAPSHOT 2.1.0.BUILD-SNAPSHOT 4.1.0.M3 2.0.2.RELEASE Lovelace-RC2 + ${spring.version} 0.25.0.RELEASE 5.1.0.M2 2.2.0.BUILD-SNAPSHOT @@ -2538,12 +2540,12 @@ org.springframework spring-core - ${spring.version} + ${spring-framework.version} org.springframework spring-framework-bom - ${spring.version} + ${spring-framework.version} import pom diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 99bb77f782ef..87f37123be4d 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -939,7 +939,7 @@ https://docs.oracle.com/javase/8/docs/api https://docs.oracle.com/javaee/7/api - https://docs.spring.io/spring-framework/docs/${spring.version}/javadoc-api + https://docs.spring.io/spring-framework/docs/${spring-framework.version}/javadoc-api https://docs.spring.io/spring-security/site/docs/${spring-security.version}/api https://tomcat.apache.org/tomcat-8.5-doc/api https://www.eclipse.org/jetty/javadoc/${jetty.version} @@ -1149,11 +1149,11 @@ true ${jooq.version} - ${spring.version} + ${spring-framework.version} ${revision} ${revision} ${spring-boot-repo} - ${spring.version} + ${spring-framework.version} ${spring-security.version} ${spring-ws.version} ${github-tag} @@ -1435,7 +1435,7 @@ org.springframework spring-core - ${spring.version} + ${spring-framework.version} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc index 90ce98f14695..ff6b50b31b44 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc @@ -39,7 +39,7 @@ configuration). [[getting-started-system-requirements]] == System Requirements Spring Boot {spring-boot-version} requires https://www.java.com[Java 8 or 9] and -{spring-reference}[Spring Framework {spring-version}] or above. +{spring-reference}[Spring Framework {spring-framework-version}] or above. Explicit build support is provided for the following build tools: From b97892ff88bfa0db654bb3da1e300755eabcada2 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 6 Sep 2018 11:35:59 +0200 Subject: [PATCH 519/701] Fix use of deprecated Mongo API We now use com.mongodb.MongoClientSettings to configure the reactive MongoDB driver. This is a breaking change as MongoClientSettingsBuilderCustomizer and user-provided MongoClientSettings beans referenced the package the settings type from com.mongodb.async.client. MongoClient.getSettings() is deprecated and still in use within tests until a replacement is available. See gh-14318 --- .../MongoClientSettingsBuilderCustomizer.java | 6 +- .../mongo/MongoReactiveAutoConfiguration.java | 2 +- .../mongo/ReactiveMongoClientFactory.java | 64 ++----------------- .../MongoReactiveAutoConfigurationTests.java | 10 +-- .../ReactiveMongoClientFactoryTests.java | 6 +- 5 files changed, 19 insertions(+), 69 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoClientSettingsBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoClientSettingsBuilderCustomizer.java index 432a316901c2..65cc3d094d6a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoClientSettingsBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoClientSettingsBuilderCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,11 +16,11 @@ package org.springframework.boot.autoconfigure.mongo; -import com.mongodb.async.client.MongoClientSettings.Builder; +import com.mongodb.MongoClientSettings.Builder; /** * Callback interface that can be implemented by beans wishing to customize the - * {@link com.mongodb.async.client.MongoClientSettings} via a {@link Builder + * {@link com.mongodb.MongoClientSettings} via a {@link Builder * MongoClientSettings.Builder} whilst retaining default auto-configuration. * * @author Mark Paluch diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java index de8ff484c6b2..503889532442 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java @@ -20,7 +20,7 @@ import javax.annotation.PreDestroy; -import com.mongodb.async.client.MongoClientSettings; +import com.mongodb.MongoClientSettings; import com.mongodb.connection.netty.NettyStreamFactoryFactory; import com.mongodb.reactivestreams.client.MongoClient; import io.netty.channel.socket.SocketChannel; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java index 2d9c20dc4975..1e35a54bc602 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java @@ -20,15 +20,10 @@ import java.util.List; import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoClientSettings.Builder; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; -import com.mongodb.async.client.MongoClientSettings; -import com.mongodb.async.client.MongoClientSettings.Builder; -import com.mongodb.connection.ClusterSettings; -import com.mongodb.connection.ConnectionPoolSettings; -import com.mongodb.connection.ServerSettings; -import com.mongodb.connection.SocketSettings; -import com.mongodb.connection.SslSettings; import com.mongodb.reactivestreams.client.MongoClient; import com.mongodb.reactivestreams.client.MongoClients; @@ -88,9 +83,8 @@ private MongoClient createEmbeddedMongoClient(MongoClientSettings settings, Builder builder = builder(settings); String host = (this.properties.getHost() != null) ? this.properties.getHost() : "localhost"; - ClusterSettings clusterSettings = ClusterSettings.builder() - .hosts(Collections.singletonList(new ServerAddress(host, port))).build(); - builder.clusterSettings(clusterSettings); + builder.applyToClusterSettings(cluster -> cluster + .hosts(Collections.singletonList(new ServerAddress(host, port)))); return createMongoClient(builder); } @@ -113,8 +107,8 @@ private MongoClient createCredentialNetworkMongoClient(MongoClientSettings setti String host = getOrDefault(this.properties.getHost(), "localhost"); int port = getOrDefault(this.properties.getPort(), MongoProperties.DEFAULT_PORT); ServerAddress serverAddress = new ServerAddress(host, port); - builder.clusterSettings(ClusterSettings.builder() - .hosts(Collections.singletonList(serverAddress)).build()); + builder.applyToClusterSettings( + cluster -> cluster.hosts(Collections.singletonList(serverAddress))); return createMongoClient(builder); } @@ -124,7 +118,6 @@ private void applyCredentials(Builder builder) { : this.properties.getMongoClientDatabase(); builder.credential((MongoCredential.createCredential( this.properties.getUsername(), database, this.properties.getPassword()))); - } private T getOrDefault(T value, T defaultValue) { @@ -138,50 +131,7 @@ private MongoClient createMongoClient(Builder builder) { private Builder createBuilder(MongoClientSettings settings, ConnectionString connection) { - Builder builder = builder(settings); - builder.clusterSettings(getClusterSettings(connection)); - builder.connectionPoolSettings(getConnectionPoolSettings(connection)); - builder.serverSettings(getServerSettings(connection)); - if (connection.getCredential() != null) { - builder.credential(connection.getCredential()); - } - builder.sslSettings(getSslSettings(connection)); - builder.socketSettings(getSocketSettings(connection)); - if (connection.getReadPreference() != null) { - builder.readPreference(connection.getReadPreference()); - } - if (connection.getReadConcern() != null) { - builder.readConcern(connection.getReadConcern()); - } - if (connection.getWriteConcern() != null) { - builder.writeConcern(connection.getWriteConcern()); - } - if (connection.getApplicationName() != null) { - builder.applicationName(connection.getApplicationName()); - } - builder.retryWrites(connection.getRetryWrites()); - return builder; - } - - private ClusterSettings getClusterSettings(ConnectionString connection) { - return ClusterSettings.builder().applyConnectionString(connection).build(); - } - - private ConnectionPoolSettings getConnectionPoolSettings( - ConnectionString connection) { - return ConnectionPoolSettings.builder().applyConnectionString(connection).build(); - } - - private ServerSettings getServerSettings(ConnectionString connection) { - return ServerSettings.builder().applyConnectionString(connection).build(); - } - - private SslSettings getSslSettings(ConnectionString connection) { - return SslSettings.builder().applyConnectionString(connection).build(); - } - - private SocketSettings getSocketSettings(ConnectionString connection) { - return SocketSettings.builder().applyConnectionString(connection).build(); + return builder(settings).applyConnectionString(connection); } private void customize(MongoClientSettings.Builder builder) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java index 1f32072df905..c430b69a080c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java @@ -18,10 +18,9 @@ import java.util.concurrent.TimeUnit; +import com.mongodb.MongoClientSettings; import com.mongodb.ReadPreference; -import com.mongodb.async.client.MongoClientSettings; import com.mongodb.connection.AsynchronousSocketChannelStreamFactoryFactory; -import com.mongodb.connection.SocketSettings; import com.mongodb.connection.StreamFactory; import com.mongodb.connection.StreamFactoryFactory; import com.mongodb.connection.netty.NettyStreamFactoryFactory; @@ -83,7 +82,8 @@ public void optionsSslConfig() { .withUserConfiguration(SslOptionsConfig.class).run((context) -> { assertThat(context).hasSingleBean(MongoClient.class); MongoClient mongo = context.getBean(MongoClient.class); - MongoClientSettings settings = mongo.getSettings(); + com.mongodb.async.client.MongoClientSettings settings = mongo + .getSettings(); assertThat(settings.getApplicationName()).isEqualTo("test-config"); assertThat(settings.getStreamFactoryFactory()) .isSameAs(context.getBean("myStreamFactoryFactory")); @@ -120,8 +120,8 @@ static class OptionsConfig { @Bean public MongoClientSettings mongoClientSettings() { return MongoClientSettings.builder().readPreference(ReadPreference.nearest()) - .socketSettings(SocketSettings.builder() - .readTimeout(300, TimeUnit.SECONDS).build()) + .applyToSocketSettings( + socket -> socket.readTimeout(300, TimeUnit.SECONDS)) .build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java index 3ea095b7470a..9751c9bc2eaf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java @@ -21,7 +21,7 @@ import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; -import com.mongodb.async.client.MongoClientSettings; +import com.mongodb.MongoClientSettings; import com.mongodb.connection.ClusterSettings; import com.mongodb.reactivestreams.client.MongoClient; import org.junit.Rule; @@ -196,13 +196,13 @@ private MongoClient createMongoClient(MongoProperties properties, } private List extractServerAddresses(MongoClient client) { - MongoClientSettings settings = client.getSettings(); + com.mongodb.async.client.MongoClientSettings settings = client.getSettings(); ClusterSettings clusterSettings = settings.getClusterSettings(); return clusterSettings.getHosts(); } private MongoCredential extractMongoCredentials(MongoClient client) { - MongoClientSettings settings = client.getSettings(); + com.mongodb.async.client.MongoClientSettings settings = client.getSettings(); return settings.getCredential(); } From 4d031999ce305db381a7affaeeb882294944ccd4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 6 Sep 2018 14:51:10 +0200 Subject: [PATCH 520/701] Polish "Fix use of deprecated Mongo API" Closes gh-14318 --- .../boot/autoconfigure/mongo/ReactiveMongoClientFactory.java | 4 ++-- .../mongo/MongoReactiveAutoConfigurationTests.java | 2 +- .../autoconfigure/mongo/ReactiveMongoClientFactoryTests.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java index 1e35a54bc602..5eb50e3d46f1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactory.java @@ -83,7 +83,7 @@ private MongoClient createEmbeddedMongoClient(MongoClientSettings settings, Builder builder = builder(settings); String host = (this.properties.getHost() != null) ? this.properties.getHost() : "localhost"; - builder.applyToClusterSettings(cluster -> cluster + builder.applyToClusterSettings((cluster) -> cluster .hosts(Collections.singletonList(new ServerAddress(host, port)))); return createMongoClient(builder); } @@ -108,7 +108,7 @@ private MongoClient createCredentialNetworkMongoClient(MongoClientSettings setti int port = getOrDefault(this.properties.getPort(), MongoProperties.DEFAULT_PORT); ServerAddress serverAddress = new ServerAddress(host, port); builder.applyToClusterSettings( - cluster -> cluster.hosts(Collections.singletonList(serverAddress))); + (cluster) -> cluster.hosts(Collections.singletonList(serverAddress))); return createMongoClient(builder); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java index c430b69a080c..fa065c49e684 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfigurationTests.java @@ -121,7 +121,7 @@ static class OptionsConfig { public MongoClientSettings mongoClientSettings() { return MongoClientSettings.builder().readPreference(ReadPreference.nearest()) .applyToSocketSettings( - socket -> socket.readTimeout(300, TimeUnit.SECONDS)) + (socket) -> socket.readTimeout(300, TimeUnit.SECONDS)) .build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java index 9751c9bc2eaf..5a9e30c3103c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/ReactiveMongoClientFactoryTests.java @@ -19,9 +19,9 @@ import java.util.Arrays; import java.util.List; +import com.mongodb.MongoClientSettings; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; -import com.mongodb.MongoClientSettings; import com.mongodb.connection.ClusterSettings; import com.mongodb.reactivestreams.client.MongoClient; import org.junit.Rule; From a32cd1965e68ef9f6c04bc3ecf064b559d83dd4b Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 6 Sep 2018 20:39:32 +0200 Subject: [PATCH 521/701] Switch to Reactor Californium-BUILD-SNAPSHOT In preparation for gh-14323 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e1b2777174aa..ea045f83a6b7 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -143,7 +143,7 @@ 2.3.0 4.2.1 5.4.1 - Californium-M2 + Californium-BUILD-SNAPSHOT 3.1.1 1.0.2 1.3.8 From 82b27c60a4268236f05462ca7f56e0b8d168b48a Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 5 Sep 2018 16:10:32 -0700 Subject: [PATCH 522/701] Drop MockitoPostProcessor factory method Remove factory method previously used to create the mock instance. Since commit 0e00a49dcc, the method is not longer needed. See gh-11077 --- .../mock/mockito/MockitoPostProcessor.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java index 1bafe45919d7..91f4b8cdac32 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java @@ -183,13 +183,11 @@ private void registerMock(ConfigurableListableBeanFactory beanFactory, RootBeanDefinition beanDefinition = createBeanDefinition(definition); String beanName = getBeanName(beanFactory, registry, definition, beanDefinition); String transformedBeanName = BeanFactoryUtils.transformedBeanName(beanName); - beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, - beanName); if (registry.containsBeanDefinition(transformedBeanName)) { registry.removeBeanDefinition(transformedBeanName); } registry.registerBeanDefinition(transformedBeanName, beanDefinition); - Object mock = createMock(definition, beanName); + Object mock = definition.createMock(beanName + " bean"); beanFactory.registerSingleton(transformedBeanName, mock); this.mockitoBeans.add(mock); this.beanNameRegistry.put(definition, beanName); @@ -202,26 +200,12 @@ private RootBeanDefinition createBeanDefinition(MockDefinition mockDefinition) { RootBeanDefinition definition = new RootBeanDefinition( mockDefinition.getTypeToMock().resolve()); definition.setTargetType(mockDefinition.getTypeToMock()); - definition.setFactoryBeanName(BEAN_NAME); - definition.setFactoryMethodName("createMock"); - definition.getConstructorArgumentValues().addIndexedArgumentValue(0, - mockDefinition); if (mockDefinition.getQualifier() != null) { mockDefinition.getQualifier().applyTo(definition); } return definition; } - /** - * Factory method used by defined beans to actually create the mock. - * @param mockDefinition the mock definition - * @param name the bean name - * @return the mock instance - */ - protected final Object createMock(MockDefinition mockDefinition, String name) { - return mockDefinition.createMock(name + " bean"); - } - private String getBeanName(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry, MockDefinition mockDefinition, RootBeanDefinition beanDefinition) { From c777614d8f3a1072b9e3d03acf6adf2f766f9e48 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 5 Sep 2018 16:30:05 -0700 Subject: [PATCH 523/701] Support @MockBean/@SpyBean with @Primary Update `MockitoPostProcessor` so that `@MockBean` and `@SpyBean` work consistently when combined with `@Primary`. See gh-11077 Co-authored-by: Andreas Neiser --- .../mock/mockito/MockitoPostProcessor.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java index 91f4b8cdac32..82112e6bc595 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java @@ -19,6 +19,7 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -184,6 +185,8 @@ private void registerMock(ConfigurableListableBeanFactory beanFactory, String beanName = getBeanName(beanFactory, registry, definition, beanDefinition); String transformedBeanName = BeanFactoryUtils.transformedBeanName(beanName); if (registry.containsBeanDefinition(transformedBeanName)) { + BeanDefinition existing = registry.getBeanDefinition(transformedBeanName); + copyBeanDefinitionDetails(existing, beanDefinition); registry.removeBeanDefinition(transformedBeanName); } registry.registerBeanDefinition(transformedBeanName, beanDefinition); @@ -196,6 +199,10 @@ private void registerMock(ConfigurableListableBeanFactory beanFactory, } } + private void copyBeanDefinitionDetails(BeanDefinition from, RootBeanDefinition to) { + to.setPrimary(from.isPrimary()); + } + private RootBeanDefinition createBeanDefinition(MockDefinition mockDefinition) { RootBeanDefinition definition = new RootBeanDefinition( mockDefinition.getTypeToMock().resolve()); @@ -212,13 +219,19 @@ private String getBeanName(ConfigurableListableBeanFactory beanFactory, if (StringUtils.hasLength(mockDefinition.getName())) { return mockDefinition.getName(); } - Set existingBeans = findCandidateBeans(beanFactory, mockDefinition); + Set existingBeans = findCandidateBeans(beanFactory, + mockDefinition.getTypeToMock(), mockDefinition.getQualifier()); if (existingBeans.isEmpty()) { return this.beanNameGenerator.generateBeanName(beanDefinition, registry); } if (existingBeans.size() == 1) { return existingBeans.iterator().next(); } + String primaryCandidate = determinePrimaryCandidate(registry, existingBeans, + mockDefinition.getTypeToMock()); + if (primaryCandidate != null) { + return primaryCandidate; + } throw new IllegalStateException( "Unable to register mock bean " + mockDefinition.getTypeToMock() + " expected a single matching bean to replace but found " @@ -226,22 +239,21 @@ private String getBeanName(ConfigurableListableBeanFactory beanFactory, } private void registerSpy(ConfigurableListableBeanFactory beanFactory, - BeanDefinitionRegistry registry, SpyDefinition definition, Field field) { - String[] existingBeans = getExistingBeans(beanFactory, definition.getTypeToSpy()); + BeanDefinitionRegistry registry, SpyDefinition spyDefinition, Field field) { + Set existingBeans = findCandidateBeans(beanFactory, + spyDefinition.getTypeToSpy(), spyDefinition.getQualifier()); if (ObjectUtils.isEmpty(existingBeans)) { - createSpy(registry, definition, field); + createSpy(registry, spyDefinition, field); } else { - registerSpies(registry, definition, field, existingBeans); + registerSpies(registry, spyDefinition, field, existingBeans); } } private Set findCandidateBeans(ConfigurableListableBeanFactory beanFactory, - MockDefinition mockDefinition) { - QualifierDefinition qualifier = mockDefinition.getQualifier(); + ResolvableType type, QualifierDefinition qualifier) { Set candidates = new TreeSet<>(); - for (String candidate : getExistingBeans(beanFactory, - mockDefinition.getTypeToMock())) { + for (String candidate : getExistingBeans(beanFactory, type)) { if (qualifier == null || qualifier.matches(beanFactory, candidate)) { candidates.add(candidate); } @@ -249,7 +261,7 @@ private Set findCandidateBeans(ConfigurableListableBeanFactory beanFacto return candidates; } - private String[] getExistingBeans(ConfigurableListableBeanFactory beanFactory, + private Set getExistingBeans(ConfigurableListableBeanFactory beanFactory, ResolvableType type) { Set beans = new LinkedHashSet<>( Arrays.asList(beanFactory.getBeanNamesForType(type))); @@ -263,7 +275,7 @@ private String[] getExistingBeans(ConfigurableListableBeanFactory beanFactory, } } beans.removeIf(this::isScopedTarget); - return StringUtils.toStringArray(beans); + return beans; } private boolean isScopedTarget(String beanName) { @@ -275,49 +287,49 @@ private boolean isScopedTarget(String beanName) { } } - private void createSpy(BeanDefinitionRegistry registry, SpyDefinition definition, + private void createSpy(BeanDefinitionRegistry registry, SpyDefinition spyDefinition, Field field) { RootBeanDefinition beanDefinition = new RootBeanDefinition( - definition.getTypeToSpy().resolve()); + spyDefinition.getTypeToSpy().resolve()); String beanName = this.beanNameGenerator.generateBeanName(beanDefinition, registry); registry.registerBeanDefinition(beanName, beanDefinition); - registerSpy(definition, field, beanName); + registerSpy(spyDefinition, field, beanName); } - private void registerSpies(BeanDefinitionRegistry registry, SpyDefinition definition, - Field field, String[] existingBeans) { + private void registerSpies(BeanDefinitionRegistry registry, + SpyDefinition spyDefinition, Field field, Collection existingBeans) { try { - registerSpy(definition, field, - determineBeanName(existingBeans, definition, registry)); + String beanName = determineBeanName(existingBeans, spyDefinition, registry); + registerSpy(spyDefinition, field, beanName); } catch (RuntimeException ex) { throw new IllegalStateException( - "Unable to register spy bean " + definition.getTypeToSpy(), ex); + "Unable to register spy bean " + spyDefinition.getTypeToSpy(), ex); } } - private String determineBeanName(String[] existingBeans, SpyDefinition definition, - BeanDefinitionRegistry registry) { + private String determineBeanName(Collection existingBeans, + SpyDefinition definition, BeanDefinitionRegistry registry) { if (StringUtils.hasText(definition.getName())) { return definition.getName(); } - if (existingBeans.length == 1) { - return existingBeans[0]; + if (existingBeans.size() == 1) { + return existingBeans.iterator().next(); } return determinePrimaryCandidate(registry, existingBeans, definition.getTypeToSpy()); } private String determinePrimaryCandidate(BeanDefinitionRegistry registry, - String[] candidateBeanNames, ResolvableType type) { + Collection candidateBeanNames, ResolvableType type) { String primaryBeanName = null; for (String candidateBeanName : candidateBeanNames) { BeanDefinition beanDefinition = registry.getBeanDefinition(candidateBeanName); if (beanDefinition.isPrimary()) { if (primaryBeanName != null) { throw new NoUniqueBeanDefinitionException(type.resolve(), - candidateBeanNames.length, + candidateBeanNames.size(), "more than one 'primary' bean found among candidates: " + Arrays.asList(candidateBeanNames)); } From a5b3a2646bd90bde4fd9b8fa86a3cddaac7ed844 Mon Sep 17 00:00:00 2001 From: Andreas Neiser Date: Wed, 5 Sep 2018 14:14:14 -0700 Subject: [PATCH 524/701] Test @MockBean/@SpyBean with @Primary Add additional tests to ensure that `@MockBean` and `@SpyBean` work consistently when combined with `@Primary`. See gh-11077 --- .../mockito/MockitoPostProcessorTests.java | 159 +++++++++++++++++- ...tingBeanWithQualifierIntegrationTests.java | 89 ++++++++++ 2 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyBeanOnTestFieldForExistingBeanWithQualifierIntegrationTests.java diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java index 1a3c426b5b49..35cf78c1cbab 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -26,9 +26,11 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.test.mock.mockito.example.ExampleService; import org.springframework.boot.test.mock.mockito.example.FailingExampleService; +import org.springframework.boot.test.mock.mockito.example.RealExampleService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import static org.assertj.core.api.Assertions.assertThat; @@ -84,6 +86,79 @@ public void canMockBeanProducedByFactoryBeanWithObjectTypeAttribute() { .isTrue(); } + @Test + public void canMockPrimaryBean() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + MockitoPostProcessor.register(context); + context.register(MockPrimaryBean.class); + context.refresh(); + assertThat(Mockito.mockingDetails(context.getBean(MockPrimaryBean.class).mock) + .isMock()).isTrue(); + assertThat(Mockito.mockingDetails(context.getBean(ExampleService.class)).isMock()) + .isTrue(); + assertThat(Mockito + .mockingDetails(context.getBean("examplePrimary", ExampleService.class)) + .isMock()).isTrue(); + assertThat(Mockito + .mockingDetails(context.getBean("exampleQualified", ExampleService.class)) + .isMock()).isFalse(); + } + + @Test + public void canMockQualifiedBeanWithPrimaryBeanPresent() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + MockitoPostProcessor.register(context); + context.register(MockQualifiedBean.class); + context.refresh(); + assertThat(Mockito.mockingDetails(context.getBean(MockQualifiedBean.class).mock) + .isMock()).isTrue(); + assertThat(Mockito.mockingDetails(context.getBean(ExampleService.class)).isMock()) + .isFalse(); + assertThat(Mockito + .mockingDetails(context.getBean("examplePrimary", ExampleService.class)) + .isMock()).isFalse(); + assertThat(Mockito + .mockingDetails(context.getBean("exampleQualified", ExampleService.class)) + .isMock()).isTrue(); + } + + @Test + public void canSpyPrimaryBean() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + MockitoPostProcessor.register(context); + context.register(SpyPrimaryBean.class); + context.refresh(); + assertThat( + Mockito.mockingDetails(context.getBean(SpyPrimaryBean.class).spy).isSpy()) + .isTrue(); + assertThat(Mockito.mockingDetails(context.getBean(ExampleService.class)).isSpy()) + .isTrue(); + assertThat(Mockito + .mockingDetails(context.getBean("examplePrimary", ExampleService.class)) + .isSpy()).isTrue(); + assertThat(Mockito + .mockingDetails(context.getBean("exampleQualified", ExampleService.class)) + .isSpy()).isFalse(); + } + + @Test + public void canSpyQualifiedBeanWithPrimaryBeanPresent() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + MockitoPostProcessor.register(context); + context.register(SpyQualifiedBean.class); + context.refresh(); + assertThat(Mockito.mockingDetails(context.getBean(SpyQualifiedBean.class).spy) + .isSpy()).isTrue(); + assertThat(Mockito.mockingDetails(context.getBean(ExampleService.class)).isSpy()) + .isFalse(); + assertThat(Mockito + .mockingDetails(context.getBean("examplePrimary", ExampleService.class)) + .isSpy()).isFalse(); + assertThat(Mockito + .mockingDetails(context.getBean("exampleQualified", ExampleService.class)) + .isSpy()).isTrue(); + } + @Configuration @MockBean(SomeInterface.class) static class MockedFactoryBean { @@ -137,6 +212,88 @@ public ExampleService example3() { } + @Configuration + static class MockPrimaryBean { + + @MockBean(ExampleService.class) + private ExampleService mock; + + @Bean + @Qualifier("test") + public ExampleService exampleQualified() { + return new RealExampleService("qualified"); + } + + @Bean + @Primary + public ExampleService examplePrimary() { + return new RealExampleService("primary"); + } + + } + + @Configuration + static class MockQualifiedBean { + + @MockBean(ExampleService.class) + @Qualifier("test") + private ExampleService mock; + + @Bean + @Qualifier("test") + public ExampleService exampleQualified() { + return new RealExampleService("qualified"); + } + + @Bean + @Primary + public ExampleService examplePrimary() { + return new RealExampleService("primary"); + } + + } + + @Configuration + static class SpyPrimaryBean { + + @SpyBean(ExampleService.class) + private ExampleService spy; + + @Bean + @Qualifier("test") + public ExampleService exampleQualified() { + return new RealExampleService("qualified"); + } + + @Bean + @Primary + public ExampleService examplePrimary() { + return new RealExampleService("primary"); + } + + } + + @Configuration + static class SpyQualifiedBean { + + @SpyBean(ExampleService.class) + @Qualifier("test") + private ExampleService spy; + + @Bean + @Qualifier("test") + public ExampleService exampleQualified() { + return new RealExampleService("qualified"); + } + + @Bean + @Primary + public ExampleService examplePrimary() { + return new RealExampleService("primary"); + } + + } + static class TestFactoryBean implements FactoryBean { @Override diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyBeanOnTestFieldForExistingBeanWithQualifierIntegrationTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyBeanOnTestFieldForExistingBeanWithQualifierIntegrationTests.java new file mode 100644 index 000000000000..d60f206a458d --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyBeanOnTestFieldForExistingBeanWithQualifierIntegrationTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2018 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.test.mock.mockito; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.example.CustomQualifier; +import org.springframework.boot.test.mock.mockito.example.CustomQualifierExampleService; +import org.springframework.boot.test.mock.mockito.example.ExampleService; +import org.springframework.boot.test.mock.mockito.example.ExampleServiceCaller; +import org.springframework.boot.test.mock.mockito.example.RealExampleService; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; + +/** + * Test {@link SpyBean} on a test class field can be used to replace existing bean while + * preserving qualifiers. + * + * @author Andreas Neiser + */ +@RunWith(SpringRunner.class) +public class SpyBeanOnTestFieldForExistingBeanWithQualifierIntegrationTests { + + @SpyBean + @CustomQualifier + private ExampleService service; + + @Autowired + private ExampleServiceCaller caller; + + @Autowired + private ApplicationContext applicationContext; + + @Test + public void testMocking() throws Exception { + this.caller.sayGreeting(); + verify(this.service).greeting(); + } + + @Test + public void onlyQualifiedBeanIsReplaced() { + assertThat(this.applicationContext.getBean("service")).isSameAs(this.service); + ExampleService anotherService = this.applicationContext.getBean("anotherService", + ExampleService.class); + assertThat(anotherService.greeting()).isEqualTo("Another"); + } + + @Configuration + static class TestConfig { + + @Bean + public CustomQualifierExampleService service() { + return new CustomQualifierExampleService(); + } + + @Bean + public ExampleService anotherService() { + return new RealExampleService("Another"); + } + + @Bean + public ExampleServiceCaller controller(@CustomQualifier ExampleService service) { + return new ExampleServiceCaller(service); + } + + } + +} From bc357225b57f442c6988a5f16a7aa9b53790a866 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 6 Sep 2018 12:47:25 -0700 Subject: [PATCH 525/701] Polish MockitoPostProcessor Closes gh-11077 --- .../mock/mockito/MockitoPostProcessor.java | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java index 82112e6bc595..851ca6fcec4b 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java @@ -86,14 +86,14 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda .getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass"); + private static final BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator(); + private final Set definitions; private ClassLoader classLoader; private BeanFactory beanFactory; - private final BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator(); - private final MockitoBeans mockitoBeans = new MockitoBeans(); private Map beanNameRegistry = new HashMap<>(); @@ -199,10 +199,6 @@ private void registerMock(ConfigurableListableBeanFactory beanFactory, } } - private void copyBeanDefinitionDetails(BeanDefinition from, RootBeanDefinition to) { - to.setPrimary(from.isPrimary()); - } - private RootBeanDefinition createBeanDefinition(MockDefinition mockDefinition) { RootBeanDefinition definition = new RootBeanDefinition( mockDefinition.getTypeToMock().resolve()); @@ -219,10 +215,11 @@ private String getBeanName(ConfigurableListableBeanFactory beanFactory, if (StringUtils.hasLength(mockDefinition.getName())) { return mockDefinition.getName(); } - Set existingBeans = findCandidateBeans(beanFactory, + Set existingBeans = getExistingBeans(beanFactory, mockDefinition.getTypeToMock(), mockDefinition.getQualifier()); if (existingBeans.isEmpty()) { - return this.beanNameGenerator.generateBeanName(beanDefinition, registry); + return MockitoPostProcessor.beanNameGenerator.generateBeanName(beanDefinition, + registry); } if (existingBeans.size() == 1) { return existingBeans.iterator().next(); @@ -238,9 +235,13 @@ private String getBeanName(ConfigurableListableBeanFactory beanFactory, + existingBeans); } + private void copyBeanDefinitionDetails(BeanDefinition from, RootBeanDefinition to) { + to.setPrimary(from.isPrimary()); + } + private void registerSpy(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry, SpyDefinition spyDefinition, Field field) { - Set existingBeans = findCandidateBeans(beanFactory, + Set existingBeans = getExistingBeans(beanFactory, spyDefinition.getTypeToSpy(), spyDefinition.getQualifier()); if (ObjectUtils.isEmpty(existingBeans)) { createSpy(registry, spyDefinition, field); @@ -250,7 +251,7 @@ private void registerSpy(ConfigurableListableBeanFactory beanFactory, } } - private Set findCandidateBeans(ConfigurableListableBeanFactory beanFactory, + private Set getExistingBeans(ConfigurableListableBeanFactory beanFactory, ResolvableType type, QualifierDefinition qualifier) { Set candidates = new TreeSet<>(); for (String candidate : getExistingBeans(beanFactory, type)) { @@ -265,12 +266,11 @@ private Set getExistingBeans(ConfigurableListableBeanFactory beanFactory ResolvableType type) { Set beans = new LinkedHashSet<>( Arrays.asList(beanFactory.getBeanNamesForType(type))); - String resolvedTypeName = type.resolve(Object.class).getName(); + String typeName = type.resolve(Object.class).getName(); for (String beanName : beanFactory.getBeanNamesForType(FactoryBean.class)) { beanName = BeanFactoryUtils.transformedBeanName(beanName); BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); - if (resolvedTypeName - .equals(beanDefinition.getAttribute(FACTORY_BEAN_OBJECT_TYPE))) { + if (typeName.equals(beanDefinition.getAttribute(FACTORY_BEAN_OBJECT_TYPE))) { beans.add(beanName); } } @@ -291,8 +291,8 @@ private void createSpy(BeanDefinitionRegistry registry, SpyDefinition spyDefinit Field field) { RootBeanDefinition beanDefinition = new RootBeanDefinition( spyDefinition.getTypeToSpy().resolve()); - String beanName = this.beanNameGenerator.generateBeanName(beanDefinition, - registry); + String beanName = MockitoPostProcessor.beanNameGenerator + .generateBeanName(beanDefinition, registry); registry.registerBeanDefinition(beanName, beanDefinition); registerSpy(spyDefinition, field, beanName); } @@ -347,7 +347,7 @@ private void registerSpy(SpyDefinition definition, Field field, String beanName) } } - protected Object createSpyIfNecessary(Object bean, String beanName) + protected final Object createSpyIfNecessary(Object bean, String beanName) throws BeansException { SpyDefinition definition = this.spies.get(beanName); if (definition != null) { @@ -476,7 +476,7 @@ public int getOrder() { @Override public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { - return createSpyIfNecessary(bean, beanName); + return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName); } @Override @@ -485,10 +485,6 @@ public Object postProcessAfterInitialization(Object bean, String beanName) if (bean instanceof FactoryBean) { return bean; } - return createSpyIfNecessary(bean, beanName); - } - - private Object createSpyIfNecessary(Object bean, String beanName) { return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName); } From 04710373bf3c1a88cf829f52697750f30aa80c23 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 6 Sep 2018 13:42:29 -0700 Subject: [PATCH 526/701] Add @Author attribution See gh-11077 --- .../boot/test/mock/mockito/MockitoPostProcessor.java | 1 + .../boot/test/mock/mockito/MockitoPostProcessorTests.java | 1 + 2 files changed, 2 insertions(+) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java index 851ca6fcec4b..0c1720e87951 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java @@ -72,6 +72,7 @@ * @author Phillip Webb * @author Andy Wilkinson * @author Stephane Nicoll + * @author Andreas Neiser * @since 1.4.0 */ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAdapter diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java index 35cf78c1cbab..88d4ccbf3dee 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java @@ -39,6 +39,7 @@ * * @author Phillip Webb * @author Andy Wilkinson + * @author Andreas Neiser */ public class MockitoPostProcessorTests { From 5e83192d7decfd2364b0fec2533745172a0647d5 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 7 Sep 2018 09:07:40 +0200 Subject: [PATCH 527/701] Upgrade to Reactor Californium RC1 Closes gh-14323 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index ea045f83a6b7..c90b23be63ac 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -143,7 +143,7 @@ 2.3.0 4.2.1 5.4.1 - Californium-BUILD-SNAPSHOT + Californium-RC1 3.1.1 1.0.2 1.3.8 From 49b4913d48b27554a77ce79c68d728dfd1140595 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 7 Sep 2018 15:44:09 +0200 Subject: [PATCH 528/701] Upgrade to Spring Framework 5.1.0.RC3 Closes gh-14324 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c90b23be63ac..2e4d2d2b5b25 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 1.23 7.4.0 - 5.1.0.BUILD-SNAPSHOT + 5.1.0.RC3 2.1.0.BUILD-SNAPSHOT 4.1.0.M3 2.0.2.RELEASE From 91e731a4b4539e7b61211f3580f982f23bbffb8d Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Thu, 30 Aug 2018 14:02:44 +0300 Subject: [PATCH 529/701] Add support for configuring missingQueuesFatal property See gh-14252 --- ...bitListenerContainerFactoryConfigurer.java | 2 ++ .../autoconfigure/amqp/RabbitProperties.java | 29 +++++++++++++++++++ ...bitListenerContainerFactoryConfigurer.java | 2 ++ .../amqp/RabbitAutoConfigurationTests.java | 3 ++ .../appendix-application-properties.adoc | 2 ++ 5 files changed, 38 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java index d3cd82b5300b..67c1fe9cea65 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java @@ -40,6 +40,8 @@ public void configure(DirectRabbitListenerContainerFactory factory, configure(factory, connectionFactory, config); map.from(config::getConsumersPerQueue).whenNonNull() .to(factory::setConsumersPerQueue); + map.from(config::getMissingQueuesFatal).whenNonNull() + .to(factory::setMissingQueuesFatal); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index 1a6cc3ffee92..327686cbcb79 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -665,6 +665,13 @@ public static class SimpleContainer extends AmqpContainer { */ private Integer transactionSize; + /** + * Whether the context should be ended up with failure if there are no any queues + * available on the broker or the container should be stopped if queues have been + * removed while the container is running. + */ + private Boolean missingQueuesFatal; + public Integer getConcurrency() { return this.concurrency; } @@ -689,6 +696,14 @@ public void setTransactionSize(Integer transactionSize) { this.transactionSize = transactionSize; } + public Boolean getMissingQueuesFatal() { + return this.missingQueuesFatal; + } + + public void setMissingQueuesFatal(Boolean missingQueuesFatal) { + this.missingQueuesFatal = missingQueuesFatal; + } + } /** @@ -701,6 +716,12 @@ public static class DirectContainer extends AmqpContainer { */ private Integer consumersPerQueue; + /** + * Whether the context should be ended up with failure if there are no any queues + * available on the broker. + */ + private Boolean missingQueuesFatal; + public Integer getConsumersPerQueue() { return this.consumersPerQueue; } @@ -709,6 +730,14 @@ public void setConsumersPerQueue(Integer consumersPerQueue) { this.consumersPerQueue = consumersPerQueue; } + public Boolean getMissingQueuesFatal() { + return this.missingQueuesFatal; + } + + public void setMissingQueuesFatal(Boolean missingQueuesFatal) { + this.missingQueuesFatal = missingQueuesFatal; + } + } public static class Template { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java index 6321fab6090f..017722763cd9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java @@ -43,6 +43,8 @@ public void configure(SimpleRabbitListenerContainerFactory factory, map.from(config::getMaxConcurrency).whenNonNull() .to(factory::setMaxConcurrentConsumers); map.from(config::getTransactionSize).whenNonNull().to(factory::setTxSize); + map.from(config::getMissingQueuesFatal).whenNonNull() + .to(factory::setMissingQueuesFatal); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index 73b66d3ede76..721e0f6aca65 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -468,6 +468,7 @@ public void testSimpleRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.simple.maxConcurrency:10", "spring.rabbitmq.listener.simple.prefetch:40", "spring.rabbitmq.listener.simple.defaultRequeueRejected:false", + "spring.rabbitmq.listener.simple.missingQueuesFatal:false", "spring.rabbitmq.listener.simple.idleEventInterval:5", "spring.rabbitmq.listener.simple.transactionSize:20") .run((context) -> { @@ -500,6 +501,7 @@ public void testDirectRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.direct.consumers-per-queue:5", "spring.rabbitmq.listener.direct.prefetch:40", "spring.rabbitmq.listener.direct.defaultRequeueRejected:false", + "spring.rabbitmq.listener.direct.missingQueuesFatal:false", "spring.rabbitmq.listener.direct.idleEventInterval:5") .run((context) -> { DirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context @@ -621,6 +623,7 @@ private void checkCommonProps(AssertableApplicationContext context, assertThat(dfa.getPropertyValue("prefetchCount")).isEqualTo(40); assertThat(dfa.getPropertyValue("messageConverter")) .isSameAs(context.getBean("myMessageConverter")); + assertThat(dfa.getPropertyValue("missingQueuesFatal")).isEqualTo(false); assertThat(dfa.getPropertyValue("defaultRequeueRejected")) .isEqualTo(Boolean.FALSE); assertThat(dfa.getPropertyValue("idleEventInterval")).isEqualTo(5L); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 846f23e0e79d..e99e7e16f94f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1137,6 +1137,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.direct.consumers-per-queue= # Number of consumers per queue. spring.rabbitmq.listener.direct.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.direct.idle-event-interval= # How often idle container events should be published. + spring.rabbitmq.listener.direct.missing-queues-fatal= # Whether the context should be ended up with failure if there are no any queues available on the broker. spring.rabbitmq.listener.direct.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.direct.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.direct.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. @@ -1150,6 +1151,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.simple.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.simple.idle-event-interval= # How often idle container events should be published. spring.rabbitmq.listener.simple.max-concurrency= # Maximum number of listener invoker threads. + spring.rabbitmq.listener.simple.missing-queues-fatal= # Whether the context should be ended up with failure if there are no any queues available on the broker or the container should be stopped if queues have been removed while the container is running. spring.rabbitmq.listener.simple.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.simple.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.simple.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. From c1322a543ce426f1daa71c9a9f30d051347b6e46 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 7 Sep 2018 11:56:58 +0200 Subject: [PATCH 530/701] Polish "Add support for configuring missingQueuesFatal property" Closes gh-14252 --- ...bitListenerContainerFactoryConfigurer.java | 3 ++ ...bitListenerContainerFactoryConfigurer.java | 2 - .../autoconfigure/amqp/RabbitProperties.java | 43 ++++++------------- ...bitListenerContainerFactoryConfigurer.java | 2 - .../amqp/RabbitAutoConfigurationTests.java | 8 ++-- .../appendix-application-properties.adoc | 4 +- 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java index 59211edc1eee..578a82459720 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java @@ -116,6 +116,9 @@ protected void configure(T factory, ConnectionFactory connectionFactory, if (configuration.getIdleEventInterval() != null) { factory.setIdleEventInterval(configuration.getIdleEventInterval().toMillis()); } + if (configuration.getMissingQueuesFatal() != null) { + factory.setMissingQueuesFatal(configuration.getMissingQueuesFatal()); + } ListenerRetry retryConfig = configuration.getRetry(); if (retryConfig.isEnabled()) { RetryInterceptorBuilder builder = (retryConfig.isStateless()) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java index 67c1fe9cea65..d3cd82b5300b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java @@ -40,8 +40,6 @@ public void configure(DirectRabbitListenerContainerFactory factory, configure(factory, connectionFactory, config); map.from(config::getConsumersPerQueue).whenNonNull() .to(factory::setConsumersPerQueue); - map.from(config::getMissingQueuesFatal).whenNonNull() - .to(factory::setMissingQueuesFatal); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index 327686cbcb79..dcbf0f318e99 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -592,6 +592,12 @@ public abstract static class AmqpContainer { */ private Duration idleEventInterval; + /** + * Whether to fail if the queues declared by the container are not available on + * the broker. + */ + private Boolean missingQueuesFatal; + /** * Optional properties for a retry interceptor. */ @@ -637,6 +643,14 @@ public void setIdleEventInterval(Duration idleEventInterval) { this.idleEventInterval = idleEventInterval; } + public Boolean getMissingQueuesFatal() { + return this.missingQueuesFatal; + } + + public void setMissingQueuesFatal(Boolean missingQueuesFatal) { + this.missingQueuesFatal = missingQueuesFatal; + } + public ListenerRetry getRetry() { return this.retry; } @@ -665,13 +679,6 @@ public static class SimpleContainer extends AmqpContainer { */ private Integer transactionSize; - /** - * Whether the context should be ended up with failure if there are no any queues - * available on the broker or the container should be stopped if queues have been - * removed while the container is running. - */ - private Boolean missingQueuesFatal; - public Integer getConcurrency() { return this.concurrency; } @@ -696,14 +703,6 @@ public void setTransactionSize(Integer transactionSize) { this.transactionSize = transactionSize; } - public Boolean getMissingQueuesFatal() { - return this.missingQueuesFatal; - } - - public void setMissingQueuesFatal(Boolean missingQueuesFatal) { - this.missingQueuesFatal = missingQueuesFatal; - } - } /** @@ -716,12 +715,6 @@ public static class DirectContainer extends AmqpContainer { */ private Integer consumersPerQueue; - /** - * Whether the context should be ended up with failure if there are no any queues - * available on the broker. - */ - private Boolean missingQueuesFatal; - public Integer getConsumersPerQueue() { return this.consumersPerQueue; } @@ -730,14 +723,6 @@ public void setConsumersPerQueue(Integer consumersPerQueue) { this.consumersPerQueue = consumersPerQueue; } - public Boolean getMissingQueuesFatal() { - return this.missingQueuesFatal; - } - - public void setMissingQueuesFatal(Boolean missingQueuesFatal) { - this.missingQueuesFatal = missingQueuesFatal; - } - } public static class Template { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java index 017722763cd9..6321fab6090f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java @@ -43,8 +43,6 @@ public void configure(SimpleRabbitListenerContainerFactory factory, map.from(config::getMaxConcurrency).whenNonNull() .to(factory::setMaxConcurrentConsumers); map.from(config::getTransactionSize).whenNonNull().to(factory::setTxSize); - map.from(config::getMissingQueuesFatal).whenNonNull() - .to(factory::setMissingQueuesFatal); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index 721e0f6aca65..c94a01852476 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -468,8 +468,8 @@ public void testSimpleRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.simple.maxConcurrency:10", "spring.rabbitmq.listener.simple.prefetch:40", "spring.rabbitmq.listener.simple.defaultRequeueRejected:false", - "spring.rabbitmq.listener.simple.missingQueuesFatal:false", "spring.rabbitmq.listener.simple.idleEventInterval:5", + "spring.rabbitmq.listener.simple.missingQueuesFatal:false", "spring.rabbitmq.listener.simple.transactionSize:20") .run((context) -> { SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context @@ -501,8 +501,8 @@ public void testDirectRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.direct.consumers-per-queue:5", "spring.rabbitmq.listener.direct.prefetch:40", "spring.rabbitmq.listener.direct.defaultRequeueRejected:false", - "spring.rabbitmq.listener.direct.missingQueuesFatal:false", - "spring.rabbitmq.listener.direct.idleEventInterval:5") + "spring.rabbitmq.listener.direct.idleEventInterval:5", + "spring.rabbitmq.listener.direct.missingQueuesFatal:false") .run((context) -> { DirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context .getBean("rabbitListenerContainerFactory", @@ -623,10 +623,10 @@ private void checkCommonProps(AssertableApplicationContext context, assertThat(dfa.getPropertyValue("prefetchCount")).isEqualTo(40); assertThat(dfa.getPropertyValue("messageConverter")) .isSameAs(context.getBean("myMessageConverter")); - assertThat(dfa.getPropertyValue("missingQueuesFatal")).isEqualTo(false); assertThat(dfa.getPropertyValue("defaultRequeueRejected")) .isEqualTo(Boolean.FALSE); assertThat(dfa.getPropertyValue("idleEventInterval")).isEqualTo(5L); + assertThat(dfa.getPropertyValue("missingQueuesFatal")).isEqualTo(false); Advice[] adviceChain = (Advice[]) dfa.getPropertyValue("adviceChain"); assertThat(adviceChain).isNotNull(); assertThat(adviceChain.length).isEqualTo(1); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e99e7e16f94f..e3ed7cc7cf67 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1137,7 +1137,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.direct.consumers-per-queue= # Number of consumers per queue. spring.rabbitmq.listener.direct.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.direct.idle-event-interval= # How often idle container events should be published. - spring.rabbitmq.listener.direct.missing-queues-fatal= # Whether the context should be ended up with failure if there are no any queues available on the broker. + spring.rabbitmq.listener.direct.missing-queues-fatal= # Whether to fail if the queues declared by the container are not available on the broker. spring.rabbitmq.listener.direct.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.direct.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.direct.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. @@ -1151,7 +1151,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.simple.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.simple.idle-event-interval= # How often idle container events should be published. spring.rabbitmq.listener.simple.max-concurrency= # Maximum number of listener invoker threads. - spring.rabbitmq.listener.simple.missing-queues-fatal= # Whether the context should be ended up with failure if there are no any queues available on the broker or the container should be stopped if queues have been removed while the container is running. + spring.rabbitmq.listener.simple.missing-queues-fatal= # Whether to fail if the queues declared by the container are not available on the broker. spring.rabbitmq.listener.simple.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.simple.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.simple.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. From 4fc2806089b73513904336c19071e5ddc2036d25 Mon Sep 17 00:00:00 2001 From: dreis2211 Date: Thu, 6 Sep 2018 20:34:33 +0200 Subject: [PATCH 531/701] Polish CommandCompleter Closes gh-14339 --- .../boot/cli/command/shell/CommandCompleter.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/CommandCompleter.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/CommandCompleter.java index 4fbfec961ff5..c6810b65f02b 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/CommandCompleter.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/CommandCompleter.java @@ -127,12 +127,7 @@ private static class OptionHelpLine { private final String usage; OptionHelpLine(OptionHelp optionHelp) { - StringBuilder options = new StringBuilder(); - for (String option : optionHelp.getOptions()) { - options.append((options.length() != 0) ? ", " : ""); - options.append(option); - } - this.options = options.toString(); + this.options = String.join(", ", optionHelp.getOptions()); this.usage = optionHelp.getUsageHelp(); } From 24051b42d0e1446ec1a8c40c7e6e42538f0520fc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 7 Sep 2018 18:41:23 +0200 Subject: [PATCH 532/701] Polish "Add support for configuring missingQueuesFatal property" See gh-14252 --- ...bitListenerContainerFactoryConfigurer.java | 4 +- .../autoconfigure/amqp/RabbitProperties.java | 45 +++++++++++++------ .../amqp/RabbitAutoConfigurationTests.java | 11 +++-- .../amqp/RabbitPropertiesTests.java | 31 +++++++++++++ .../appendix-application-properties.adoc | 4 +- 5 files changed, 73 insertions(+), 22 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java index 578a82459720..d271bc0fea4f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java @@ -116,9 +116,7 @@ protected void configure(T factory, ConnectionFactory connectionFactory, if (configuration.getIdleEventInterval() != null) { factory.setIdleEventInterval(configuration.getIdleEventInterval().toMillis()); } - if (configuration.getMissingQueuesFatal() != null) { - factory.setMissingQueuesFatal(configuration.getMissingQueuesFatal()); - } + factory.setMissingQueuesFatal(configuration.isMissingQueuesFatal()); ListenerRetry retryConfig = configuration.getRetry(); if (retryConfig.isEnabled()) { RetryInterceptorBuilder builder = (retryConfig.isStateless()) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java index dcbf0f318e99..b8bc40ec19a7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitProperties.java @@ -592,12 +592,6 @@ public abstract static class AmqpContainer { */ private Duration idleEventInterval; - /** - * Whether to fail if the queues declared by the container are not available on - * the broker. - */ - private Boolean missingQueuesFatal; - /** * Optional properties for a retry interceptor. */ @@ -643,13 +637,7 @@ public void setIdleEventInterval(Duration idleEventInterval) { this.idleEventInterval = idleEventInterval; } - public Boolean getMissingQueuesFatal() { - return this.missingQueuesFatal; - } - - public void setMissingQueuesFatal(Boolean missingQueuesFatal) { - this.missingQueuesFatal = missingQueuesFatal; - } + public abstract boolean isMissingQueuesFatal(); public ListenerRetry getRetry() { return this.retry; @@ -679,6 +667,13 @@ public static class SimpleContainer extends AmqpContainer { */ private Integer transactionSize; + /** + * Whether to fail if the queues declared by the container are not available on + * the broker and/or whether to stop the container if one or more queues are + * deleted at runtime. + */ + private boolean missingQueuesFatal = true; + public Integer getConcurrency() { return this.concurrency; } @@ -703,6 +698,15 @@ public void setTransactionSize(Integer transactionSize) { this.transactionSize = transactionSize; } + @Override + public boolean isMissingQueuesFatal() { + return this.missingQueuesFatal; + } + + public void setMissingQueuesFatal(boolean missingQueuesFatal) { + this.missingQueuesFatal = missingQueuesFatal; + } + } /** @@ -715,6 +719,12 @@ public static class DirectContainer extends AmqpContainer { */ private Integer consumersPerQueue; + /** + * Whether to fail if the queues declared by the container are not available on + * the broker. + */ + private boolean missingQueuesFatal = false; + public Integer getConsumersPerQueue() { return this.consumersPerQueue; } @@ -723,6 +733,15 @@ public void setConsumersPerQueue(Integer consumersPerQueue) { this.consumersPerQueue = consumersPerQueue; } + @Override + public boolean isMissingQueuesFatal() { + return this.missingQueuesFatal; + } + + public void setMissingQueuesFatal(boolean missingQueuesFatal) { + this.missingQueuesFatal = missingQueuesFatal; + } + } public static class Template { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index c94a01852476..4e6ecea329c4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -469,8 +469,8 @@ public void testSimpleRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.simple.prefetch:40", "spring.rabbitmq.listener.simple.defaultRequeueRejected:false", "spring.rabbitmq.listener.simple.idleEventInterval:5", - "spring.rabbitmq.listener.simple.missingQueuesFatal:false", - "spring.rabbitmq.listener.simple.transactionSize:20") + "spring.rabbitmq.listener.simple.transactionSize:20", + "spring.rabbitmq.listener.simple.missingQueuesFatal:false") .run((context) -> { SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context .getBean("rabbitListenerContainerFactory", @@ -481,6 +481,8 @@ public void testSimpleRabbitListenerContainerFactoryWithCustomSettings() { assertThat(dfa.getPropertyValue("maxConcurrentConsumers")) .isEqualTo(10); assertThat(dfa.getPropertyValue("txSize")).isEqualTo(20); + assertThat(dfa.getPropertyValue("missingQueuesFatal")) + .isEqualTo(false); checkCommonProps(context, dfa); }); } @@ -502,7 +504,7 @@ public void testDirectRabbitListenerContainerFactoryWithCustomSettings() { "spring.rabbitmq.listener.direct.prefetch:40", "spring.rabbitmq.listener.direct.defaultRequeueRejected:false", "spring.rabbitmq.listener.direct.idleEventInterval:5", - "spring.rabbitmq.listener.direct.missingQueuesFatal:false") + "spring.rabbitmq.listener.direct.missingQueuesFatal:true") .run((context) -> { DirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context .getBean("rabbitListenerContainerFactory", @@ -510,6 +512,8 @@ public void testDirectRabbitListenerContainerFactoryWithCustomSettings() { DirectFieldAccessor dfa = new DirectFieldAccessor( rabbitListenerContainerFactory); assertThat(dfa.getPropertyValue("consumersPerQueue")).isEqualTo(5); + assertThat(dfa.getPropertyValue("missingQueuesFatal")) + .isEqualTo(true); checkCommonProps(context, dfa); }); } @@ -626,7 +630,6 @@ private void checkCommonProps(AssertableApplicationContext context, assertThat(dfa.getPropertyValue("defaultRequeueRejected")) .isEqualTo(Boolean.FALSE); assertThat(dfa.getPropertyValue("idleEventInterval")).isEqualTo(5L); - assertThat(dfa.getPropertyValue("missingQueuesFatal")).isEqualTo(false); Advice[] adviceChain = (Advice[]) dfa.getPropertyValue("adviceChain"); assertThat(adviceChain).isNotNull(); assertThat(adviceChain.length).isEqualTo(1); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java index 8d0d046e414b..1872ce191a99 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java @@ -18,6 +18,12 @@ import org.junit.Test; +import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.beans.DirectFieldAccessor; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -25,6 +31,7 @@ * * @author Dave Syer * @author Andy Wilkinson + * @author Stephane Nicoll */ public class RabbitPropertiesTests { @@ -226,4 +233,28 @@ public void determineAddressesUsesHostAndPortPropertiesWhenNoAddressesSet() { .isEqualTo("rabbit.example.com:1234"); } + @Test + public void simpleContainerUseConsistentDefaultValues() { + SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); + SimpleMessageListenerContainer container = factory.createListenerContainer(); + DirectFieldAccessor dfa = new DirectFieldAccessor(container); + RabbitProperties.SimpleContainer simple = this.properties.getListener() + .getSimple(); + assertThat(simple.isAutoStartup()).isEqualTo(container.isAutoStartup()); + assertThat(simple.isMissingQueuesFatal()) + .isEqualTo(dfa.getPropertyValue("missingQueuesFatal")); + } + + @Test + public void directContainerUseConsistentDefaultValues() { + DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory(); + DirectMessageListenerContainer container = factory.createListenerContainer(); + DirectFieldAccessor dfa = new DirectFieldAccessor(container); + RabbitProperties.DirectContainer direct = this.properties.getListener() + .getDirect(); + assertThat(direct.isAutoStartup()).isEqualTo(container.isAutoStartup()); + assertThat(direct.isMissingQueuesFatal()) + .isEqualTo(dfa.getPropertyValue("missingQueuesFatal")); + } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e3ed7cc7cf67..648cef76b4a8 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1137,7 +1137,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.direct.consumers-per-queue= # Number of consumers per queue. spring.rabbitmq.listener.direct.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.direct.idle-event-interval= # How often idle container events should be published. - spring.rabbitmq.listener.direct.missing-queues-fatal= # Whether to fail if the queues declared by the container are not available on the broker. + spring.rabbitmq.listener.direct.missing-queues-fatal=false # Whether to fail if the queues declared by the container are not available on the broker. spring.rabbitmq.listener.direct.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.direct.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.direct.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. @@ -1151,7 +1151,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.simple.default-requeue-rejected= # Whether rejected deliveries are re-queued by default. spring.rabbitmq.listener.simple.idle-event-interval= # How often idle container events should be published. spring.rabbitmq.listener.simple.max-concurrency= # Maximum number of listener invoker threads. - spring.rabbitmq.listener.simple.missing-queues-fatal= # Whether to fail if the queues declared by the container are not available on the broker. + spring.rabbitmq.listener.simple.missing-queues-fatal=true # Whether to fail if the queues declared by the container are not available on the broker and/or whether to stop the container if one or more queues are deleted at runtime. spring.rabbitmq.listener.simple.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). spring.rabbitmq.listener.simple.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.simple.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. From 049335524142cd69ceff31fa544786e59a2814d8 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sat, 8 Sep 2018 08:20:43 +0200 Subject: [PATCH 533/701] Use deterministic order for configuration properties metadata This commit updates the annotation processor to write metadata in a consistent way. Groups, properties and hints are written and each item is ordered alphabetically based on its name. Also, deprecated items are written last. Closes gh-14347 --- .../json/JSONObject.java | 4 +- .../metadata/JSONOrderedObject.java | 48 ------------------ .../metadata/JsonConverter.java | 50 ++++++++++++++++--- .../metadata/JsonMarshaller.java | 2 +- ...ationMetadataAnnotationProcessorTests.java | 25 ++++++++-- .../metadata/JsonMarshallerTests.java | 50 ++++++++++++++++++- 6 files changed, 118 insertions(+), 61 deletions(-) delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JSONOrderedObject.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java index 43386a958412..5b0bedf71866 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java @@ -18,8 +18,8 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; // Note: this class was written without inspecting the non-free org.json source code. @@ -111,7 +111,7 @@ public String toString() { * Creates a {@code JSONObject} with no name/value mappings. */ public JSONObject() { - this.nameValuePairs = new HashMap<>(); + this.nameValuePairs = new LinkedHashMap<>(); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JSONOrderedObject.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JSONOrderedObject.java deleted file mode 100644 index bda84dd8c588..000000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JSONOrderedObject.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012-2018 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.configurationprocessor.metadata; - -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.boot.configurationprocessor.json.JSONException; -import org.springframework.boot.configurationprocessor.json.JSONObject; - -/** - * Extension to {@link JSONObject} that remembers the order of inserts. - * - * @author Stephane Nicoll - * @author Phillip Webb - */ -@SuppressWarnings("rawtypes") -class JSONOrderedObject extends JSONObject { - - private Set keys = new LinkedHashSet<>(); - - @Override - public JSONObject put(String key, Object value) throws JSONException { - this.keys.add(key); - return super.put(key, value); - } - - @Override - public Iterator keys() { - return this.keys.iterator(); - } - -} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java index 2aa14d3b54e5..874c022744c2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java @@ -18,7 +18,10 @@ import java.lang.reflect.Array; import java.util.Collection; +import java.util.Comparator; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.springframework.boot.configurationprocessor.json.JSONArray; import org.springframework.boot.configurationprocessor.json.JSONObject; @@ -32,10 +35,15 @@ */ class JsonConverter { + private static final ItemMetadataComparator ITEM_COMPARATOR = new ItemMetadataComparator(); + public JSONArray toJsonArray(ConfigurationMetadata metadata, ItemType itemType) throws Exception { JSONArray jsonArray = new JSONArray(); - for (ItemMetadata item : metadata.getItems()) { + List items = metadata.getItems().stream() + .filter((item) -> item.isOfItemType(itemType)).sorted(ITEM_COMPARATOR) + .collect(Collectors.toList()); + for (ItemMetadata item : items) { if (item.isOfItemType(itemType)) { jsonArray.put(toJsonObject(item)); } @@ -52,7 +60,7 @@ public JSONArray toJsonArray(Collection hints) throws Exception { } public JSONObject toJsonObject(ItemMetadata item) throws Exception { - JSONObject jsonObject = new JSONOrderedObject(); + JSONObject jsonObject = new JSONObject(); jsonObject.put("name", item.getName()); putIfPresent(jsonObject, "type", item.getType()); putIfPresent(jsonObject, "description", item.getDescription()); @@ -81,7 +89,7 @@ public JSONObject toJsonObject(ItemMetadata item) throws Exception { } private JSONObject toJsonObject(ItemHint hint) throws Exception { - JSONObject jsonObject = new JSONOrderedObject(); + JSONObject jsonObject = new JSONObject(); jsonObject.put("name", hint.getName()); if (!hint.getValues().isEmpty()) { jsonObject.put("values", getItemHintValues(hint)); @@ -101,7 +109,7 @@ private JSONArray getItemHintValues(ItemHint hint) throws Exception { } private JSONObject getItemHintValue(ItemHint.ValueHint value) throws Exception { - JSONObject result = new JSONOrderedObject(); + JSONObject result = new JSONObject(); putHintValue(result, value.getValue()); putIfPresent(result, "description", value.getDescription()); return result; @@ -117,10 +125,10 @@ private JSONArray getItemHintProviders(ItemHint hint) throws Exception { private JSONObject getItemHintProvider(ItemHint.ValueProvider provider) throws Exception { - JSONObject result = new JSONOrderedObject(); + JSONObject result = new JSONObject(); result.put("name", provider.getName()); if (provider.getParameters() != null && !provider.getParameters().isEmpty()) { - JSONObject parameters = new JSONOrderedObject(); + JSONObject parameters = new JSONObject(); for (Map.Entry entry : provider.getParameters().entrySet()) { parameters.put(entry.getKey(), extractItemValue(entry.getValue())); } @@ -160,4 +168,34 @@ private Object extractItemValue(Object value) { return defaultValue; } + private static class ItemMetadataComparator implements Comparator { + + @Override + public int compare(ItemMetadata o1, ItemMetadata o2) { + if (o1.isOfItemType(ItemType.GROUP)) { + return compareGroup(o1, o2); + } + return compareProperty(o1, o2); + } + + private int compareGroup(ItemMetadata o1, ItemMetadata o2) { + return o1.getName().compareTo(o2.getName()); + } + + private int compareProperty(ItemMetadata o1, ItemMetadata o2) { + if (isDeprecated(o1) && !isDeprecated(o2)) { + return 1; + } + if (isDeprecated(o2) && !isDeprecated(o1)) { + return -1; + } + return o1.getName().compareTo(o2.getName()); + } + + private boolean isDeprecated(ItemMetadata item) { + return item.getDeprecation() != null; + } + + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java index 4230638bd440..8271bd88bd30 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java @@ -45,7 +45,7 @@ public class JsonMarshaller { public void write(ConfigurationMetadata metadata, OutputStream outputStream) throws IOException { try { - JSONObject object = new JSONOrderedObject(); + JSONObject object = new JSONObject(); JsonConverter converter = new JsonConverter(); object.put("groups", converter.toJsonArray(metadata, ItemType.GROUP)); object.put("properties", converter.toJsonArray(metadata, ItemType.PROPERTY)); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index 98d66f7af714..613b6db92672 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -22,6 +22,8 @@ import java.time.Duration; import java.util.Arrays; import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.junit.Before; import org.junit.Rule; @@ -822,9 +824,26 @@ public void mergeExistingPropertyWithSeveralCandidates() throws Exception { ConfigurationMetadata metadata = compile(SimpleProperties.class, SimpleConflictingProperties.class); assertThat(metadata.getItems()).hasSize(6); - assertThat(metadata).has(Metadata.withProperty("simple.flag", Boolean.class) - .fromSource(SimpleProperties.class).withDescription("A simple flag.") - .withDeprecation(null, null).withDefaultValue(true)); + List items = metadata.getItems().stream() + .filter((item) -> item.getName().equals("simple.flag")) + .collect(Collectors.toList()); + assertThat(items).hasSize(2); + ItemMetadata matchingProperty = items.stream() + .filter((item) -> item.getType().equals(Boolean.class.getName())) + .findFirst().orElse(null); + assertThat(matchingProperty).isNotNull(); + assertThat(matchingProperty.getDefaultValue()).isEqualTo(true); + assertThat(matchingProperty.getSourceType()) + .isEqualTo(SimpleProperties.class.getName()); + assertThat(matchingProperty.getDescription()).isEqualTo("A simple flag."); + ItemMetadata nonMatchingProperty = items.stream() + .filter((item) -> item.getType().equals(String.class.getName())) + .findFirst().orElse(null); + assertThat(nonMatchingProperty).isNotNull(); + assertThat(nonMatchingProperty.getDefaultValue()).isEqualTo("hello"); + assertThat(nonMatchingProperty.getSourceType()) + .isEqualTo(SimpleConflictingProperties.class.getName()); + assertThat(nonMatchingProperty.getDescription()).isNull(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java index a9b0b8b78df4..f19f2f733440 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,6 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Collections; @@ -82,4 +83,51 @@ public void marshallAndUnmarshal() throws Exception { .withProvider("second")); } + @Test + public void marshallOrderItems() throws IOException { + ConfigurationMetadata metadata = new ConfigurationMetadata(); + metadata.add(ItemHint.newHint("fff")); + metadata.add(ItemHint.newHint("eee")); + metadata.add(ItemMetadata.newProperty("com.example.bravo", "bbb", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newProperty("com.example.bravo", "aaa", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newProperty("com.example.alpha", "ddd", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newProperty("com.example.alpha", "ccc", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newGroup("com.acme.bravo", + "com.example.AnotherTestProperties", null, null)); + metadata.add(ItemMetadata.newGroup("com.acme.alpha", "com.example.TestProperties", + null, null)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + JsonMarshaller marshaller = new JsonMarshaller(); + marshaller.write(metadata, outputStream); + String json = new String(outputStream.toByteArray()); + assertThat(json).containsSubsequence("\"groups\"", "\"com.acme.alpha\"", + "\"com.acme.bravo\"", "\"properties\"", "\"com.example.alpha.ccc\"", + "\"com.example.alpha.ddd\"", "\"com.example.bravo.aaa\"", + "\"com.example.bravo.bbb\"", "\"hints\"", "\"eee\"", "\"fff\""); + } + + @Test + public void marshallPutDeprecatedItemsAtTheEnd() throws IOException { + ConfigurationMetadata metadata = new ConfigurationMetadata(); + metadata.add(ItemMetadata.newProperty("com.example.bravo", "bbb", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newProperty("com.example.bravo", "aaa", null, null, + null, null, null, new ItemDeprecation(null, null, "warning"))); + metadata.add(ItemMetadata.newProperty("com.example.alpha", "ddd", null, null, + null, null, null, null)); + metadata.add(ItemMetadata.newProperty("com.example.alpha", "ccc", null, null, + null, null, null, new ItemDeprecation(null, null, "warning"))); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + JsonMarshaller marshaller = new JsonMarshaller(); + marshaller.write(metadata, outputStream); + String json = new String(outputStream.toByteArray()); + assertThat(json).containsSubsequence("\"properties\"", + "\"com.example.alpha.ddd\"", "\"com.example.bravo.bbb\"", + "\"com.example.alpha.ccc\"", "\"com.example.bravo.aaa\""); + } + } From 67d543c64cd79734a9d27d9a086d099e0c364648 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 9 Sep 2018 10:36:18 +0200 Subject: [PATCH 534/701] Start building against Spring Session Bean snapshots See gh-14333 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2e4d2d2b5b25..4e1e032e9549 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -171,7 +171,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.BUILD-SNAPSHOT - Bean-M2 + Bean-BUILD-SNAPSHOT 3.0.3.RELEASE 3.23.1 3.1.0 From 89944edf278eef0f5fa10e624bf95cb922016e13 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:07 +0100 Subject: [PATCH 535/701] Upgrade to Couchbase Client 2.6.2 Closes gh-14373 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 19b13e38014d..0c8ac0e2ef2b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -50,7 +50,7 @@ 3.7 1.6 2.6.0 - 2.6.1 + 2.6.2 2.1.0 10.14.2.0 1.6.1 From 753dd454fb1ecfa67b3fbc0edb019011acfafc4d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:07 +0100 Subject: [PATCH 536/701] Upgrade to Cassandra Driver 3.6.0 Closes gh-14374 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 0c8ac0e2ef2b..1c2d8c5ab4ff 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -43,7 +43,7 @@ 2.1.4 1.8.17 2.6.2 - 3.5.1 + 3.6.0 1.3.4 1.11 2.5.0 From c9bdc09c14a9eeda8ba444b085e07e81a0e2181e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:08 +0100 Subject: [PATCH 537/701] Upgrade to Lettuce 5.1.0.RC1 Closes gh-14375 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 1c2d8c5ab4ff..4bcd4cef7978 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -121,7 +121,7 @@ 5.3.0-RC1 2.0.0 1.2.61 - 5.1.0.M1 + 5.1.0.RC1 3.6.2 2.11.1 1.2.3 From 3cec99d8aa2676c2ed3b03d5329e41d95cfbc5c1 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:09 +0100 Subject: [PATCH 538/701] Upgrade to Netty Tcnative 2.0.15.Final Closes gh-14376 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4bcd4cef7978..7706154f2b4c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -136,7 +136,7 @@ 1.9.22 3.1.2 4.1.29.Final - 2.0.13.Final + 2.0.15.Final 1.1.0 1.0.3 42.2.5 From 75a74d6a94c39e6da9ba75aa9dfee2e9e3c32be2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:10 +0100 Subject: [PATCH 539/701] Upgrade to Rxjava2 2.2.2 Closes gh-14377 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 7706154f2b4c..8014b20cc2dd 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -148,7 +148,7 @@ 1.0.2 1.3.8 1.2.1 - 2.2.0 + 2.2.2 3.14.0 2.32.1 4.2.1 From e5680816faa26ba744e088ad7036b94fccba4e8f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:10 +0100 Subject: [PATCH 540/701] Upgrade to Byte Buddy 1.8.22 Closes gh-14378 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8014b20cc2dd..c69e6814027c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -41,7 +41,7 @@ 3.11.0 4.0.6 2.1.4 - 1.8.17 + 1.8.22 2.6.2 3.6.0 1.3.4 From 3b1c4f7c190ab553f964a8e37cc8435804e74b0c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:11 +0100 Subject: [PATCH 541/701] Upgrade to Artemis 2.6.3 Closes gh-14379 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c69e6814027c..cfe77063edfa 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -36,7 +36,7 @@ 5.15.6 2.7.7 1.9.64 - 2.6.2 + 2.6.3 1.9.1 3.11.0 4.0.6 From 1ef8e053748b13f57417f7f1f54f91eb4ed56561 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:12 +0100 Subject: [PATCH 542/701] Upgrade to Commons Lang3 3.8 Closes gh-14380 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index cfe77063edfa..6da3aa59433c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -47,7 +47,7 @@ 1.3.4 1.11 2.5.0 - 3.7 + 3.8 1.6 2.6.0 2.6.2 From 495025af97d911167a767d56a234f318d2d5fefa Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:12 +0100 Subject: [PATCH 543/701] Upgrade to Tomcat 9.0.11 Closes gh-14381 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6da3aa59433c..695c42f85075 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -182,7 +182,7 @@ 2.3.0 2.0.1 3.0.1.RELEASE - 9.0.10 + 9.0.11 4.0.7 2.0.13.Final 3325375 From 22ef443d511522e008ac2ae268bf768155631b0b Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:13 +0100 Subject: [PATCH 544/701] Upgrade to Assertj 3.11.1 Closes gh-14382 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 695c42f85075..69041f215669 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -38,7 +38,7 @@ 1.9.64 2.6.3 1.9.1 - 3.11.0 + 3.11.1 4.0.6 2.1.4 1.8.22 From fccb8f5619b04c5acc36f57ea4ee26c973647244 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:14 +0100 Subject: [PATCH 545/701] Upgrade to Ehcache3 3.6.0 Closes gh-14383 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 69041f215669..b89ed12034cf 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -56,7 +56,7 @@ 1.6.1 3.2.6 2.10.5 - 3.5.2 + 3.6.0 2.1.1 5.1.4 2.3.28 From f897a50833bdb4ca5739459d227a5206bac5dd36 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:15 +0100 Subject: [PATCH 546/701] Upgrade to Elasticsearch 6.4.0 Closes gh-14384 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b89ed12034cf..54e216249295 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -60,7 +60,7 @@ 2.1.1 5.1.4 2.3.28 - 6.3.2 + 6.4.0 3.0.0 2.3.0.1 2.5.2 From 9be62edfa27e87e3b38d3e98b06ec47031c1a8e4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:16 +0100 Subject: [PATCH 547/701] Upgrade to Hibernate 5.3.6.Final Closes gh-14385 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 54e216249295..daeb39bf4a6d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -69,7 +69,7 @@ 1.3 3.10.4 1.2.3 - 5.3.5.Final + 5.3.6.Final 6.0.12.Final 3.2.0 2.4.1 From bd4a5f5c916228893eaeec042a3bc5c1ef629f09 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:17 +0100 Subject: [PATCH 548/701] Upgrade to Infinispan 9.3.2.Final Closes gh-14386 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index daeb39bf4a6d..5b961fc74ecf 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -77,7 +77,7 @@ 4.1.4 4.5.6 4.4.10 - 9.3.1.Final + 9.3.2.Final 2.12 2.9.6 3.0.9 From f910a1e671bee1232989c8ea15fbfe29ac167d84 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:17 +0100 Subject: [PATCH 549/701] Upgrade to Junit Jupiter 5.3.0 Closes gh-14387 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5b961fc74ecf..fca00df85008 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -118,7 +118,7 @@ 1.2 1.3.1 4.12 - 5.3.0-RC1 + 5.3.0 2.0.0 1.2.61 5.1.0.RC1 From e27ba5875e1857f38ee3fe3658fdf74f72411926 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:18 +0100 Subject: [PATCH 550/701] Upgrade to Mariadb 2.3.0 Closes gh-14388 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fca00df85008..42e527844010 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -126,7 +126,7 @@ 2.11.1 1.2.3 1.18.2 - 2.2.6 + 2.3.0 1.0.6 2.21.0 1.9.0 From 3307760bed2b42efc876822cb93c0b9738dc6a49 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:19 +0100 Subject: [PATCH 551/701] Upgrade to Mockito 2.22.0 Closes gh-14389 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 42e527844010..841af1cb1e36 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -128,7 +128,7 @@ 1.18.2 2.3.0 1.0.6 - 2.21.0 + 2.22.0 1.9.0 3.8.0 6.4.0.jre8 From 49ea341f26ee01c1f3f9618d7c8a57ea42b2fa6c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:19 +0100 Subject: [PATCH 552/701] Upgrade to Mongodb 3.8.1 Closes gh-14390 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 841af1cb1e36..9e44494c7359 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -130,7 +130,7 @@ 1.0.6 2.22.0 1.9.0 - 3.8.0 + 3.8.1 6.4.0.jre8 8.0.12 1.9.22 From c4103bf0c741361c70c0dcfbdda4898c1c9e474f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:20 +0100 Subject: [PATCH 553/701] Upgrade to Mongo Driver Reactivestreams 1.9.1 Closes gh-14391 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 9e44494c7359..307d51f959f6 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -129,7 +129,7 @@ 2.3.0 1.0.6 2.22.0 - 1.9.0 + 1.9.1 3.8.1 6.4.0.jre8 8.0.12 From 379a8a4781bd6485f7bba1958e7be34910a76aee Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:20 +0100 Subject: [PATCH 554/701] Upgrade to Xmlunit2 2.6.2 Closes gh-14392 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 307d51f959f6..840a962a2595 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -189,7 +189,7 @@ 0.35 1.6.3 1.4.01 - 2.6.1 + 2.6.2 3.0.0 1.6.0 From 366c4d60447d608ba3d2fe9e4f631a2eb6e29cca Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 08:56:21 +0100 Subject: [PATCH 555/701] Upgrade to Versions Maven Plugin 2.7 Closes gh-14393 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 840a962a2595..fd03faf2b96b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -213,7 +213,7 @@ 3.0.1 2.22.0 3.2.2 - 2.5 + 2.7 1.0.2 1.0.1 From 61ca6f439ce161ff77c43c46bf1a12ec5c62880c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 09:20:24 +0100 Subject: [PATCH 556/701] Retain property aliases when flattening dependencies pom Closes gh-12544 --- spring-boot-project/spring-boot-dependencies/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fd03faf2b96b..f48b50525fa1 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -3072,6 +3072,7 @@ bom keep + keep remove From 48367e7741feb8c78ac68d596e748ead55e74f4b Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 10 Sep 2018 15:57:37 +0200 Subject: [PATCH 557/701] Make standard JSON builder customiser classes package-private Closes gh-14399 --- .../boot/autoconfigure/gson/GsonAutoConfiguration.java | 2 +- .../boot/autoconfigure/jackson/JacksonAutoConfiguration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java index 6956a5da7155..3de566bccd10 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java @@ -62,7 +62,7 @@ public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer( return new StandardGsonBuilderCustomizer(gsonProperties); } - private static final class StandardGsonBuilderCustomizer + static final class StandardGsonBuilderCustomizer implements GsonBuilderCustomizer, Ordered { private final GsonProperties properties; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index cc83ef5cab2e..43671acc1e51 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -213,7 +213,7 @@ public StandardJackson2ObjectMapperBuilderCustomizer standardJacksonObjectMapper jacksonProperties); } - private static final class StandardJackson2ObjectMapperBuilderCustomizer + static final class StandardJackson2ObjectMapperBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer, Ordered { private final ApplicationContext applicationContext; From 144bc69afcd64cac0ec79bdea14b8d915b937640 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 10 Sep 2018 20:22:17 +0100 Subject: [PATCH 558/701] Upgrade to Spring Kafka 2.2.0.M3 Closes gh-14331 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f48b50525fa1..b70292d8f833 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ ${spring.version} 0.25.0.RELEASE 5.1.0.M2 - 2.2.0.BUILD-SNAPSHOT + 2.2.0.M3 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 968a637e50a67c4aa2ab2ecf70519851b9cd79b7 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 10 Sep 2018 14:09:19 -0700 Subject: [PATCH 559/701] Refactor ReactiveOAuth2ClientAutoConfiguration for non webapps Non web applications might want to leverage `ReactiveClientRegistrationRepository` and `ServerOAuth2AuthorizedClientRepository` to configure `WebClient`. Closes gh-14350 --- ...ReactiveOAuth2ClientAutoConfiguration.java | 61 +++++- ...ntRegistrationRepositoryConfiguration.java | 60 ------ ...eactiveOAuth2WebSecurityConfiguration.java | 45 ----- ...iveOAuth2ClientAutoConfigurationTests.java | 184 ++++++++++++++---- ...istrationRepositoryConfigurationTests.java | 65 ------- ...veOAuth2WebSecurityConfigurationTests.java | 114 ----------- 6 files changed, 200 insertions(+), 329 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java index dcaecfba661a..15b94bf56ed4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java @@ -15,15 +15,32 @@ */ package org.springframework.boot.autoconfigure.security.oauth2.client.reactive; +import java.util.ArrayList; +import java.util.List; + +import reactor.core.publisher.Flux; + import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's Reactive @@ -34,10 +51,42 @@ */ @Configuration @AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) -@ConditionalOnClass({ EnableWebFluxSecurity.class, ClientRegistration.class }) -@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) -@Import({ ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class, - ReactiveOAuth2WebSecurityConfiguration.class }) +@EnableConfigurationProperties(OAuth2ClientProperties.class) +@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ClientRegistration.class }) public class ReactiveOAuth2ClientAutoConfiguration { + private final OAuth2ClientProperties properties; + + public ReactiveOAuth2ClientAutoConfiguration(OAuth2ClientProperties properties) { + this.properties = properties; + } + + @Bean + @Conditional(ClientsConfiguredCondition.class) + @ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class) + public InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>( + OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(this.properties).values()); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + + @Bean + @ConditionalOnBean(ReactiveClientRegistrationRepository.class) + @ConditionalOnMissingBean + public ReactiveOAuth2AuthorizedClientService authorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + + @Bean + @ConditionalOnBean(ReactiveOAuth2AuthorizedClientService.class) + @ConditionalOnMissingBean + public ServerOAuth2AuthorizedClientRepository authorizedClientRepository( + ReactiveOAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( + authorizedClientService); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java deleted file mode 100644 index 325ae96191a3..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; - -/** - * {@link Configuration} used to map {@link OAuth2ClientProperties} to client - * registrations. - * - * @author Madhura Bhave - */ -@Configuration -@EnableConfigurationProperties(OAuth2ClientProperties.class) -@Conditional(ClientsConfiguredCondition.class) -class ReactiveOAuth2ClientRegistrationRepositoryConfiguration { - - private final OAuth2ClientProperties properties; - - ReactiveOAuth2ClientRegistrationRepositoryConfiguration( - OAuth2ClientProperties properties) { - this.properties = properties; - } - - @Bean - @ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class) - public InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() { - List registrations = new ArrayList<>( - OAuth2ClientPropertiesRegistrationAdapter - .getClientRegistrations(this.properties).values()); - return new InMemoryReactiveClientRegistrationRepository(registrations); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java deleted file mode 100644 index 31cf4b25c063..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; - -/** - * {@link Configuration} used to create an in-memory - * {@link ReactiveOAuth2AuthorizedClientService}. - * - * @author Madhura Bhave - * @since 2.1.0 - */ -@Configuration -public class ReactiveOAuth2WebSecurityConfiguration { - - @Bean - @ConditionalOnBean(ReactiveClientRegistrationRepository.class) - @ConditionalOnMissingBean - public ReactiveOAuth2AuthorizedClientService authorizedClientService( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - return new InMemoryReactiveOAuth2AuthorizedClientService( - clientRegistrationRepository); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java index f6c391317df9..5275807c27ec 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -15,14 +15,28 @@ */ package org.springframework.boot.autoconfigure.security.oauth2.client.reactive; +import java.util.ArrayList; +import java.util.List; + import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.core.AuthorizationGrantType; import static org.assertj.core.api.Assertions.assertThat; @@ -33,69 +47,161 @@ */ public class ReactiveOAuth2ClientAutoConfigurationTests { - private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration( AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class)); private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; @Test - public void autoConfigurationShouldImportConfigurations() { + public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(ClientRegistrationRepository.class)); + } + + @Test + public void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() { this.contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", REGISTRATION_PREFIX + ".foo.client-secret=secret", REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { - assertThat(context).hasSingleBean( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + ReactiveClientRegistrationRepository repository = context + .getBean(ReactiveClientRegistrationRepository.class); + ClientRegistration registration = repository + .findByRegistrationId("foo").block(); + assertThat(registration).isNotNull(); + assertThat(registration.getClientSecret()).isEqualTo("secret"); + }); + } + + @Test + public void authorizedClientServiceBeanIsConditionalOnClientRegistrationRepository() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class)); + } + + @Test + public void configurationRegistersAuthorizedClientServiceBean() { + this.contextRunner + .withUserConfiguration(ReactiveClientRepositoryConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean( + InMemoryReactiveClientRegistrationRepository.class)); + } + + @Test + public void authorizedClientServiceBeanIsConditionalOnMissingBean() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class) + .run((context) -> { assertThat(context) - .hasSingleBean(ReactiveOAuth2WebSecurityConfiguration.class); + .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class); + assertThat(context).hasBean("testAuthorizedClientService"); }); } @Test - public void autoConfigurationConditionalOnClassEnableWebFluxSecurity() { - FilteredClassLoader classLoader = new FilteredClassLoader( - EnableWebFluxSecurity.class); - this.contextRunner.withClassLoader(classLoader) - .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", - REGISTRATION_PREFIX + ".foo.client-secret=secret", - REGISTRATION_PREFIX + ".foo.provider=github") + public void authorizedClientRepositoryBeanIsConditionalOnAuthorizedClientService() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(ServerOAuth2AuthorizedClientRepository.class)); + } + + @Test + public void configurationRegistersAuthorizedClientRepositoryBean() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2AuthorizedClientServiceConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean( + AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.class)); + } + + @Test + public void authorizedClientRepositoryBeanIsConditionalOnMissingBean() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class) .run((context) -> { - assertThat(context).doesNotHaveBean( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); - assertThat(context).doesNotHaveBean( - ReactiveOAuth2WebSecurityConfiguration.class); + assertThat(context) + .hasSingleBean(ServerOAuth2AuthorizedClientRepository.class); + assertThat(context).hasBean("testAuthorizedClientRepository"); }); } + @Test + public void autoConfigurationConditionalOnClassFlux() { + assertWhenClassNotPresent(Flux.class); + } + + @Test + public void autoConfigurationConditionalOnClassEnableWebFluxSecurity() { + assertWhenClassNotPresent(EnableWebFluxSecurity.class); + } + @Test public void autoConfigurationConditionalOnClassClientRegistration() { - FilteredClassLoader classLoader = new FilteredClassLoader( - ClientRegistration.class); + assertWhenClassNotPresent(ClientRegistration.class); + } + + private void assertWhenClassNotPresent(Class classToFilter) { + FilteredClassLoader classLoader = new FilteredClassLoader(classToFilter); this.contextRunner.withClassLoader(classLoader) .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", REGISTRATION_PREFIX + ".foo.client-secret=secret", REGISTRATION_PREFIX + ".foo.provider=github") - .run((context) -> { - assertThat(context).doesNotHaveBean( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); - assertThat(context).doesNotHaveBean( - ReactiveOAuth2WebSecurityConfiguration.class); - }); + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class)); } - @Test - public void autoConfigurationConditionalOnReactiveWebApplication() { - WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations - .of(ReactiveOAuth2ClientAutoConfiguration.class)); - contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", - REGISTRATION_PREFIX + ".foo.client-secret=secret", - REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { - assertThat(context).doesNotHaveBean( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); - assertThat(context).doesNotHaveBean( - ReactiveOAuth2WebSecurityConfiguration.class); - }); + @Configuration + static class ReactiveClientRepositoryConfiguration { + + @Bean + public ReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>(); + registrations.add(getClientRegistration("first", "http://user-info-uri.com")); + registrations.add(getClientRegistration("second", "http://other-user-info")); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + + private ClientRegistration getClientRegistration(String id, String userInfoUri) { + ClientRegistration.Builder builder = ClientRegistration + .withRegistrationId(id); + builder.clientName("foo").clientId("foo").clientAuthenticationMethod( + org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .scope("read").clientSecret("secret") + .redirectUriTemplate("http://redirect-uri.com") + .authorizationUri("http://authorization-uri.com") + .tokenUri("http://token-uri.com").userInfoUri(userInfoUri) + .userNameAttributeName("login"); + return builder.build(); + } + + } + + @Configuration + @Import(ReactiveClientRepositoryConfiguration.class) + static class ReactiveOAuth2AuthorizedClientServiceConfiguration { + + @Bean + public ReactiveOAuth2AuthorizedClientService testAuthorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + + } + + @Configuration + @Import(ReactiveOAuth2AuthorizedClientServiceConfiguration.class) + static class ReactiveOAuth2AuthorizedClientRepositoryConfiguration { + + @Bean + public ServerOAuth2AuthorizedClientRepository testAuthorizedClientRepository( + ReactiveOAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( + authorizedClientService); + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java deleted file mode 100644 index 749d7b3b9dd7..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; - -import org.junit.Test; - -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link ReactiveOAuth2ClientRegistrationRepositoryConfiguration}. - * - * @author Madhura Bhave - */ -public class ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); - - private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; - - @Test - public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { - this.contextRunner - .withUserConfiguration( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) - .run((context) -> assertThat(context) - .doesNotHaveBean(ClientRegistrationRepository.class)); - } - - @Test - public void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() { - this.contextRunner - .withUserConfiguration( - ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) - .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", - REGISTRATION_PREFIX + ".foo.client-secret=secret", - REGISTRATION_PREFIX + ".foo.provider=github") - .run((context) -> { - ReactiveClientRegistrationRepository repository = context - .getBean(ReactiveClientRegistrationRepository.class); - ClientRegistration registration = repository - .findByRegistrationId("foo").block(); - assertThat(registration).isNotNull(); - assertThat(registration.getClientSecret()).isEqualTo("secret"); - }); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java deleted file mode 100644 index 4d1b9016324b..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.security.oauth2.client.reactive; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; - -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; -import org.springframework.security.oauth2.core.AuthorizationGrantType; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link ReactiveOAuth2WebSecurityConfiguration}. - * - * @author Madhura Bhave - */ -public class ReactiveOAuth2WebSecurityConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); - - @Test - public void authorizedClientServiceBeanIsConditionalOnClientRegistrationRepository() { - this.contextRunner - .withUserConfiguration(ReactiveOAuth2WebSecurityConfiguration.class) - .run((context) -> assertThat(context) - .doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class)); - } - - @Test - public void configurationRegistersAuthorizedClientServiceBean() { - this.contextRunner - .withUserConfiguration(ReactiveClientRepositoryConfiguration.class, - ReactiveOAuth2WebSecurityConfiguration.class) - .run((context) -> assertThat(context) - .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class)); - } - - @Test - public void authorizedClientServiceBeanIsConditionalOnMissingBean() { - this.contextRunner - .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, - ReactiveOAuth2WebSecurityConfiguration.class) - .run((context) -> { - assertThat(context) - .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class); - assertThat(context).hasBean("testAuthorizedClientService"); - }); - } - - @Configuration - static class ReactiveClientRepositoryConfiguration { - - @Bean - public ReactiveClientRegistrationRepository clientRegistrationRepository() { - List registrations = new ArrayList<>(); - registrations.add(getClientRegistration("first", "http://user-info-uri.com")); - registrations.add(getClientRegistration("second", "http://other-user-info")); - return new InMemoryReactiveClientRegistrationRepository(registrations); - } - - private ClientRegistration getClientRegistration(String id, String userInfoUri) { - ClientRegistration.Builder builder = ClientRegistration - .withRegistrationId(id); - builder.clientName("foo").clientId("foo").clientAuthenticationMethod( - org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC) - .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - .scope("read").clientSecret("secret") - .redirectUriTemplate("http://redirect-uri.com") - .authorizationUri("http://authorization-uri.com") - .tokenUri("http://token-uri.com").userInfoUri(userInfoUri) - .userNameAttributeName("login"); - return builder.build(); - } - - } - - @Configuration - @Import(ReactiveClientRepositoryConfiguration.class) - static class OAuth2AuthorizedClientServiceConfiguration { - - @Bean - public ReactiveOAuth2AuthorizedClientService testAuthorizedClientService( - ReactiveClientRegistrationRepository clientRegistrationRepository) { - return new InMemoryReactiveOAuth2AuthorizedClientService( - clientRegistrationRepository); - } - - } - -} From dcd568c4e3bec642a104b922b405fa5d405e00ca Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 11 Sep 2018 11:40:19 +0200 Subject: [PATCH 560/701] Upgrade to Spring Security 5.1.0.RC2 Closes gh-14407 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b70292d8f833..291bbb1e2db5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -170,7 +170,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.BUILD-SNAPSHOT + 5.1.0.RC2 Bean-BUILD-SNAPSHOT 3.0.3.RELEASE 3.23.1 From ff0ae3b5c0aeee69bf4948915dce34726b24e756 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 11 Sep 2018 11:41:24 +0200 Subject: [PATCH 561/701] Upgrade to Spring Session Bean-M3 Closes gh-14333 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 291bbb1e2db5..fac0137fed03 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -171,7 +171,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.RC2 - Bean-BUILD-SNAPSHOT + Bean-M3 3.0.3.RELEASE 3.23.1 3.1.0 From 74891a75bb84a0e78dc3e182242d6f0c855f8c06 Mon Sep 17 00:00:00 2001 From: LEVI PAUL Date: Mon, 10 Sep 2018 13:33:50 -0400 Subject: [PATCH 562/701] Include TaskExecutionAutoConfiguration in @WebMvcTest Closes gh-14400 --- .../main/resources/META-INF/spring.factories | 1 + ...TestAutoConfigurationIntegrationTests.java | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index 26f679a72ab2..fb1756d37b0c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -128,6 +128,7 @@ org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfigurati org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\ org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ +org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\ org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAutoConfigurationIntegrationTests.java index be3432fec3b6..8f7e5fbb462b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTestAutoConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,9 +23,13 @@ import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.context.ApplicationContext; +import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration; @@ -34,6 +38,7 @@ * Tests for the auto-configuration imported by {@link WebMvcTest}. * * @author Andy Wilkinson + * @author Levi Puot Paul */ @RunWith(SpringRunner.class) @WebMvcTest @@ -66,4 +71,20 @@ public void thymeleafAutoConfigurationWasImported() { .has(importedAutoConfiguration(ThymeleafAutoConfiguration.class)); } + @Test + public void taskExecutionAutoConfigurationWasImported() { + assertThat(this.applicationContext) + .has(importedAutoConfiguration(TaskExecutionAutoConfiguration.class)); + } + + @Test + public void asyncTaskExecutorWithApplicationTaskExecutor() { + assertThat(this.applicationContext.getBeansOfType(AsyncTaskExecutor.class)) + .hasSize(1); + assertThat(ReflectionTestUtils.getField( + this.applicationContext.getBean(RequestMappingHandlerAdapter.class), + "taskExecutor")).isSameAs( + this.applicationContext.getBean("applicationTaskExecutor")); + } + } From 94ebd337473075e2050e79bd53fe9a8d85c43e98 Mon Sep 17 00:00:00 2001 From: "Oliver B. Fischer" Date: Tue, 12 Sep 2017 22:21:13 +0200 Subject: [PATCH 563/701] Issue a warning from launch script when app will run as root See gh-10275 --- .../org/springframework/boot/loader/tools/launch.script | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script index 30e6ca41c74a..2ab9e71ecd3a 100755 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script @@ -128,6 +128,9 @@ log_file="$LOG_FOLDER/$LOG_FILENAME" # shellcheck disable=SC2012 [[ $(id -u) == "0" ]] && run_user=$(ls -ld "$jarfile" | awk '{print $3}') +# Issue an warning if the application will run as root +[[ $(id -u ${run_user}) == "0" ]] && { echoYellow "Application is running as root (UID 0). This is considered insecure."; } + # Find Java if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then javaexe="$JAVA_HOME/bin/java" From 1332fcb0ad332f67183f5149a16e4cffa54fc5bb Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 11 Sep 2018 12:12:43 +0100 Subject: [PATCH 564/701] Polish "Issue a warning from launch script when app will run as root" Closes gh-10275 --- .../org/springframework/boot/loader/tools/launch.script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script index 2ab9e71ecd3a..c79e808933be 100755 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script @@ -128,7 +128,7 @@ log_file="$LOG_FOLDER/$LOG_FILENAME" # shellcheck disable=SC2012 [[ $(id -u) == "0" ]] && run_user=$(ls -ld "$jarfile" | awk '{print $3}') -# Issue an warning if the application will run as root +# Issue a warning if the application will run as root [[ $(id -u ${run_user}) == "0" ]] && { echoYellow "Application is running as root (UID 0). This is considered insecure."; } # Find Java From f51a7e7d4690a08f22ea95cda5c6af530a808e91 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 11 Sep 2018 15:23:39 +0200 Subject: [PATCH 565/701] Upgrade to Tomcat 9.0.12 Closes gh-14408 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index fac0137fed03..5931535f2855 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -182,7 +182,7 @@ 2.3.0 2.0.1 3.0.1.RELEASE - 9.0.11 + 9.0.12 4.0.7 2.0.13.Final 3325375 From 2872579efe9491434a85f3a3b6bf8c673f5a3647 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 11 Sep 2018 15:24:34 +0200 Subject: [PATCH 566/701] Upgrade to Spring AMQP 2.1.0.M3 Closes gh-14409 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 5931535f2855..90ce5d47ddf5 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -158,7 +158,7 @@ 7.4.0 5.1.0.RC3 - 2.1.0.BUILD-SNAPSHOT + 2.1.0.M3 4.1.0.M3 2.0.2.RELEASE Lovelace-RC2 From 634c7bcc427282587fc7fa89c8e1f79d5b10c478 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 11 Sep 2018 20:06:43 +0100 Subject: [PATCH 567/701] Upgrade to Infinispan 9.3.3.Final Closes gh-14415 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8d374ba33c35..2bc3ccb25918 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -77,7 +77,7 @@ 4.1.4 4.5.6 4.4.10 - 9.3.2.Final + 9.3.3.Final 2.12 2.9.6 3.0.9 From cd2323358e047361a206b7cac1b89f5c3916d920 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 11 Sep 2018 20:06:44 +0100 Subject: [PATCH 568/701] Upgrade to Junit Jupiter 5.3.1 Closes gh-14416 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2bc3ccb25918..c8668742736d 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -118,7 +118,7 @@ 1.2 1.3.1 4.12 - 5.3.0 + 5.3.1 2.0.0 1.2.61 5.1.0.RC1 From 6041bc5bb0191d505b4727586d3ce18fc4146154 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 11 Sep 2018 20:09:20 +0100 Subject: [PATCH 569/701] Correct the permissions of scripts in archives of boot distribution Closes gh-14158 --- .../plugin/ApplicationPluginAction.java | 2 +- ...plicationPluginActionIntegrationTests.java | 32 +++++++++++++++++++ ...Tests-scriptsHaveCorrectPermissions.gradle | 13 ++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-scriptsHaveCorrectPermissions.gradle diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java index 0a9b83989640..fb4345321b32 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java @@ -80,7 +80,7 @@ public void execute(Project project) { bootStartScripts.getConventionMapping().map("defaultJvmOpts", applicationConvention::getApplicationDefaultJvmArgs); CopySpec binCopySpec = project.copySpec().into("bin").from(bootStartScripts); - binCopySpec.setFileMode(0x755); + binCopySpec.setFileMode(0755); distribution.getContents().with(binCopySpec); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java index 9fc22f37e594..a8dfbb3c5b0f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.function.Consumer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -156,6 +157,26 @@ public void applicationNameCanBeUsedToCustomizeDistributionName() throws IOExcep "custom-boot/bin/custom.bat"); } + @Test + public void scriptsHaveCorrectPermissions() throws IOException { + assertThat( + this.gradleBuild.build("bootDistTar").task(":bootDistTar").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + String name = this.gradleBuild.getProjectDir().getName(); + File distribution = new File(this.gradleBuild.getProjectDir(), + "build/distributions/" + name + "-boot.tar"); + assertThat(distribution).isFile(); + tarEntries(distribution, (entry) -> { + int filePermissions = entry.getMode() & 0777; + if (entry.isFile() && !entry.getName().startsWith(name + "-boot/bin/")) { + assertThat(filePermissions).isEqualTo(0644); + } + else { + assertThat(filePermissions).isEqualTo(0755); + } + }); + } + private List zipEntryNames(File distribution) throws IOException { List entryNames = new ArrayList<>(); try (ZipFile zipFile = new ZipFile(distribution)) { @@ -179,4 +200,15 @@ private List tarEntryNames(File distribution) throws IOException { return entryNames; } + private void tarEntries(File distribution, Consumer consumer) + throws IOException { + try (TarArchiveInputStream input = new TarArchiveInputStream( + new FileInputStream(distribution))) { + TarArchiveEntry entry; + while ((entry = input.getNextTarEntry()) != null) { + consumer.accept(entry); + } + } + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-scriptsHaveCorrectPermissions.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-scriptsHaveCorrectPermissions.gradle new file mode 100644 index 000000000000..3f06faff0e9b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-scriptsHaveCorrectPermissions.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'application' +apply plugin: 'java' + +bootJar { + mainClassName = 'com.example.ExampleApplication' +} From 78464f999f2dec6395f2cdec2f456d2c930de8e4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 11 Sep 2018 20:31:12 +0100 Subject: [PATCH 570/701] Test the Gradle plugin against Gradle 4.10 Closes gh-14417 --- .../boot/gradle/junit/GradleCompatibilitySuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java index a51778ef4e87..c25211041dc1 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java @@ -39,7 +39,7 @@ public final class GradleCompatibilitySuite extends Suite { private static final List GRADLE_VERSIONS = Arrays.asList("default", "4.1", - "4.2", "4.3", "4.4.1", "4.5.1", "4.6", "4.7", "4.8.1", "4.9"); + "4.2", "4.3", "4.4.1", "4.5.1", "4.6", "4.7", "4.8.1", "4.9", "4.10"); public GradleCompatibilitySuite(Class clazz) throws InitializationError { super(clazz, createRunners(clazz)); From 424dfc398b37e69a4e61e041091b073f1e098e9f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 12:46:37 -0700 Subject: [PATCH 571/701] Move 'insights.web' properties to 'spring.http' Relocate the 'spring.insights.web.log-request-details' property to 'spring.http.log-request-details'. Closes gh-14313 --- .../http/HttpEncodingProperties.java | 123 -------------- ...ttpMessageConvertersAutoConfiguration.java | 11 +- .../autoconfigure/http/HttpProperties.java | 159 ++++++++++++++++++ .../http/codec/CodecsAutoConfiguration.java | 10 +- .../insight/InsightsProperties.java | 54 ------ .../autoconfigure/insight/package-info.java | 20 --- .../DispatcherServletAutoConfiguration.java | 16 +- .../HttpEncodingAutoConfiguration.java | 16 +- .../appendix-application-properties.adoc | 8 +- .../src/main/asciidoc/using-spring-boot.adoc | 2 +- ...DocsAutoConfigurationIntegrationTests.java | 4 +- 11 files changed, 190 insertions(+), 233 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpEncodingProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/InsightsProperties.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/package-info.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpEncodingProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpEncodingProperties.java deleted file mode 100644 index 9706a1ddf619..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpEncodingProperties.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.http; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Locale; -import java.util.Map; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Configuration properties for http encoding. - * - * @author Stephane Nicoll - * @author Brian Clozel - * @since 1.2.0 - */ -@ConfigurationProperties(prefix = "spring.http.encoding") -public class HttpEncodingProperties { - - public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - - /** - * Charset of HTTP requests and responses. Added to the "Content-Type" header if not - * set explicitly. - */ - private Charset charset = DEFAULT_CHARSET; - - /** - * Whether to force the encoding to the configured charset on HTTP requests and - * responses. - */ - private Boolean force; - - /** - * Whether to force the encoding to the configured charset on HTTP requests. Defaults - * to true when "force" has not been specified. - */ - private Boolean forceRequest; - - /** - * Whether to force the encoding to the configured charset on HTTP responses. - */ - private Boolean forceResponse; - - /** - * Locale in which to encode mapping. - */ - private Map mapping; - - public Charset getCharset() { - return this.charset; - } - - public void setCharset(Charset charset) { - this.charset = charset; - } - - public boolean isForce() { - return Boolean.TRUE.equals(this.force); - } - - public void setForce(boolean force) { - this.force = force; - } - - public boolean isForceRequest() { - return Boolean.TRUE.equals(this.forceRequest); - } - - public void setForceRequest(boolean forceRequest) { - this.forceRequest = forceRequest; - } - - public boolean isForceResponse() { - return Boolean.TRUE.equals(this.forceResponse); - } - - public void setForceResponse(boolean forceResponse) { - this.forceResponse = forceResponse; - } - - public Map getMapping() { - return this.mapping; - } - - public void setMapping(Map mapping) { - this.mapping = mapping; - } - - public boolean shouldForce(Type type) { - Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest; - if (force == null) { - force = this.force; - } - if (force == null) { - force = (type == Type.REQUEST); - } - return force; - } - - public enum Type { - - REQUEST, RESPONSE - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java index 97aa3e346288..6a50195520c7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java @@ -74,21 +74,20 @@ public HttpMessageConverters messageConverters() { @Configuration @ConditionalOnClass(StringHttpMessageConverter.class) - @EnableConfigurationProperties(HttpEncodingProperties.class) + @EnableConfigurationProperties(HttpProperties.class) protected static class StringHttpMessageConverterConfiguration { - private final HttpEncodingProperties encodingProperties; + private final HttpProperties.Encoding properties; - protected StringHttpMessageConverterConfiguration( - HttpEncodingProperties encodingProperties) { - this.encodingProperties = encodingProperties; + protected StringHttpMessageConverterConfiguration(HttpProperties httpProperties) { + this.properties = httpProperties.getEncoding(); } @Bean @ConditionalOnMissingBean public StringHttpMessageConverter stringHttpMessageConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter( - this.encodingProperties.getCharset()); + this.properties.getCharset()); converter.setWriteAcceptCharset(false); return converter; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java new file mode 100644 index 000000000000..0ec8c88137ac --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java @@ -0,0 +1,159 @@ +/* + * Copyright 2012-2018 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.autoconfigure.http; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * HTTP properties. + * + * @author Phillip Webb + * @author Stephane Nicoll + * @author Brian Clozel + * @since 2.1.0 + */ +@ConfigurationProperties(prefix = "spring.http") +public class HttpProperties { + + /** + * Whether logging of (potentially sensitive) request details at DEBUG and TRACE level + * is allowed. + */ + private boolean logRequestDetails; + + /** + * HTTP encoding properties. + */ + private Encoding encoding = new Encoding(); + + public boolean isLogRequestDetails() { + return this.logRequestDetails; + } + + public void setLogRequestDetails(boolean logRequestDetails) { + this.logRequestDetails = logRequestDetails; + } + + public Encoding getEncoding() { + return this.encoding; + } + + public void setEncoding(Encoding encoding) { + this.encoding = encoding; + } + + /** + * Configuration properties for http encoding. + */ + public static class Encoding { + + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + + /** + * Charset of HTTP requests and responses. Added to the "Content-Type" header if + * not set explicitly. + */ + private Charset charset = DEFAULT_CHARSET; + + /** + * Whether to force the encoding to the configured charset on HTTP requests and + * responses. + */ + private Boolean force; + + /** + * Whether to force the encoding to the configured charset on HTTP requests. + * Defaults to true when "force" has not been specified. + */ + private Boolean forceRequest; + + /** + * Whether to force the encoding to the configured charset on HTTP responses. + */ + private Boolean forceResponse; + + /** + * Locale in which to encode mapping. + */ + private Map mapping; + + public Charset getCharset() { + return this.charset; + } + + public void setCharset(Charset charset) { + this.charset = charset; + } + + public boolean isForce() { + return Boolean.TRUE.equals(this.force); + } + + public void setForce(boolean force) { + this.force = force; + } + + public boolean isForceRequest() { + return Boolean.TRUE.equals(this.forceRequest); + } + + public void setForceRequest(boolean forceRequest) { + this.forceRequest = forceRequest; + } + + public boolean isForceResponse() { + return Boolean.TRUE.equals(this.forceResponse); + } + + public void setForceResponse(boolean forceResponse) { + this.forceResponse = forceResponse; + } + + public Map getMapping() { + return this.mapping; + } + + public void setMapping(Map mapping) { + this.mapping = mapping; + } + + public boolean shouldForce(Type type) { + Boolean force = (type != Type.REQUEST) ? this.forceResponse + : this.forceRequest; + if (force == null) { + force = this.force; + } + if (force == null) { + force = (type == Type.REQUEST); + } + return force; + } + + public enum Type { + + REQUEST, RESPONSE + + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java index 7e6ce073e280..2834f4072ca6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.insight.InsightsProperties; +import org.springframework.boot.autoconfigure.http.HttpProperties; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.codec.CodecCustomizer; @@ -67,13 +67,13 @@ public CodecCustomizer jacksonCodecCustomizer(ObjectMapper objectMapper) { } @Configuration - @EnableConfigurationProperties(InsightsProperties.class) + @EnableConfigurationProperties(HttpProperties.class) static class LoggingCodecConfiguration { @Bean - public CodecCustomizer loggingCodecCustomizer(InsightsProperties properties) { - return (configurer) -> configurer.defaultCodecs().enableLoggingRequestDetails( - properties.getWeb().isLogRequestDetails()); + public CodecCustomizer loggingCodecCustomizer(HttpProperties properties) { + return (configurer) -> configurer.defaultCodecs() + .enableLoggingRequestDetails(properties.isLogRequestDetails()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/InsightsProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/InsightsProperties.java deleted file mode 100644 index 488677e68d39..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/InsightsProperties.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2018 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.autoconfigure.insight; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Configuration properties for customizing application insights. - * - * @author Brian Clozel - * @since 2.1.0 - */ -@ConfigurationProperties(prefix = "spring.insights") -public class InsightsProperties { - - private final Web web = new Web(); - - public Web getWeb() { - return this.web; - } - - public static class Web { - - /** - * Whether logging of (potentially sensitive) request details at DEBUG and TRACE - * level is allowed. - */ - private boolean logRequestDetails; - - public boolean isLogRequestDetails() { - return this.logRequestDetails; - } - - public void setLogRequestDetails(boolean logRequestDetails) { - this.logRequestDetails = logRequestDetails; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/package-info.java deleted file mode 100644 index 7e91b5b0f082..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/insight/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2012-2018 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. - */ - -/** - * Auto-configuration for application insights. - */ -package org.springframework.boot.autoconfigure.insight; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java index 3a2161842b8f..134b88b7bf4d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration.java @@ -36,7 +36,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.autoconfigure.insight.InsightsProperties; +import org.springframework.boot.autoconfigure.http.HttpProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @@ -82,17 +82,17 @@ public class DispatcherServletAutoConfiguration { @Configuration @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) - @EnableConfigurationProperties({ WebMvcProperties.class, InsightsProperties.class }) + @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { - private final WebMvcProperties webMvcProperties; + private final HttpProperties httpProperties; - private final InsightsProperties insightsProperties; + private final WebMvcProperties webMvcProperties; - public DispatcherServletConfiguration(WebMvcProperties webMvcProperties, - InsightsProperties insightsProperties) { + public DispatcherServletConfiguration(HttpProperties httpProperties, + WebMvcProperties webMvcProperties) { + this.httpProperties = httpProperties; this.webMvcProperties = webMvcProperties; - this.insightsProperties = insightsProperties; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) @@ -105,7 +105,7 @@ public DispatcherServlet dispatcherServlet() { dispatcherServlet.setThrowExceptionIfNoHandlerFound( this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setEnableLoggingRequestDetails( - this.insightsProperties.getWeb().isLogRequestDetails()); + this.httpProperties.isLogRequestDetails()); return dispatcherServlet; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java index b24d4473b6c0..933b5b4c5767 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java @@ -21,8 +21,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.http.HttpEncodingProperties; -import org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type; +import org.springframework.boot.autoconfigure.http.HttpProperties; +import org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; @@ -41,16 +41,16 @@ * @since 1.2.0 */ @Configuration -@EnableConfigurationProperties(HttpEncodingProperties.class) +@EnableConfigurationProperties(HttpProperties.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { - private final HttpEncodingProperties properties; + private final HttpProperties.Encoding properties; - public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { - this.properties = properties; + public HttpEncodingAutoConfiguration(HttpProperties properties) { + this.properties = properties.getEncoding(); } @Bean @@ -71,9 +71,9 @@ public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() { private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer, Ordered { - private final HttpEncodingProperties properties; + private final HttpProperties.Encoding properties; - LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) { + LocaleCharsetMappingsCustomizer(HttpProperties.Encoding properties) { this.properties = properties; } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 648cef76b4a8..f744fa89c702 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -92,9 +92,6 @@ content into your application. Rather, pick only the properties that you need. # HAZELCAST ({sc-spring-boot-autoconfigure}/hazelcast/HazelcastProperties.{sc-ext}[HazelcastProperties]) spring.hazelcast.config= # The location of the configuration file to use to initialize Hazelcast. - # INSIGHTS ({sc-spring-boot-autoconfigure}/insight/InsightsProperties.{sc-ext}[InsightsProperties]) - spring.insights.web.log-request-details=false # Whether logging of (potentially sensitive) request details at DEBUG and TRACE level is allowed. - # PROJECT INFORMATION ({sc-spring-boot-autoconfigure}/info/ProjectInfoProperties.{sc-ext}[ProjectInfoProperties]) spring.info.build.location=classpath:META-INF/build-info.properties # Location of the generated build-info.properties file. spring.info.git.location=classpath:git.properties # Location of the generated git.properties file. @@ -331,16 +328,15 @@ content into your application. Rather, pick only the properties that you need. # SPRING HATEOAS ({sc-spring-boot-autoconfigure}/hateoas/HateoasProperties.{sc-ext}[HateoasProperties]) spring.hateoas.use-hal-as-default-json-media-type=true # Whether application/hal+json responses should be sent to requests that accept application/json. - # HTTP message conversion + # HTTP ({sc-spring-boot-autoconfigure}/http/HttpEncodingProperties.{sc-ext}[HttpProperties]) spring.http.converters.preferred-json-mapper= # Preferred JSON mapper to use for HTTP message conversion. By default, auto-detected according to the environment. - - # HTTP encoding ({sc-spring-boot-autoconfigure}/http/HttpEncodingProperties.{sc-ext}[HttpEncodingProperties]) spring.http.encoding.charset=UTF-8 # Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly. spring.http.encoding.enabled=true # Whether to enable http encoding support. spring.http.encoding.force= # Whether to force the encoding to the configured charset on HTTP requests and responses. spring.http.encoding.force-request= # Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when "force" has not been specified. spring.http.encoding.force-response= # Whether to force the encoding to the configured charset on HTTP responses. spring.http.encoding.mapping= # Locale in which to encode mapping. + spring.http.log-request-details=false # Whether logging of (potentially sensitive) request details at DEBUG and TRACE level is allowed. # MULTIPART ({sc-spring-boot-autoconfigure}/web/servlet/MultipartProperties.{sc-ext}[MultipartProperties]) spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index eb73013e49fb..1fb979c0767f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -788,7 +788,7 @@ Spring WebFlux applications, developer tools will enable DEBUG logging for the Spring Framework web infrastructure. This will give you information about the incoming request, which handler is processing it, the response outcome, etc. If you wish to log all request details (including potentially sensitive information), you can turn on -the `spring.insights.web.log-request-details` configuration property. +the `spring.http.log-request-details` configuration property. TIP: For a complete list of the properties that are applied by the devtools, see {sc-spring-boot-devtools}/env/DevToolsPropertyDefaultsPostProcessor.{sc-ext}[DevToolsPropertyDefaultsPostProcessor]. diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java index 31f93934eef1..0a10c845431b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java @@ -52,8 +52,8 @@ public void deleteSnippets() { @Test public void defaultSnippetsAreWritten() throws Exception { - this.webTestClient.get().uri("/").exchange().expectBody() - .consumeWith(document("default-snippets")); + this.webTestClient.get().uri("/").exchange().expectStatus().is2xxSuccessful() + .expectBody().consumeWith(document("default-snippets")); File defaultSnippetsDir = new File("target/generated-snippets/default-snippets"); assertThat(defaultSnippetsDir).exists(); assertThat(new File(defaultSnippetsDir, "curl-request.adoc")) From ab6bdc7ae20a4990d20cf39f0ce20d3846e1b739 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 31 Aug 2018 17:17:28 -0700 Subject: [PATCH 572/701] Apply springSecurity configurer to WebTestClient Also, @WebFluxTest now adds any ServerHttpSecurity beans to the context. Closes gh-13632 --- .../reactive/WebFluxTypeExcludeFilter.java | 11 +++++ .../WebTestClientAutoConfiguration.java | 14 +++++-- .../WebTestClientSecurityConfiguration.java | 38 ++++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 + ...AdvancedConfigurationIntegrationTests.java | 6 ++- ...DocsAutoConfigurationIntegrationTests.java | 2 + .../WebFluxTypeExcludeFilterTests.java | 10 +++++ .../WebTestClientAutoConfigurationTests.java | 40 +++++++++++++++++++ ...luxTestAllControllersIntegrationTests.java | 2 + .../WebFluxTestConverterIntegrationTests.java | 2 + ...FluxTestOneControllerIntegrationTests.java | 2 + 11 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java index 29449209b642..52bfd977ac66 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java @@ -29,6 +29,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.stereotype.Controller; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.reactive.config.WebFluxConfigurer; @@ -43,6 +44,9 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { private static final Set> DEFAULT_INCLUDES; + private static final String[] OPTIONAL_INCLUDES = { + "org.springframework.security.config.web.server.ServerHttpSecurity" }; + static { Set> includes = new LinkedHashSet<>(); includes.add(ControllerAdvice.class); @@ -51,6 +55,13 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { includes.add(Converter.class); includes.add(GenericConverter.class); includes.add(WebExceptionHandler.class); + for (String optionalInclude : OPTIONAL_INCLUDES) { + try { + includes.add(ClassUtils.forName(optionalInclude, null)); + } + catch (Exception ex) { + } + } DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java index 16946190c6b4..2eaa216ce96a 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java @@ -33,6 +33,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.web.reactive.server.MockServerConfigurer; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.server.WebHandler; @@ -47,6 +49,7 @@ @Configuration @ConditionalOnClass({ WebClient.class, WebTestClient.class }) @AutoConfigureAfter({ CodecsAutoConfiguration.class, WebFluxAutoConfiguration.class }) +@Import(WebTestClientSecurityConfiguration.class) @EnableConfigurationProperties public class WebTestClientAutoConfiguration { @@ -54,9 +57,14 @@ public class WebTestClientAutoConfiguration { @ConditionalOnMissingBean @ConditionalOnBean(WebHandler.class) public WebTestClient webTestClient(ApplicationContext applicationContext, - List customizers) { - WebTestClient.Builder builder = WebTestClient - .bindToApplicationContext(applicationContext).configureClient(); + List customizers, + List configurers) { + WebTestClient.MockServerSpec mockServerSpec = WebTestClient + .bindToApplicationContext(applicationContext); + for (MockServerConfigurer configurer : configurers) { + mockServerSpec.apply(configurer); + } + WebTestClient.Builder builder = mockServerSpec.configureClient(); for (WebTestClientBuilderCustomizer customizer : customizers) { customizer.customize(builder); } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java new file mode 100644 index 000000000000..ed33932de40f --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.web.reactive; + +/** Configuration for Spring Security's {@link org.springframework.test.web.reactive.server.WebTestClient} integration. +* + * @author Madhura Bhave + */ + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers; +import org.springframework.test.web.reactive.server.MockServerConfigurer; + +@Configuration +@ConditionalOnClass(SecurityMockServerConfigurers.class) +class WebTestClientSecurityConfiguration { + + @Bean + public MockServerConfigurer get() { + return SecurityMockServerConfigurers.springSecurity(); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index fb1756d37b0c..cbc25286c25b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -78,6 +78,8 @@ org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration # AutoConfigureWebClient auto-configuration imports org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient=\ +org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration # AutoConfigureWebFlux auto-configuration imports diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java index 8dbe16ae673c..93d77fe0b910 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java @@ -30,6 +30,7 @@ import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.restdocs.templates.TemplateFormats; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.FileSystemUtils; @@ -46,6 +47,7 @@ */ @RunWith(SpringRunner.class) @WebFluxTest +@WithMockUser @AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443) public class WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests { @@ -59,8 +61,8 @@ public void deleteSnippets() { @Test public void defaultSnippetsAreWritten() throws Exception { - this.webTestClient.get().uri("/").exchange().expectBody() - .consumeWith(document("default-snippets")); + this.webTestClient.get().uri("/").exchange().expectStatus().is2xxSuccessful() + .expectBody().consumeWith(document("default-snippets")); File defaultSnippetsDir = new File("target/generated-snippets/default-snippets"); assertThat(defaultSnippetsDir).exists(); assertThat(new File(defaultSnippetsDir, "curl-request.md")) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java index 0a10c845431b..bbf8689b08d7 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/restdocs/WebTestClientRestDocsAutoConfigurationIntegrationTests.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.FileSystemUtils; @@ -39,6 +40,7 @@ */ @RunWith(SpringRunner.class) @WebFluxTest +@WithMockUser @AutoConfigureRestDocs(uriScheme = "https", uriHost = "api.example.com", uriPort = 443) public class WebTestClientRestDocsAutoConfigurationIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java index f3ab2b13adbb..98b5f1122730 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java @@ -25,6 +25,7 @@ import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; @@ -53,6 +54,7 @@ public void matchWhenHasNoControllers() throws Exception { assertThat(excludes(filter, ExampleWeb.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse(); } @Test @@ -65,6 +67,7 @@ public void matchWhenHasController() throws Exception { assertThat(excludes(filter, ExampleWeb.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse(); } @Test @@ -77,6 +80,7 @@ public void matchNotUsingDefaultFilters() throws Exception { assertThat(excludes(filter, ExampleWeb.class)).isTrue(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isTrue(); } @Test @@ -89,6 +93,7 @@ public void matchWithIncludeFilter() throws Exception { assertThat(excludes(filter, ExampleWeb.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isFalse(); + assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse(); } @Test @@ -101,6 +106,7 @@ public void matchWithExcludeFilter() throws Exception { assertThat(excludes(filter, ExampleWeb.class)).isFalse(); assertThat(excludes(filter, ExampleService.class)).isTrue(); assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + assertThat(excludes(filter, ExampleServerHttpSecurity.class)).isFalse(); } private boolean excludes(WebFluxTypeExcludeFilter filter, Class type) @@ -164,4 +170,8 @@ static class ExampleRepository { } + static class ExampleServerHttpSecurity extends ServerHttpSecurity { + + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java index 8d1029d9957d..3801dbb9734e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java @@ -18,19 +18,24 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.List; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.http.codec.CodecConfigurer; +import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -80,6 +85,41 @@ public void shouldCustomizeTimeout() { }); } + @Test + @SuppressWarnings("unchecked") + public void shouldApplySpringSecurityConfigurer() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .run((context) -> { + WebTestClient webTestClient = context.getBean(WebTestClient.class); + WebTestClient.Builder builder = (WebTestClient.Builder) ReflectionTestUtils + .getField(webTestClient, "builder"); + WebHttpHandlerBuilder httpHandlerBuilder = (WebHttpHandlerBuilder) ReflectionTestUtils + .getField(builder, "httpHandlerBuilder"); + List filters = (List) ReflectionTestUtils + .getField(httpHandlerBuilder, "filters"); + assertThat(filters.get(0).getClass().getName()).isEqualTo( + "org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$MutatorFilter"); + }); + } + + @Test + @SuppressWarnings("unchecked") + public void shouldNotApplySpringSecurityConfigurerWhenSpringSecurityNotOnClassPath() { + FilteredClassLoader classLoader = new FilteredClassLoader( + SecurityMockServerConfigurers.class); + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withClassLoader(classLoader).run((context) -> { + WebTestClient webTestClient = context.getBean(WebTestClient.class); + WebTestClient.Builder builder = (WebTestClient.Builder) ReflectionTestUtils + .getField(webTestClient, "builder"); + WebHttpHandlerBuilder httpHandlerBuilder = (WebHttpHandlerBuilder) ReflectionTestUtils + .getField(builder, "httpHandlerBuilder"); + List filters = (List) ReflectionTestUtils + .getField(httpHandlerBuilder, "filters"); + assertThat(filters.size()).isEqualTo(0); + }); + } + @Configuration static class BaseConfiguration { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java index a87af480e3c4..d0dc7e9092d4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestAllControllersIntegrationTests.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; @@ -30,6 +31,7 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) +@WithMockUser @WebFluxTest public class WebFluxTestAllControllersIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java index 718e19adf787..f1efd012e14f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; @@ -32,6 +33,7 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) +@WithMockUser @WebFluxTest(controllers = ExampleController2.class) public class WebFluxTestConverterIntegrationTests { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java index 49bacba5916c..6f65e3f8e199 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; @@ -30,6 +31,7 @@ * @author Stephane Nicoll */ @RunWith(SpringRunner.class) +@WithMockUser @WebFluxTest(controllers = ExampleController1.class) public class WebFluxTestOneControllerIntegrationTests { From 0c00508b3cdec4d30641dd26d8503299e0391fd3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 14:21:56 -0700 Subject: [PATCH 573/701] Register ApplicationConversionService for context Update `SpringApplication` to automatically register the shared `ApplicationConversionService` instance with the `BeanFactory` and `Environment`. Closes gh-12148 --- .../boot/SpringApplication.java | 22 +++++++++++++++++- .../builder/SpringApplicationBuilder.java | 15 ++++++++++++ .../convert/ApplicationConversionService.java | 2 +- .../boot/SpringApplicationTests.java | 23 +++++++++++++++++++ .../simple/service/HelloWorldService.java | 13 +++++++++-- .../simple/SampleSimpleApplicationTests.java | 6 ++--- 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 3c17d435404d..d8f95d516ca4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -45,6 +45,7 @@ import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; @@ -214,6 +215,8 @@ public class SpringApplication { private boolean addCommandLineProperties = true; + private boolean addConversionService = true; + private Banner banner; private ResourceLoader resourceLoader; @@ -397,7 +400,6 @@ private void prepareContext(ConfigurableApplicationContext context, logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } - // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); @@ -503,6 +505,10 @@ private ConfigurableEnvironment getOrCreateEnvironment() { */ protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { + if (this.addConversionService) { + environment.setConversionService( + ApplicationConversionService.getSharedInstance()); + } configurePropertySources(environment, args); configureProfiles(environment, args); } @@ -644,6 +650,10 @@ protected void postProcessApplicationContext(ConfigurableApplicationContext cont .setClassLoader(this.resourceLoader.getClassLoader()); } } + if (this.addConversionService) { + context.getBeanFactory().setConversionService( + ApplicationConversionService.getSharedInstance()); + } } /** @@ -1046,6 +1056,16 @@ public void setAddCommandLineProperties(boolean addCommandLineProperties) { this.addCommandLineProperties = addCommandLineProperties; } + /** + * Sets if the {@link ApplicationConversionService} should be added to the application + * context's {@link Environment}. + * @param addConversionService if the application conversion service should be added + * @since 2.1.0 + */ + public void setAddConversionService(boolean addConversionService) { + this.addConversionService = addConversionService; + } + /** * Set default environment properties which will be used in addition to those in the * existing {@link Environment}. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java index e05f8868af28..50615b90b03f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java @@ -31,11 +31,13 @@ import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.util.StringUtils; @@ -370,6 +372,19 @@ public SpringApplicationBuilder addCommandLineProperties( return this; } + /** + * Flag to indicate if the {@link ApplicationConversionService} should be added to the + * application context's {@link Environment}. + * @param addConversionService if the conversion service should be added. + * @return the current builder + * @since 2.1.0 + */ + public SpringApplicationBuilder setAddConversionService( + boolean addConversionService) { + this.application.setAddConversionService(addConversionService); + return this; + } + /** * Default properties for the environment in the form {@code key=value} or * {@code key:value}. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java index 83ad9a07dedf..33aaab3a24a8 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java @@ -57,7 +57,7 @@ public ApplicationConversionService(StringValueResolver embeddedValueResolver) { * building it once needed. * @return the shared {@code ConversionService} instance (never {@code null}) */ - public static ConversionService getSharedInstance() { + public static ApplicationConversionService getSharedInstance() { ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance; if (sharedInstance == null) { synchronized (ApplicationConversionService.class) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index cb2274333079..8fd562e5f940 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -56,6 +56,7 @@ import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.SpringApplicationEvent; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.testsupport.rule.OutputCapture; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; @@ -597,6 +598,28 @@ public void disableCommandLinePropertySource() { matchingPropertySource(PropertySource.class, "commandLineArgs")); } + @Test + public void contextUsesApplicationConversionService() { + SpringApplication application = new SpringApplication(ExampleConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + this.context = application.run(); + assertThat(this.context.getBeanFactory().getConversionService()) + .isInstanceOf(ApplicationConversionService.class); + assertThat(this.context.getEnvironment().getConversionService()) + .isInstanceOf(ApplicationConversionService.class); + } + + @Test + public void contextWhenHasAddConversionServiceFalseUsesRegularConversionService() { + SpringApplication application = new SpringApplication(ExampleConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.setAddConversionService(false); + this.context = application.run(); + assertThat(this.context.getBeanFactory().getConversionService()).isNull(); + assertThat(this.context.getEnvironment().getConversionService()) + .isNotInstanceOf(ApplicationConversionService.class); + } + @Test public void runCommandLineRunnersAndApplicationRunners() { SpringApplication application = new SpringApplication(CommandLineRunConfig.class); diff --git a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java index 751a5cff4741..69ea7065dd7f 100644 --- a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java +++ b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2018 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,6 +16,8 @@ package sample.simple.service; +import java.time.Duration; + import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -25,8 +27,15 @@ public class HelloWorldService { @Value("${name:World}") private String name; + @Value("${duration:10s}") + private Duration duration; + public String getHelloMessage() { - return "Hello " + this.name; + return "Hello " + this.name + " for " + this.duration.getSeconds() + " seconds"; + } + + public Duration getDuration() { + return this.duration; } } diff --git a/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java b/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java index 4b70473be407..aeae98231043 100644 --- a/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -62,9 +62,9 @@ public void testDefaultSettings() throws Exception { @Test public void testCommandLineOverrides() throws Exception { - SampleSimpleApplication.main(new String[] { "--name=Gordon" }); + SampleSimpleApplication.main(new String[] { "--name=Gordon", "--duration=1m" }); String output = this.outputCapture.toString(); - assertThat(output).contains("Hello Gordon"); + assertThat(output).contains("Hello Gordon for 60 seconds"); } } From 57ec09a55fd0ac1850a3d4fe19dd396aa6219148 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 14:27:10 -0700 Subject: [PATCH 574/701] Polish --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../web/reactive/WebFluxTypeExcludeFilter.java | 1 + .../reactive/WebTestClientSecurityConfiguration.java | 12 +++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c8668742736d..de7834a5a638 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -156,7 +156,7 @@ 1.7.25 1.23 7.4.0 - + 5.1.0.RC3 2.1.0.M3 4.1.0.M3 diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java index 52bfd977ac66..68b5774bb6f1 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilter.java @@ -60,6 +60,7 @@ class WebFluxTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { includes.add(ClassUtils.forName(optionalInclude, null)); } catch (Exception ex) { + // Ignore } } DEFAULT_INCLUDES = Collections.unmodifiableSet(includes); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java index ed33932de40f..0c09b669299e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.boot.test.autoconfigure.web.reactive; -/** Configuration for Spring Security's {@link org.springframework.test.web.reactive.server.WebTestClient} integration. -* - * @author Madhura Bhave - */ +package org.springframework.boot.test.autoconfigure.web.reactive; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; @@ -26,6 +22,12 @@ import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers; import org.springframework.test.web.reactive.server.MockServerConfigurer; +/** + * Configuration for Spring Security's + * {@link org.springframework.test.web.reactive.server.WebTestClient} integration. + * + * @author Madhura Bhave + */ @Configuration @ConditionalOnClass(SecurityMockServerConfigurers.class) class WebTestClientSecurityConfiguration { From 84b6fff8c048731bae2a72687dd2dec06255317e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 14:28:28 -0700 Subject: [PATCH 575/701] Update copyright year for changed files --- .../amqp/DirectRabbitListenerContainerFactoryConfigurer.java | 2 +- .../amqp/SimpleRabbitListenerContainerFactoryConfigurer.java | 2 +- .../boot/autoconfigure/amqp/RabbitPropertiesTests.java | 2 +- .../web/reactive/WebFluxTypeExcludeFilterTests.java | 2 +- .../webclient/WebFluxTestConverterIntegrationTests.java | 2 +- .../webclient/WebFluxTestOneControllerIntegrationTests.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java index d3cd82b5300b..9fa00956d406 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/DirectRabbitListenerContainerFactoryConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java index 6321fab6090f..2155e72141ac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/SimpleRabbitListenerContainerFactoryConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java index 1872ce191a99..e3c0040b6b07 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitPropertiesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java index 98b5f1122730..bfa3f9aa2944 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebFluxTypeExcludeFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java index f1efd012e14f..20aef8c8ba5c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestConverterIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java index 6f65e3f8e199..666adc7ae9b3 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/webclient/WebFluxTestOneControllerIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. From aa2da0bb0d2de4b796b0ef8deab28c8c3ebc60d5 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 15:07:34 -0700 Subject: [PATCH 576/701] Remove logging level changes from devtools Update `DevToolsPropertyDefaultsPostProcessor` to remove custom logging level configuration. Unfortunately it's not easy to back-off logging overrides when the user has a custom logback/log4j configuration. Closes gh-14310 --- .../env/DevToolsPropertyDefaultsPostProcessor.java | 3 --- .../src/main/asciidoc/using-spring-boot.adoc | 7 ------- 2 files changed, 10 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index b96be7c75db8..d5e181b33fa4 100755 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -59,9 +59,6 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro devToolsProperties.put("server.error.include-stacktrace", "ALWAYS"); devToolsProperties.put("server.servlet.jsp.init-parameters.development", "true"); devToolsProperties.put("spring.reactor.stacktrace-mode.enabled", "true"); - devToolsProperties.put("logging.level.org.springframework.web", "DEBUG"); - devToolsProperties.put("logging.level.org.springframework.core.codec", "DEBUG"); - devToolsProperties.put("logging.level.org.springframework.http", "DEBUG"); PROPERTIES = Collections.unmodifiableMap(devToolsProperties); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 1fb979c0767f..42a1c3e12042 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -783,13 +783,6 @@ For example, Thymeleaf offers the `spring.thymeleaf.cache` property. Rather than to set these properties manually, the `spring-boot-devtools` module automatically applies sensible development-time configuration. -Because you need more information about web requests while developing Spring MVC and -Spring WebFlux applications, developer tools will enable DEBUG logging for the -Spring Framework web infrastructure. This will give you information about the incoming -request, which handler is processing it, the response outcome, etc. If you wish to log -all request details (including potentially sensitive information), you can turn on -the `spring.http.log-request-details` configuration property. - TIP: For a complete list of the properties that are applied by the devtools, see {sc-spring-boot-devtools}/env/DevToolsPropertyDefaultsPostProcessor.{sc-ext}[DevToolsPropertyDefaultsPostProcessor]. From 8ed516e9aeaaeaa2fb139e5fadcc6f150297a237 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 15:10:25 -0700 Subject: [PATCH 577/701] Polish --- .../boot/context/logging/LoggingApplicationListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java index 4e59f2c788b9..75d9227aae5d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java @@ -118,12 +118,12 @@ public class LoggingApplicationListener implements GenericApplicationListener { static { LOG_LEVEL_LOGGERS = new LinkedMultiValueMap<>(); LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.springframework.boot"); + LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.hibernate.SQL"); LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.springframework"); LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.tomcat"); LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.catalina"); LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.eclipse.jetty"); LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl"); - LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.hibernate.SQL"); } private static final Class[] EVENT_TYPES = { ApplicationStartingEvent.class, From 59e210642bfea371eee8cc6bb1e2d39546027c4f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 15:15:06 -0700 Subject: [PATCH 578/701] Upgrade plexus-utils to 3.1.0 Closes gh-14422 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index e7d801c6cf55..0126d2a3ab9a 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -196,7 +196,7 @@ org.codehaus.plexus plexus-utils - 3.0.24 + 3.1.0 org.eclipse.aether From 1f9754fc81aeddf0d3cbf72479b3968bc4377182 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 15:23:29 -0700 Subject: [PATCH 579/701] Upgrade to plexus-archiver to 3.6.0 Closes gh-14411 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 0126d2a3ab9a..3731acabd6f7 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -186,7 +186,7 @@ org.codehaus.plexus plexus-archiver - 2.8.1 + 3.6.0 org.codehaus.plexus From 894e0e11d43fc73b7c09e18a28e235a19fa588d1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 16:49:06 -0700 Subject: [PATCH 580/701] Switch from Aether to Maven Resolver Replace Aether dependencies with Maven Resolver following the Eclipse EOL announcement for Aether. Closes gh-7627 --- spring-boot-project/spring-boot-cli/pom.xml | 136 ++++++++++-------- ...DependencyManagementBomTransformation.java | 21 +++ .../spring-boot-parent/pom.xml | 89 ++++++------ .../spring-boot-test-support/pom.xml | 34 ++--- 4 files changed, 153 insertions(+), 127 deletions(-) diff --git a/spring-boot-project/spring-boot-cli/pom.xml b/spring-boot-project/spring-boot-cli/pom.xml index d5c63cd14f1d..37b67de351e9 100644 --- a/spring-boot-project/spring-boot-cli/pom.xml +++ b/spring-boot-project/spring-boot-cli/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -39,6 +40,20 @@ org.codehaus.groovy groovy + + org.sonatype.plexus + plexus-sec-dispatcher + + + org.sonatype.sisu + sisu-inject-plexus + + + org.sonatype.sisu + sisu-inject-bean + + + org.springframework spring-core @@ -47,53 +62,43 @@ org.springframework.security spring-security-crypto + + org.apache.httpcomponents + httpclient + org.apache.maven - maven-aether-provider - - - org.eclipse.sisu.plexus - org.eclipse.sisu - - + maven-model org.apache.maven maven-settings-builder - org.codehaus.plexus - plexus-component-api + org.apache.maven + maven-resolver-provider - * - * + com.google.guava + guava - org.eclipse.aether - aether-api - - - org.eclipse.aether - aether-connector-basic - - - org.eclipse.aether - aether-impl + org.apache.maven.resolver + maven-resolver-connector-basic - org.eclipse.aether - aether-spi + org.apache.maven.resolver + maven-resolver-impl - org.eclipse.aether - aether-transport-file + org.apache.maven.resolver + maven-resolver-transport-file - org.eclipse.aether - aether-transport-http + org.apache.maven.resolver + maven-resolver-transport-http jcl-over-slf4j @@ -101,10 +106,6 @@ - - org.eclipse.aether - aether-util - org.springframework.boot @@ -308,17 +309,23 @@ false - - + + - - - - + + + + @@ -328,12 +335,14 @@ + tofile="${project.build.directory}/homebrew/springboot.rb" + overwrite="true"> - @@ -347,20 +356,27 @@ false - - + + - + - - - - + + + + @@ -370,7 +386,8 @@ + tofile="${project.build.directory}/scoop/springboot.json" + overwrite="true"> @@ -382,8 +399,9 @@ - + diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyManagementBomTransformation.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyManagementBomTransformation.java index 848478ded3d4..5aca2953fcfd 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyManagementBomTransformation.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/DependencyManagementBomTransformation.java @@ -28,7 +28,9 @@ import java.util.Set; import groovy.grape.Grape; +import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; +import org.apache.maven.model.Parent; import org.apache.maven.model.Repository; import org.apache.maven.model.building.DefaultModelBuilder; import org.apache.maven.model.building.DefaultModelBuilderFactory; @@ -61,6 +63,7 @@ * @since 1.3.0 */ @Order(DependencyManagementBomTransformation.ORDER) +@SuppressWarnings("deprecation") public class DependencyManagementBomTransformation extends AnnotatedNodeASTTransformation { @@ -210,6 +213,19 @@ private Message createSyntaxErrorMessage(String message, ASTNode node) { private static class GrapeModelResolver implements ModelResolver { + @Override + public ModelSource resolveModel(Parent parent) throws UnresolvableModelException { + return resolveModel(parent.getGroupId(), parent.getArtifactId(), + parent.getVersion()); + } + + @Override + public ModelSource resolveModel(Dependency dependency) + throws UnresolvableModelException { + return resolveModel(dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion()); + } + @Override public ModelSource resolveModel(String groupId, String artifactId, String version) throws UnresolvableModelException { @@ -233,6 +249,11 @@ public void addRepository(Repository repository) throws InvalidRepositoryException { } + @Override + public void addRepository(Repository repository, boolean replace) + throws InvalidRepositoryException { + } + @Override public ModelResolver newCopy() { return this; diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 3731acabd6f7..d9fb115c80bc 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -23,8 +23,8 @@ 1.8 UTF-8 UTF-8 - 1.0.2.v20150114 - 3.1.1 + 3.5.4 + 1.1.1 1.0-groovy-2.4 @@ -78,6 +78,16 @@ + + org.sonatype.plexus + plexus-sec-dispatcher + 1.4 + + + org.sonatype.sisu + sisu-inject-plexus + 1.4.2 + com.squareup.okhttp okhttp @@ -128,11 +138,6 @@ ivy 2.3.0 - - org.apache.maven - maven-aether-provider - 3.2.1 - org.apache.maven maven-archiver @@ -168,6 +173,36 @@ maven-settings-builder ${maven.version} + + org.apache.maven + maven-model-builder + ${maven.version} + + + org.apache.maven + maven-resolver-provider + ${maven.version} + + + org.apache.maven.resolver + maven-resolver-connector-basic + ${maven-resolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-file + ${maven-resolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-http + ${maven-resolver.version} + + + org.apache.maven.resolver + maven-resolver-impl + ${maven-resolver.version} + org.apache.maven.shared maven-common-artifact-filters @@ -188,51 +223,11 @@ plexus-archiver 3.6.0 - - org.codehaus.plexus - plexus-component-api - 1.0-alpha-33 - org.codehaus.plexus plexus-utils 3.1.0 - - org.eclipse.aether - aether-api - ${aether.version} - - - org.eclipse.aether - aether-connector-basic - ${aether.version} - - - org.eclipse.aether - aether-impl - ${aether.version} - - - org.eclipse.aether - aether-spi - ${aether.version} - - - org.eclipse.aether - aether-transport-file - ${aether.version} - - - org.eclipse.aether - aether-transport-http - ${aether.version} - - - org.eclipse.aether - aether-util - ${aether.version} - org.sonatype.plexus plexus-build-api diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-test-support/pom.xml index d8140318c12b..150dab46f347 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/pom.xml @@ -26,35 +26,27 @@ + + org.apache.maven.resolver + maven-resolver-connector-basic + + + org.apache.maven.resolver + maven-resolver-impl + org.apache.maven - maven-aether-provider + maven-resolver-provider - org.eclipse.sisu.plexus - org.eclipse.sisu + com.google.guava + guava - org.eclipse.aether - aether-api - - - org.eclipse.aether - aether-connector-basic - - - org.eclipse.aether - aether-impl - - - org.eclipse.aether - aether-spi - - - org.eclipse.aether - aether-transport-http + org.apache.maven.resolver + maven-resolver-transport-http jcl-over-slf4j From bb19d5690c2d7f3a3fd82d33addf88a6c29e45bd Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 20:13:27 -0700 Subject: [PATCH 581/701] Fix spring-boot-actuator-autoconfigure test logs Add log4j to `spring-boot-actuator-autoconfigure` test scope so that we get valid log output. See gh-14148 --- .../spring-boot-actuator-autoconfigure/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index bd2f32275f8e..5aea66cbc2fb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -425,6 +425,16 @@ + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-api + test + org.aspectj aspectjrt From c6398d3eef0a649a4cfe5d329ad6319a9e360354 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:40:46 -0700 Subject: [PATCH 582/701] Polish --- spring-boot-project/spring-boot-dependencies/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index de7834a5a638..db4bc1d58958 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -1372,7 +1372,8 @@ org.apache.activemq artemis-server - ${artemis.version} + ${artemis.version} + commons-logging commons-logging From d5ba03c2ae48d1d13a1a9658abb81e195a9620c2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:44:21 -0700 Subject: [PATCH 583/701] Upgrade to maven-common-artifact-filters 3.0.1 Closes gh-14441 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index d9fb115c80bc..bc8a2e7d4032 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -206,7 +206,7 @@ org.apache.maven.shared maven-common-artifact-filters - 1.4 + 3.0.1 org.apache.maven.plugins From 869e8bba627e9e6b3dd5db64b2a2603395d49544 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:45:17 -0700 Subject: [PATCH 584/701] Upgrade to checkstyle 8.12 Closes gh-14439 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 02075aa623a5..1e03b7b4ad80 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ com.puppycrawl.tools checkstyle - 8.11 + 8.12 io.spring.javaformat From 3f8a5fd2e3a0246ae0dc6b7c88e43800400d34ba Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:45:51 -0700 Subject: [PATCH 585/701] Upgrade to zt-zip 1.13 Closes gh-14437 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index bc8a2e7d4032..8f14caa70a3d 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -252,7 +252,7 @@ org.zeroturnaround zt-zip - 1.7 + 1.13 From abd08418c0ffddba9fbcc15a783435f701d64881 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:46:22 -0700 Subject: [PATCH 586/701] Upgrade to testcontainers 1.8.3 Closes gh-14436 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 8f14caa70a3d..8cabcc34be6e 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -106,7 +106,7 @@ org.testcontainers testcontainers - 1.7.2 + 1.8.3 com.vaadin.external.google From 8b16630a492cb07d041f1972e07606a52b01e0ef Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:46:51 -0700 Subject: [PATCH 587/701] Upgrade to sisu-inject-plexus 2.6.0 Closes gh-14435 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 8cabcc34be6e..8251c4e75bbf 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -86,7 +86,7 @@ org.sonatype.sisu sisu-inject-plexus - 1.4.2 + 2.6.0 com.squareup.okhttp From e00a25472916accedd40786df5554059552df4bc Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:47:23 -0700 Subject: [PATCH 588/701] Upgrade to maven-plugin-annotations 3.5.2 Closes gh-14434 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 8251c4e75bbf..19b60de2fc47 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -216,7 +216,7 @@ org.apache.maven.plugin-tools maven-plugin-annotations - 3.2 + 3.5.2 org.codehaus.plexus From 6e64ae0921c048d29020412014e537bfee7a65e9 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:47:55 -0700 Subject: [PATCH 589/701] Upgrade to maven-archiver 3.2.0 Closes gh-14433 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 19b60de2fc47..85b99a6ca9bc 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -141,7 +141,7 @@ org.apache.maven maven-archiver - 2.6 + 3.2.0 org.apache.maven From 4adceec45f62e16b7960706364560ff452089991 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:48:23 -0700 Subject: [PATCH 590/701] Upgrade to Ivy 2.4.0 Closes gh-14432 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 85b99a6ca9bc..27b6943bdd7d 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -136,7 +136,7 @@ org.apache.ivy ivy - 2.3.0 + 2.4.0 org.apache.maven From 83a2031934c5692b0ab850c83dd9421e0387b838 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:48:52 -0700 Subject: [PATCH 591/701] Upgrade to Commons Compress 1.18 Closes gh-14431 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 27b6943bdd7d..ba641d415559 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -131,7 +131,7 @@ org.apache.commons commons-compress - 1.14 + 1.18 org.apache.ivy From 372fee11f56ba7718d0ff48b20774cdb2f769f19 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:49:22 -0700 Subject: [PATCH 592/701] Upgrade to JOpt Simple 5.0.4 Closes gh-14430 --- .../springframework/boot/cli/command/options/OptionHandler.java | 2 +- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHandler.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHandler.java index 871be69a999a..17d1beadd668 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHandler.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHandler.java @@ -58,7 +58,7 @@ public OptionSpecBuilder option(String name, String description) { return getParser().accepts(name, description); } - public OptionSpecBuilder option(Collection aliases, String description) { + public OptionSpecBuilder option(List aliases, String description) { return getParser().acceptsAll(aliases, description); } diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index ba641d415559..ee09f5e90cfa 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -126,7 +126,7 @@ net.sf.jopt-simple jopt-simple - 4.6 + 5.0.4 org.apache.commons From 9beab013f9bd499c1925d6b85690f7f859e10ff4 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:50:57 -0700 Subject: [PATCH 593/701] Upgrade to okhttp 3.11.0 Closes gh-14427 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index ee09f5e90cfa..da4a45cf0a12 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -96,7 +96,7 @@ com.squareup.okhttp3 okhttp - 3.9.0 + 3.11.0 com.squareup.okhttp3 From f0bfcd8947caea3b976d5096d530a9db14309aae Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:51:54 -0700 Subject: [PATCH 594/701] Drop okhttp 2.x managed dependency Closes gh-14442 --- spring-boot-project/spring-boot-parent/pom.xml | 5 ----- spring-boot-project/spring-boot/pom.xml | 5 ----- 2 files changed, 10 deletions(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index da4a45cf0a12..294d87eb1078 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -88,11 +88,6 @@ sisu-inject-plexus 2.6.0 - - com.squareup.okhttp - okhttp - 2.7.5 - com.squareup.okhttp3 okhttp diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index 77871ec32317..6debcfc73763 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -308,11 +308,6 @@ mssql-jdbc test - - com.squareup.okhttp - okhttp - test - com.squareup.okhttp3 okhttp From b41e135713be4b91e6c74c406ecfc49de765ea9b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:52:24 -0700 Subject: [PATCH 595/701] Upgrade to mockito-kotlin 1.6.0 Closes gh-14426 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index 294d87eb1078..a713c1b44fea 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -62,7 +62,7 @@ com.nhaarman mockito-kotlin - 1.5.0 + 1.6.0 org.jetbrains.kotlin From 670d9bd6f8166785c8ea8ebebdd946416999e93e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:52:53 -0700 Subject: [PATCH 596/701] Upgrade to classmate 1.4.0 Closes gh-14424 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index db4bc1d58958..4d6b4d0ade12 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -44,7 +44,7 @@ 1.8.22 2.6.2 3.6.0 - 1.3.4 + 1.4.0 1.11 2.5.0 3.8 From f99df9858811729b82cf95783a65ec7954a961f2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 21:59:00 -0700 Subject: [PATCH 597/701] Unify maven-shade-plugin version in parent POM Closes gh-14440 --- spring-boot-project/spring-boot-parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-parent/pom.xml b/spring-boot-project/spring-boot-parent/pom.xml index a713c1b44fea..1d4f2385a4c3 100644 --- a/spring-boot-project/spring-boot-parent/pom.xml +++ b/spring-boot-project/spring-boot-parent/pom.xml @@ -206,7 +206,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.2 + ${maven-shade-plugin.version} org.apache.maven.plugin-tools From a2cf2cd87fd8a85d5e7ba5abf09720845b83332f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 12 Sep 2018 17:06:03 +0100 Subject: [PATCH 598/701] Raise the minimum supported version of Gradle to 4.4 Closes gh-14418 --- .../src/main/asciidoc/build-tool-plugins.adoc | 2 +- .../src/main/asciidoc/getting-started.adoc | 6 +++--- .../gradle/wrapper/gradle-wrapper.jar | Bin 54208 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +-- .../spring-boot-gradle-plugin/gradlew | 6 +++--- .../src/main/asciidoc/index.adoc | 2 +- .../boot/gradle/plugin/SpringBootPlugin.java | 4 ++-- .../tasks/bundling/BootZipCopyAction.java | 2 +- .../junit/GradleCompatibilitySuite.java | 4 ++-- .../SpringBootPluginIntegrationTests.java | 10 +++++----- .../bundling/AbstractBootArchiveTests.java | 3 +-- 11 files changed, 20 insertions(+), 22 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc index 4a29dbe0a858..0c45a612b714 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -168,7 +168,7 @@ Advanced configuration options and examples are available in the == Spring Boot Gradle Plugin The Spring Boot Gradle Plugin provides Spring Boot support in Gradle, letting you package executable jar or war archives, run Spring Boot applications, and use the dependency -management provided by `spring-boot-dependencies`. It requires Gradle 4.0 or later. Please +management provided by `spring-boot-dependencies`. It requires Gradle 4.4 or later. Please refer to the plugin's documentation to learn more: * Reference ({spring-boot-gradle-plugin}/reference/html[HTML] and diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc index ff6b50b31b44..2e2ad1ca7023 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc @@ -50,7 +50,7 @@ Explicit build support is provided for the following build tools: |3.2+ |Gradle -|4.x +|4.4+ |=== @@ -199,8 +199,8 @@ scope. [[getting-started-gradle-installation]] ==== Gradle Installation -Spring Boot is compatible with Gradle 4. If you do not already have Gradle installed, you -can follow the instructions at https://gradle.org. +Spring Boot is compatible with Gradle 4.4 and later. If you do not already have Gradle +installed, you can follow the instructions at https://gradle.org. Spring Boot dependencies can be declared by using the `org.springframework.boot` `group`. Typically, your project declares dependencies to one or more diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.jar index 372a96843c88301252bbfac3291eda2ad0427492..01b8bf6b1f99cad9213fc495b33ad5bbab8efd20 100644 GIT binary patch delta 32243 zcmZ6yV{m0rw>6xOZFFqgM#r{o+ddtgIO*87ZFSr+JGPyi*m?Ut&sX);y+3xXS-a-i zRl91{m~)OX*6%Wij&cZOWjP2)OfWE5STHcKA7BZ{l>dSsVA4d;!3q4DIGHCIH?APp zZ(#o?t(*k%Kk1Xy|6QM$|FbqZ(sDulCrT=3+WF6y#+~@wk_hod!3~^}Oz=qo9AR+P zt5?5Fe%(gP`_JR7TkoOVNa0?CX^6u84M_Jp&UL#M^s;VIE59MtmY6ylh7~Bc{PgMy<|*k^XRIsn zW=AzN0x3$-T!&qR2OUgJH9^rKPB0dD(eyBDxPjkU{Haf1UfjMz*+2+;v`nJIzGC}n zA}HME)nN)9PmuE6^%xcR!eCVm2{g~WU#3`4n6O6@CQ<1U#{e8|UCJ>9jK;jT(kF-c zAxGVu5PX4`bwJbV(D1j%!;}t+A;f==`tnLg%n+_D{rR^8gS|LB@*9fY)>VGhFsa!5 zMs(uPA_TC;KOnd;g}9Y2tcesz%^vZUo|zk$0Ly6SP+KYMf{r$U^Js^-ip%(DcjT*e z6cfq$YDbXH92L()DZUu=s*7t% zA@oF`)O`*`PU|^(RNh(8FNdow=046hg z6F0XU9Ry>{We-86wN2buNn%audgB|@-`KBs_#upllIY-&iKx01jmGxz&Ez&Foa8gp z;I4YyabkNM3LDKXLW-u;in>om7eFjH#fwr#$AzU2Zil46d9II6n^y&4oB6w~z-CljrOp zqakLSXA1~u$M4=)eWp8FAfMIu%;Fc1)puafIw%vky?CPsoq4kkJ@8Bj(HFg)G||VL zB|Hm)f&fGaCr%Mh97RL-h6=OZls&VrzWX3a1n7(!eSemFPXX4QJljD4^g!G{{s8d4 z5d!RXu5X@No?*HjcZfk6gzTkIw(mk z_1YKwp~!3$B_3(W6y=c^mzbA|1RCn>)qwg^FHYE`gw3<1xkv=yu>D*h24RLW0%PH*Sw<%`pQulKN6v1hw7FOW41Xaav!OOnM zx-G}YuFusjVB&XLd=ASo?ROPpRkk2D*6hUZdN(bbMeNSZN4qQ=lbYbxH`^maeR_>^ zVrL*xlag7Ty~+w8MLqGtSnM{TIb9*o=#W|Gw^1lv)Y+h==QQz=;hk23eqW_f=&|8U zsVMBKwA`L@**;-)%yi8;J&+%1no!A~G~A?%ycai&`8`$B5kRnhO+<`8d7bIrg+i&; zx~9^E4p#xs+MJ!NEVE)Ge0uOyYcwqvj-sF0czj5ffsX)SgCX30B%qhDU^A?=UnXt* zYc=1x%x`vVA|s__Sz1OZS~-2MLQKuhZ7H{T?yadiO5B)(3rOvyH?G{Ck|u?GQBh6k zHP+11|K_T){xC7bhDzWkTPX`wxf#Pet12)JiV@BO*_f|q?z?IvUQ7-D{ZZzwBB!_T z*q(;DqHhUUB|Kc(2PI`%mr&@o&&X1jjrX(^6}o9wGHja5V~x7kbL{4`U$XJa>)QA| z)qb;*-F;hHf^V|NIsleR4!M$NeIDJT<~!Z&in$#m^z;9^iaGf(@d)|E z$;bLUUu^N@gsIWMMLHm%B3CBO^+g%2JrzH^Cs9r}AGlckUm0+MjCPtiGP{ znwkIzkZ>*!A*(g-@&?svu+6llw80!kcq+K37pl426s}{oMdy^Zi*4BK!F3N0!GM}+ zJtMo)1L0NX%0!nGlShz4YB|J`nPkwqESjV+yt4L)=FIlUy+?)+yc2-G&b;U*>`d!u zudv?a8;mxrq96*jFakS+OS(!;rlIQkB%N8gy)uh-!e2snpXSt(}K z5jXcG%HhP}u_Fwd=jYHzm@05q4_3n!Sjpn-Ocyb!htjD`OL=HV6j(`t@-DJ?n+#zY zv|FJ#3TSClHgk4S?2TT1_S22Ky(sC=xbM{>%CB?|Q82?|;Au(^aj}ST1aWa?a8-bl zgd}RIBDx>qX;u;Ce*KSysbUTbkC<+O?zC{?0o=OM9V%=RDD(g+jBb_g19QoFcL^yq zu7wbDIci*iIe8W1>ge>OJ$>dEX(8eodMSS+stncs@8cEJHDdOGh%*_cs=2PR6!Ip~ zHb)p^>k5=<*G@SxZ zrgVm>;tga!C@Gu|jzw#dxrn}=OXH6yxC*ad#reE`r5)QTMJKXu?;-Q#x_rO;&rX}A zNjC`LGF{?2ai^dcSDPkQL+LTzF7uftsCJnUts4bCU)Ix^+Pyb(zO(i~jvPQno>zq! z*?0#ORm{m;qzTk&ct)q|kF69GS6s<%$5f@bBaEE;9IL2iM4pt6PNsvq^bF#|J2f#! zo;Hr6j?-HGHI5ZME{6*FRu{icKR>>;PQf0nkG7&>J9r~==|)*aQ^SgSzV_yBo0ibl zq^vY(3;TXhjT~hy&2T^XIU|6oQdcxF^4Hrl!r861#?Q{5dQoiSvQFd zY-;om7)}$9t&-=yD*|L<8w%uy8qq6DZsE~n%wkqith9NUR-anoC1e1Hx2?I@w6yK% ziL&yI-RMbB@?W>$30!y#3STAoPy!li(0ViXGKJ{!+1U@bhn6Ery)-dtXvX!pWSNEw1ufy3?E6*)5pq{d}=n z{AZN29xXR+70b71iT>zUpV)t>`1(i_wPj)Rml>{?5wins+&4 zFBQpIshntp-?K7XEDYyXg!f86^qrF7n75mXjXWL|&FwSXEOv-)t21~tN~Zcqjcc-T z-@h8h*h8&t=~I~QjC*fVNY`F~bT{u)bkVAP-VI}Jm2xV&zES|6k1lQ;BFdI}#2YO0 zVYZHrJ@88=!YrJo4}KawRE7WznhzB99p0wkGWRsB_{fKC$Jj>&KAera&>=yr3%}Cf zF?vDaV$wHk{}($Mxe|6fB6}{{t{0 zfPAj8vBM$EiAH5EcOX&;)vzy`rTz3&>ZA}yz+Gu?W*W4ln9<41US9d)}7UWD(Xwg85{>Riz$ytHkaNf_Ix6`IgrKzmd zQpteg`&`os=C*;_1H)0Ri5oUI0CkF)3~wuOm~k1CKT3+%17?&;iiCnIRiM) zi3)!_kAZX&iHB@DIqME;oo49F8(qo;j-O}h$8&VQ2M?^-dFN315gKW1XP*Mnt--I3 z%EJMePxJ3@5z!w*%K`V--}p*!{N_dhZ>$mDV$exh2}U5}Se~JAt)(KX&BSL}2-$+E zT?mwt&M%DPcZ&xdy^u!8Jq^SNA>9IB?xHC1U#9}n$~ zhH@x{+UN6=0U6mV6sC~}Q%L^Re3juO1f<#S^E+Z9+4$nk!O9((jB-F4!+k zf_`x3+}$bYFA%MQ9@8C+q4ftZshWC1oBW$fWH+@l;XddlH0Dl?SxqMA55ayP>rwZp z`mMJ(;i~bQW^FIhxlg%cX);lvQ_OQTn#*xS$7n>`Xe5VC;oIrUL-8|Df+0ZRtmawe z5j@MHfO?$I=+KF?gKw3RygC_ptM5r^&Y6SD}Yo!l3Gz<$fm zlX$g)8;HSv>&!FlS-cPJXzA}X>6aY@$Zw#IUdZ8%HzF09W-zIhFhEe6Bfl=9yS7UF z1PggPMK`);plebqNO)pj0|DI5UfFO(wUX7P*RgR}*HE3sggrI~@0Lj@VpqlOt7PHQ2EP+s7yBDm&lwvQM_Bmq6v$E z^Wn66eGXEf7mkMRHxO*Xw&3Gh)?iXso3eH zRu2n@vAiDLQZXYh$B>_+!xA==htGyB2;Jj(?gaiHrX?_f1{lmoYjoKU6o`@g@>O~D?`ljyX~&p(=I;$Z4%j~S z(*k^4OA$lxgs$`D4s;+3M8a{(+w#JUI2$ z2Pu)5+Xhu9a0vxzPB}D|NY-6+Ml~sWv6}dfjH|Nf`Hps*iwZ9~E^qi$hPmCJ%THmI zl|()~hy!Xdv|JPhJ&+LadTD3X1agFZY^s$7JZ<*gSG0Gbg0}Xs&MQ+q7`(Xn0cg*y z{QL~FDNh@^#vT31hl?d5QpQ@vS|}rS;Dsdh6=%GP{Yb@tzpjfWu0x)eI}sve1~lfS zkb6FL^21k!m*Z*=<1zQtHMmlA0K+lYQig5Kw<8mQ^d=ihz5Dmoi)yD7!i=6Hy}yqf>A)Uab9**kE4vL9)la&D>TvSrwO#+Y|>Dvel# z7)|J5QInN(lUH9MQuzii(J}Uhx%IZjlzAxjC$oC z86bI+Abp4oo6CkL!EjouJ1}KUzX99Qd<$fIYrmNqH0b^yc#mc%EK#-QidH`H%RBU1WUTf zwt^z_kPkSinT;7E&1Od`p=cQ?`?pLGHIW2mPhH~w=20GRjvnRbgqd8i$j zhx^PMNIJ`l+XB7NWnZZsIA&#!E^eckI%Sti$g(y2b}PqP#BB#{2uo#U`aqI91~8(()an}v}UDrg?*EJu7Y0}Uo>p*B3% zT2g^?3crikIcF+hZey?};p`1izF(duPcnN%f0mqZo#60uV;a|j0}8%-&KSfuFJ0s@ zQf6e6+oku3PbD;t<0J?b%w9_4aE)(GBW1zV)Hm@~MYnDMKy89}1cNsvZkJah|kNOX&uGjZOlnnej6b2`D)DUbZWIAO}lI%kxqa} zycUve)behE_)#I&g~jcSN5ifCgw=&GD~EX>-8MpyFNUcu1{VZa$vORrj3NRdLLJ51 zRpU(c0cb{mLd?yfap`;n)ENdcp`N~=A+p2;uY8x)EfJ}@>4KnXeilWfTP_@>Vf>TM zFfrS$dt|=98vzI((I**>XOE7h=p}w>?!;Zpu5bx*Y{`re#3Y^zeASWqQkDD6-!-fP z*7Vw3ywUW^VEo>$c0l@MDb_oY`fMroBv|l5&wg|OADnenIAo4F&pW2pzPB9=3)A|) z56G|TOn57+UD4+s^u`43;hW&Rg2NE(9Mb9q3gG@HBqd+8%N@P)#~;~qWY!y2pI?zm z65MVpj9gW?7HAk5&V5Exlg*XOcGXzYVS>d$WCL#16B3$3rgIa?<&D0aOBWiN#|lfw z4g@0r2Y=i?DP+KJmaRcpyhYt18bPALGM+drA=@WVAoqA?&P<&!L@|6qD; zGgdl`pCC{I9v_QMN>VHgl~pMzt9>yXYd@=h#?%J+tx(@E?F~Qq5R@6?Y)T%z{(?2q zBwz-;lQ}Wntafjh_Tra0>q^Xs)1q2^!Tj$!3t8d2sSgeYrUD7pG-8krj{ZLiz(y$+rJGfQt=$7xd!J9*t(x#z|9hwN2zI%&@ z5yy{zn88n1dJ_<9g3$cchevN*09bjyG2n$NcGT!vcVw{gMy%eStBYTpk7`i ze4dj9-V@F5lZlN|V|w>SwXpmZ)?C~4d#^?bZ=di3{ndusZXBStLHk{a|BiicJn^5y zaJs-y;;Lu3z{(vfI%tqv&>G>#Wlln^*c)``E6U}?`6=IGn^k>RofZiyfVYx(dC*0W z7mui3wc)@zOGF|(Ltf8!9&dghSBykmd~20+WsC6iY!X!Asq%PreuX#rBW)@e8!g2# zmeOpAE9m6`NesLf*)4RwlB}V4E=z`hOEu(mx1BVFqsZ4^T50%T3+lDHL0i|@U`Rd| zD5dr)y#bpieY(FdN!L9H*t+ua6!c|~De{N=glDJ~*0yhCG*F67G-?@b_<82KRZ<2? zM;MciyG0a@FHl3Elp)Y;Dyb_9nVf8+o5Q-78h2jN+#mn<#aD8_!8trb`eY2v=7I=6 zJZ8Mm@|FizCRh#u4qCBmTU?6iCgbnYfXQ9K`Cg2p0}Rm7iP6-zUOqxn9_?7jX(+_T^Jmo42IG;#^x8V!aRj zU6}2-IR=V3{3%mOI6bsS{vo*-5v#|`krmKOg@4YRO(k(;#7SLvcNofNoVB|+u~!)E zkO0o9AAQadv!{vFwquDT<-*=I7X~jg$b7?LpmCxo2?QVz0OpSnS+hpdG4TQ;jcA`+ zfZIE5L%dYVt_&FLCrt`pQgF7X50zVicwOnvZSbXYN?qr~G^rWz0qaK%Kliq9n6j`s|!vl%2Cdo&jfN zsen4E6bp~_Bn}dT6f^ex^qxl$pU<>Zw6>FUi=cpS6*$&x8ZyHh^uXh^i#)To%qhg2xYWFcUx*egI$ai|3 z*H+tRNsDeJRicO;OHiFH;lZS_&06c=A>E5R?S;2pq}&^mV3gd!@?Tjx<0!B zF+EISrz6)sd{v|C;FyE0!KK9a<0wjK(>?n>M;^>8u1t>vQ}70}C;g2#xtn9^krSY@ zOkVF@+s2N-<&-eFQK$iB1QP_79uH3njy;5ufC?XS@Q;4L(B zryJs#kd?Kb>a`D3Ny<#~mYV-*`s>Ynb=()qscF;K5xCvfI~j*fLF**%CjOX(qSj2yXZ*1d^C`SnLY)?{E@e zecs>==f;#6?$e-;U&ec|1A6oVrk3K$eo{J)P3F)$5mWCLZ8D-#e)C_Pdy9e#lvi1zFo1Vp zzP<4ZjxtOm&5UT)H!W%B63FX3Q7l@V=2S>IipzogI@V|ryHkovy_9@_sP!qPZA2qY z^svq%v`=I4U*daiB{CXrIlYM`rM*H;&T=kAlU3(>d-#bCXia(3Lr76IZBBxFCF2K3 zrrZHMSKX}PPTVdp(%&A8o857#OLGQDNFYqP#4$M(JTiefs zEQlf?5aNq{tR$HLdGEWbGEG&^;PLnO=$deH%A ze4oet0p=MHAL0SSIvsLT?>sp3R)ih7qS#b~x^hk;&Au&G_o5y!pr8)^xU8~HqtP2` z5R}&GqoL@jFx|%vwfZ+F&ET-rNCdm>K)boiyQOtNr~25)EuRu~dM^>qp2mDRX|$GW zG_KA)ZS%uDXVFiKlgqM!HhM}&KXcfk>sn0099|EYMdduKGj5I4Y|-#w$dK^+cS^5R zgM)YA{%?xf%-`&Q>CW+HrJXbO)@rExsl!?-dK!rDB=!-rKNgLN)vSb*PVh9Zzv&I4 z3U>YkwC(C_{AKZ;8FBk#!<%W4ZqyrZP?KlLBKOQMUIRg><9_An502GpX%NS^o-xEv zrm$#ZrIybhZ6J7F#_A~-^Uxy@#gS)|(t-*1I(^kTs+}c&sy9mGs4arz=9jvWIGsuSk&}=aj#o^5vBW81+B5u?BgudU&xrl(fVq&kn_O zgc$zXtR$Qnyn{26IYCID4o*M3|BY~IUE)$^_e8`Wc{(>DqJ!;s^&>W^b>m{H(8w2n z4#Cd5b5J260Ef$9K{|Ob0N?eK!VAHxW23EogT9PKx)dv!B`6>a*F%jcO*SpscuuAo z=L_Y3_q$2l@JIi3wdj(e!XW)mx0{2|Awq!x2KJZ)5T*xU9kvKlKOId^P1Qq*wpWv* zj}dut(BLJKG?0>*u#)UicqPVcP)_H_p`U9KYwBJWdbDAAm6vF!qjS);dMvN$*0e4y zS=j|#Rt3~Ko%+=|(Ov^A9UUDLfBZg3bF%C`tp0NAy$kSpa8eSK6GwO{LVa)%!IQ|$ z=kS>iy`2Rd$Q6wrx1*-qdWTUzM{EZ&iIe8im?ag{!h+0m$rMZ?%3M_<9QSSJL$Pv+ z3TXwzj%L)oHGf%!dn4Py=b;y#3UCjV-3px2rXF#G9fw;Z$D_Ewr2)%RCk~qQGvRIM z?mD8XunbWT!r++`aihgJ^3tTg=1G{7j$P57+;IW?Z^J4Ktw&>UC+d@eerX7s_vZ-~mj36n+@e6Hbxxg)hrA2@M_JL5Jyy zHUmdte2N6PWz=x@rn)6|5ilK7Wc0+E~1VPrK@hnr1 znJe0PL^w>Fotqj6Xl4#71p>=<{jV3i+8moF4)LXlM@(idxSY1@>#^ppHAKsVtCfHr z8V&-tZ-1bsIrd9?5>E>gmFCVDIC*}o zG(9605ZDFq_BUzq-H`-=DnMLthl)7lAm8a$jfmD(A#bBLk5T~^4@%=qF3C!bX}a0; zRhyL-&>zb|HvZQ}hZfQVFd%l!yi>KWS-x8G<+?BVs$<4x?Zi9ULNFi3Cf4_OP40}i zTs0}t-a0?n$F=eftGI(!)g{1{tA&!3kwMyAFFS3ojxL+#+P-bbZ*|jJ9AmMbO~q4{ z(FLC|@o`&j0)b=vo=wRv2l4C#Hz&BZ3%_u%TS+AcjN!;|K!KVy{f6daoBmo;eF&r}C;C6h)Kf1#N{PA^*o zJ4rx8PDhRKXzNxuei!zW{i6VBht4{SdmOk(Y04@XN2At2W>Pcd{a4CP5oxAv~`60j7FNA6=h^83gXRe zNWP5FCwJ5fz%}CW9GSO0D2B#Opn#Gxcl`-Djhf)0^O1NQnoOG&pn}~1^ro{kM{k)y zn;>R2Z&PN%m-Ux0>nJ1TD-fL9OiKw#uap&VOKMYRS~6zL3!wrSsWafr6Gl(#)f<0P zOFB;FZ0^f(ryD;tAej=i!A5G*rK#@r8YR`teKRO6$0ci)hRyN04Q-6hCDo0NS2}O+ zu!vYfFVOH|Yi>nmHl&N55e^!r&eC%8#X)h?q0-mPZtiL-vWQr`OgoeEIjD#wlX>%_wBk68cngpPoTn_G+(fLH4fLGJyQVJJNyZ{-FDDn*QzgB?~Eze zM?G}ggHN($~WryB6sIXs8-SXZvDeln*f&K2aQrQgg&S=>au2Um0 z;wiHKu?q0+ur<;AkuF;7L)}kSFf5b>NhdtHtzyHxS#*Ui*7Z>i*(t(j{u!mgF*JQYdrob|G{a<5(OmmcfX)w}}- zkZZeXBe%{&500VvjYGRr$-6_kN}jxiP7t|;lNO-M$qu)#T}V!VkwBU0_@mjK3qq2> z^YlG_vyPpP?>`q_3d{*%3d&s)oiL?S$PMm? z{4W53E&Ki{EatO7?BGeq%)nj@_YWzj)6Yq7r`H+%r76La`6>&>YrHtlYQ71lLUav z7!UHOHk(yiUO(ygo1k_my;ikE-vxHw#4{aw0N@HTV z9vf+g?2F^7MX4NI<8GgDhOqgzLuhUkACZ(LMNW{Vv6;ypBe|-3K9x&xWw;A*Ngdx_ z*TYz zlh$P66K4~=h+>JGwB&K5vEqb`u@1_~HViu;vmCq}o*)SOw@b;wmFu2}cO)R^(4Dua z*zw|h@y z%iL|cFpvK?edzTTy4IQBX9D8F4dVAFWCDC#naO{8)(Xmw>bDsH5F+rhm}<{Tk(AQc&6T*nROM2h-8g0WSo=-8pb*h_yBjszj%)%Wo|8w z1|%CtU)?Ll-PhnU%!g5@H^34X8M)Q7blJXk|KMrw9{em7M?t5Ck2N7$brbNRDJO~9 z@*o_AEt5QUWH{~IzKf#KPjm?WCr5|nLcmrq33hOq;3BDz11AxGAB@Ht@_+F94o(hL zgR^%o>j$kUKGAUrTmVK`xjFx?a(#C}@L=ec2NhCcIdhOoPF?=6)X6Q`_q$2)0QJlF${osXU&DRf63ALjogAs z;T1k0<&O_W#)=O{g=;oDy?@d!*v;)-JHBVlV9-2zJ+S6@Wpjm zaHhVGd@Wo)K%a+2T1|IiAjsKK!sieS>v3W6xcp>J#WhuQlufzzXLSlkNF~V&xYRT! zQ(H_n{i$Rp96I1|9`_!p6IWfdIn*&IAV6DBvTdGl)*kx4JLzhmx`QLBH?j>Z0HNwb z+lPB;r~B+|F!lt&CY-k0^H*tGD#~n(#CKwPMv>HcqS^^L%MR9@ZZ?2Sa6bSPhk2>|_>3%u#sH5&&aq09OlhgZ!e?+(AHkxgaiTVF!+cNJ-kIWO%RBlTgU@syxJW= zqN33s*KqfhaahI2sJ@LJXJtXniZj2#2U-elB`WEwzUQCe0ZQ@%`*WJV|I}_TF;3Wv zFx;9ylN#MiUD_B=T@qPgu3S72l9Yo~lKTj^S#_SA_Q-aH`fe!k5-~~}@rR`llKd3HYVd}F9Fw9DIIRvA!R5q1p`||lleHr}>VxmTN1<0yRuEIQnB^^7 z{TF%O)%e97?uz{?f7pAGLrbV@@>(xdFT%P#zIl9LLxMBNIX_QxG1MK-a=}is5oofgW{suk&;~TYfnKG}SoK$@vp7UpR zNGI;i=@TfGe!v2=TH%cq)^@KaJLYL4SM1~^$ZU;x@7l+=U!m+>sQsYe%Z%iV;UFp` zM14`$u-^6OwBf{5h`XZQ4sNBx16FnLIsDlU&vRX`#ZSDA_g1_Yq+0$bMZSL~f81gK zCyS<8zt6`#uL}p!$Ks-r-P7FJ4_imVVvia&zz0~4un0bdTC;Kg2%f}bTSW`iGZ|J` zO7IlZ;$VMj;94V;j|BPv)YO}G<%B1_;oaskLe{sgdHbVvDfYDf;OHAy)J`0-!YA_h zKX)z%XgKybDrjqd#vgtr4Q~yn0zYv9D08Ob0Z2!6qLXc;1AeH-TI9WTQu5alLjn;r zD=2&@gIn=?A1>OjsHSG9&H~^hy(l{$$o1&ko)FoB5hFOKl-eJ*_QK2y^gHe0mUC4< zO;I-(d}9s6)9kFNKO(k%rV)>95HBdrdj0Y7TL^j_#hn4j3wsC%XKW2z8^i$tPV?)? z&29&5^gS+)!)d<*ef#4E-9cu>PilH%!-mJ3` z-qp2v8?R5M2Hex!p>x`tZ~pwSZYIP}Kcw(j_W}MwDPihF=A82=YW?HI`bwk_x@BT5 zguU6Z|(m=x`e0+Xes(2S7E^YWg0(b7;AG zK1Xd#n|mPTF{f`BSy||j@x_E^q;k55Dfkxm30Hq2Ay6in=Jpl*xLxpQq`df!1K-sr zdh#_b0xr%@hAr0r5f?G63?jEm%i6!#6ap)a_*@;U#zmusKAp)2Tt%(?NCG^M5f#HIls{<&Jc`W7g5*oSsM{f zM#PF(%wf=^_5D5Jge#=pHd!4wS6y0#|6u!rlb9w9-X&P4s9e1jOKsmhns((abJ+Qx zz2s1QRb3W~Q>EHE(!IY?p~TuLLsEg$L7_!6)>dOqZsVe|fEZnkGYJu}Z}A|0V%=nE z2b^X>i?l>Z7Nb;AxpyVA%E~mPnv;n?G5D+59HncTeg&GO%ha9NQ=XfBYIfbE__O=R zrk-%N6?1`1UjPk)^J$Xh$<`;4OSg79(UFYYreQ_?+aMtd-m-ax82zfelrt7=7+U2JBBZYl!p3VoK4LoVB<37r^}ihT$SIaf%7ulT;i zD9PV7jU$|6j?U;!oa1s&SD#w1=+bVMo@}fury3RYELaJF(zB!H#@ZD}4}kZj|Kll_ zuVVev8}xy#BR2A4VNQ&%4r0mIS)*Z33LlOk_rI#{i2c_OuTBL}-KS`H&}!ZtDFbX+ z@cd^}#>H()M+3#icqQO~YGSBKVtGG{e-=id0}7*7l2k@|VHHNcv6C$iFbem4sP}UmGsx?EKo-@+cIL zeI45O6K_#t+*`dho4hAt-QB)Jw=AU>cPy36vI>P5GEJ$EZv)rrH=i!VeBI8N=00le z+B(ZmDO(ykMp4gFq7d_5JXHH|LAFo43czZKQnG~zZK962~il!ipWz)ofsxT$@xpI%1Al@nk@IfYYcDDrO60cdK>TiKY%yUnfUF$kaggx|Ls2r)O@+{ZSWsBaU&-M6=5Yg*CHfM*`NTtF#aJC z6;cKV?i#xFf-4SuF`UDqu88grnl@WzX*+s}P#d<=kOld4`SysYr*r0=VeZ3W7-zWZ zab2c7{~N1kvBhio(j*zG1SVo%%e;xtN3X}vN1M<0x8-fH?w{ADD?w1WPQ$1JqWrD< zru^70GTKhjyRHP+JF)~?1yKMK8A+x%0S?^jahjo7l?PqyRHkY>m2RBneF#Vz&fSHdsY z0lA3NVSNjk7TzQh#zdojHu@5%O~X`{jXyKZ@T4mu}I?%zRba;$@^u{dcMDr&QAr9o&r#MZGsB?Z`AjGis|DY?iWDFhZxY zZ6~WznU1bZhurHh=HCE4(fo*n%InS2r1s3`lb^X(7_~DwqjI830nVjcl(QE^jC5%_ zPdW+V+CQ4CmO`6oIZ=O2_l~q+o9s{6zJylc!jV_}G=^SEN+bU!Oj_yD@mRLxArAr_ zr0{!xsRi~s>U25vn3Jb!)_(8SF*1HKm*Bq5RQ@g5qCOw>LR$mS*F>n+<@$SjW6Bai zBUK#r+tE-5;*?~U4;UU?em?LUO{YU`-zNQLc|GQ>u3Dc<}4ROj#d`>2R$sk+t z`Bkgnd{y@?4)UR~7Fw|wub6t?h2}xHocM7B z8}C%1x7~mbjxV-pUz}xR(_eR_(}7a>1Mj`5f#9?sm<7>FvyZU5_cJRuunB8X**X&H z1B?9{&2sJG4jiWFANvcZMyN#kVFSc0PhT(Rq;qS(4%=Z=;`k%;#HoGfLL3fy5Q+}m zflH7|0y7vkx!)zS`+$!N?87-Ytnz{8VQDPjJWBvY0wzdT15bhR+NE|+X7`Nd z&`=5ChV4X}-$G$AC=??g^O_88%@njCL1%#ZV<7qx@4s0#_LbK+nR@`?$fW8%~Z#;Fy*3sK&-bj$vr&g zEsN{oa`6AUx(cW`lBbUag1fuBySqEV-QC?cXmDHHo#5`0;O_3hA-F>z$+wr>_rJ^a zd;4~F=GRrdJvH6aRb5r?PpD`?Y7drmVFdzd$h zcj26}K7HRg_*O>lb+mPspbdlG2 zk@36YI7eq#3|Jju2~S58*%`ds85ublg2Dj6cW9Cz3)t#}ESpGq>kx)S`;iYO8|bWL zyF$w`vM8)fyFn4KutExQ30E=$W~j7)aH-Q~O}If^-}!Kz1o+YhL-hlHRbW|cHKU}F zvRy|!nv46&g`qp58W)PWs>5W z61Ae}qsp%XbdC=$*xXAEbt-s^GAQX=8#Tktucl8sY?ZK6)MP0uRkeu4sdrQW**&jD z8IS=m>_Y_;;RuP$l5+EBIB>Sdoqmdo zh#(}H-E*Rgujo1oR&y2M=I&`05F{T6HN&)9PRyQ;$$B&_kjr}4W)Whtv6zVct<>@C zD|NESqYa&K%?_WJeWLC1eQ?;jFCk^LrXEYl@7Naf`hE zd+mbcbZ`{WxAE3lzxQt-{PR(df<7PNPo65RP0ntKFA&H12cyJEJnlS;_<&#FI>hfZHfeaaX8?8RYeDm>!? z=E5nKS<135eY*u-tl{VdwrxuxM+P`kS#9vzmxF;ZkG8hLb+2a-vtRY3KGS#KSAuJu zm3MT$Kyrb2Ln!^$YX{aj`A0*v4qR*=#(Dbcb~^sE3D-MtCZeEd91>j~OE(jK+bKzu z=0?0mR%n;7V+@P@6hr+@igww%R4p-LRjABk35cRE%GFRw#gC`~Z-2;7Zi;Ti_KcRHproAqJm+ZH%^ zF#xYTI(7=J4Z2>pxw;m;?UpVp|8>%Foo~q zD^OBfcdw-S$rc6hc+uEp`tYM`%BpTXegv-TKDHlm$0CRWOSE1Yxe1wU4?8Yb3tKpv z2NS*+DpD-&dEduHmgEmMt{ZSq4+kZNy1BNi|YM$OH9@ZkH z@-Jc$Gvmn)dO)*O5$&b#jSl8xCU^5b)3L=6TET|2TwM5Ko)$3bnYB$?X<}taLhC$t zBuX-KV8SCr*WV#t>$Y7=e3-{S;i5F#Pl#qWrh8U92@M0XejD7G>(Z5kU^3$5G=8Xiv7EFO@nNCowz+l)LACksld zA!DpsnV*oKquRj5;^q*F%*HayoB=EH^R~Xr%#0l!n`F(bV7Z#(J9d!AzY`&mWhgr0 z2p2nsh@F#{^|!BAOGvwt3@vEFfdlAFLB*hEBjd)~ypfc?;7`g5|A7meVKQAt{#g!; zfx|%Wv;N!Uxi?7|NzA*h5r#;h(Qff6DmhSQaUWq_G;=jky%|f#F6p-6YBs?u&)@tt z*^%J=Iq|47d6G%RpzMxZor4-)zjwmyqVWM#4o3bwZ#fH#h@q8@Kw7e}2qbNqHN#AV zf98)MXv_TX{|T4!u9WNKDYzLgu8qsJ^JyYNuPFHvi7fvbzRv-Dh*g zu~JjK(KXa?330P$!Z~0K{|8kctCQCkSN1G~xy<%z)@+pUSj+Az9j^t~ScZZw9aX!m zijrubaT?eTgdL6Z0vnrU_evA&tbm^-)q5}sWLI{ndM zKG|x7xf}dAUe7?vm2ic*fKY^gDJ>6#Y$c3$m(j2uMJrFEX{k(j z-4)lSM6yAuEh5V;v3zuBfkE7vSs4C6T6gde@T3_O)exa=(st}qd=H7lvF0cGRPxPv z=lrXvaOg$?y|RY z>9+dJ7DM?>wY-Sk_Gyu@s)|*FBR-psj2mC4GMji&DVFrJ54~70C%7wR7s%b}J}@O^ zfJUjuN}DT1D)nAk&QrS4q?6v;tsS}MN{_Z-L)6Q>R+@gIPtccu&p#<0cWDe!3t%+T zw@estFb;C00-q$B%RVi`aCC~g3E#^x{DAkb_cn$3k!O9;|6zd$+s+;w(jFDulZZIc zA$jR-yvq%umBeDIJp%Eb{`l!OP9NC)8i1)-O`zA4r4IE4w+9g}m#=AG^O~#^nT4DfxAD7aq!s<>rM+jIy4bm#SN;=dnxik%MP; z5@nHLNCyes9v9XVme(_EE4mWtyJVVnR!=ys0=ffhWfh{u-y6x_0RB`Gd}@KM5ClzN zOCUvo6v)lh$rbqEi34OAX8@GETX&onK@mLF-+=xQ-h`;4t}B<{uF4%CN}~!TAr^%J zu2#|GloY!D2 zE!WdvnvF3Y*}(+K-UiKcBB!9@TasVTRg^ppKEgMWE>--Ok_%elqtZ#j@tB0zXPI_! z-U}TPgR+{t32@8!cp1Q|N}Lozm0RR@$)D;7!9)JV8?)E%!AS$lJAB0v_51=xR9>+; z`fZhUk&vn6oNkp76(MZ0K7}u2FRzeQC`{*gLtZOXXlbX@d*vq~m^%-C23LUmz=G?V zR*q0*CJqyObN#btVta*L6ahaPgY}Ft53Ap|3vbwQ*i~Qo<2M9A7W|R~$-2&% z+|q)1X-S>C49bFX-r33gEZI~pu<|i}Yp2oKgcA1Z;4}7`Bqs^5DpKTTdX7FGABkg% zRsUwsAPKt{M78yI2h?TkrCnlm%rcF&BXv$JEAa`oVwgfA`w*a+aKj0CAW4O7IA*w)*&XnT-COnj5y;qpB8 zf#@Xtf%G8ehrQgF%ZcZbQDMJ>rL(UY2=S++IqCC$+6L*=>rjDLNs@q*zjRJNySdIo z-9MwzXsg7`&2eqQ2fx*nmn?4rXAH({CB>cZbuXP#SPQ17yWo#VUVI~|FX|xwW;vvd z;3sHR{UrVIaY|v1GN{S_ZanMpqI3Oa({DRq^zx_wE#Z5q7-*F@7SM?65O2xpNU`1{ z)4e0wC!G@KM#e*4&-e)-g@qONr8ov>2uFP%W0)&=_CW^%Cbp+beCb_&wMyAGY@f-ch)D4|}+!XH0#K-fHsdB{>%`_-3Ycz5eXs6o3F0|rXb_qEG=;}jti50EytEH6V z3y0S@4K_cfr`o2*rWsMH9P6UA9g-E+Ah=*l4oB!n5TMt)1XHLPgEU=oE8=rC@Hq-7 zAIHy6c>+C~m1QZOlLyb&Q-n%{Z0sVxc}_OiI7yXZEo1WAB<(iHu2*h)h|TWZZ?$LX z!SRi5xx1WLo+-jHHCmpePj54wUGF3-n{T=hmU@R9c!Hp_W$(xwWQe_&fvTPmI zS|}sX?70i&OdCyYyB;Dy)??!>-_7G?gIX#HHw#CYhG?`FaB(Nry-^~K);CM)mf@AQ z9p$@PbKin9zCu~DK1A6_FMww$z;mc8tq)bT+19?RVx7JP&{tk~B8ew;!=|XxI;&}t zDAS{-^D{B8+b^oyhp<vK?dea1JozWFA=#lX7(LnVyY+}qI-BQ+yP!-tsXOlBJv-n$ zO-V9*l zdkpiX=r(0=pkCEy;{fBkuaL3r%1lqDY-|HBiL(RHU_~?jUqFk?ibT@=Q7TW zbqBy$%R((A7B>0jq7gyD&6oM6eVNzD)@v$_FZZ^@QKmNO)F$_X#^B(F7~!bE#m6Q$ z^y&xFJQ@+jHs7~CCal4)SGZ3dQYtK=ea@38#m?s_uRChnD3+n}k$5}@*7gN1s1&|W z1R^45(vdt7Z+1~?&_1X##pUY~4C3wTghK$9;x((@WaGZ%98Ij;`dbb4ykz708HsFd z2J6iW$sqwK1Y!yywY{NTwVX>Y^(MZKAp;Q0Z#kIoMXw(h`_psQkSrbNyXt%~+-~Z^ zFeU{vga#p`M7oe=3CJ&n2hdyyCU>FM28O3#58IdKsUwUD*G9O5*6X%zUEqC`<3#|; zK+K;ka?q+{4^phk#whI5#(~%&e$S(krB>J1gV+NeXr$LAW=fuzK8H}B3{fu`u-qa;6jMUV zKT#mMB9zbZSEYl{vWWjolY>skS=0u|oJ^hB#|t8^<54rl)Xq(~zd&DU_Z zU9VTNAI?{{RCf<*V-ETGhi2GVrsR&)IaaX!{Mk@~qLCMKZ~2jzExV$W?1O0lhtF8d zVpJzdJkUE|GuPCNYV=1(p;1?9&kUHyeM_$hZOQKrrFt>y4HP#8iY-s&n4fqt_|3wO@)kmA;BN zs2jc{8VcD=)vt<#v=bGLg-M6I>G6A5A%|z)spPxb#yEjHbip*m2-OT^kvA9C%sO@f7U2OxI0Dvuh)jC|nrpl4Oc83+?K z^71@rd0tVAX7ik|)V%Nij57DN#ad(-7t$gIU%QVGGR=AQGaD6Pmt@Hl;5WeHmWjna zk=GN10PJ4xWeEu0fr?eqzSu!J`SIDy{#{tcc&@LB`zOp!#CP5Z8HQ6MGcXLW&2r?n zcoa4fA7N)lS!|SLqG#AstY9Mc;e}B*sX4_CNp5L;E{xxU92hC4=2o?h5E(=bwJ zJ&5*5-FZW8pT*Dt^-her(9H{e4g}SMv(Dhy0Z0zABR*2sw2%mg0Ft!<5tCBb^B2?& zYT`6l1iiLilroB(;7X5=VS$e0tgFFPdc2m-j1nmUf)c86wLe>x zwJy%!(atL4*&+JD(x4Sh=t2c3#;s@SAnU%9k8-Th**mT9d3?H->j<*>R9JPHQIr`Z zJ7CR2iNku2PH%$o6IuPQDXm!pP}sv#%Shv8S8uwmz|h`EPzt?|7n@L2lu02; zi%N^JI-KAI^1GcA3x5iLsf*}@rC===l~xi`w7GLr?B}?_gJV&juvTF$Gc^>4fTzRK zNXAL>XkFY@0umMS*V=t3G!xIV5XBb+tqalR8c2ETVSYp25x zi;Rlz>H%Ll+ze~8a?|v5^P~AaVk&9U?w$ed4a0(2=R(auH;aCkF{o}*4__}S7CJ2g znX-eqcNB1857wbne&Jngq=n}5LlZ*jy*(tR6MzfyZ>%5REUM*N6x7QWYa^LqjH|@i zj^x7dDXWo-Wn;4tvD79ptFoFMvL`{zv_{EmEBQw+7*e#;*nP^i@s}(o3k?&p7&A`3%ufL_p|w;D7AbN^5OmDEK9 zxLBH1<-(~Q^A~j)gNtDkL5X@hWu3}k%qG4&%$DgRyPVWQ{sRH<*60;N3a#JjXRPWc zylDgcYgRfkiIU^Is~W|^gS zXZZM_kh$dRAHiYs9hb+fYHi2o10nC54#8IBihFb7o2y8Li=bbvRaU&^J)7ua0*7~4l!aL=8=jq)40+OF^_00cPF z;g-0b29@8KT2FnA$w$)fb_d##LS~ zPkx>niyq-fbu`C8^ZGJ;^zfKR4xaHKn5c9xQ{fEwKGq1ufKYUP%^2+pcf8B-L;b#SY15iq5|KxOXQvPYrNDyo%H3qA z)3E8_iCq-Gi~fX-79@dA{262}vg#n2p$ZfBy69#<+H$*?c>VFRhy5Nd_i+y{3J>?4 zI5Z{dRI%z33%vYbHZ&%s30>brnTv9^fy%YWpm;bGG9JQe3gM4PJ*G!Iz>+TpkD*y& z!L*ZP++||pzPD1-1dGA3z;XtyBMU`k;HD*xzKejLM{BzU%;i(6U9?hQY$v{evjhP( zaJB`V?bxotq!S^mR&W}rf(cnX%d;9&*jhXG{j$M&MSGmaeU{?IqGWWdz}s^Y0G=`g z8zR5&Nho6)K<7a5E4w}oz!N<)?zN?M7Znm`OJByyNeGh{{@^y71=HjZ_XfL{72!&E z5~<(c!X)m?VjtzA7iLBEOQ+~$;6X$|yr+6PCJLdJ$?=G(O!_b%v z4!_a2!J56LbCKb945w|8u+W-IE|BPSxva^|k~zIkMgRx9;TlN5l#g7}ck($QE3w4t>XK$Zppy+f~DyV^98>#3;^rb+_&|QfXl(@lP5Bk#jtw<59Hp znMv)WzHa>(4rG)UAy!e&Zh&-Jj9uqYKwMlwxn+6D|1F}aB1NLiqi0tprfo!)3-YRDYV$Z+hC z6c;85ZxOy9exu$rYK#%piD0?7orXZ}aWHyRT_lLxh2h8KBXt@m-quN`vUb5Yc`Oo! zuzJ2H^Sq^mK~t-9A0H=4LMCi1vnZept)UfKK(PVv-9*k*Vn=zYamTB1ed|Zj6<}}{ z_Erpczjj*Pqz z|Fc8#GfJutA63&F?HXlqvtAn^aHEfKjwexX2#f;BM2tFGyoFW%%3RUls6=cf_g+a zf=o&_iz0FYY*Q1JQo;W};i@8a6kmWD4e}&!TFc#3H&l%67oIIyGG#beN!QUPh#owH z!aZnP4_nxQP>mFTWhpFvF4vXOBHKOKT-}d))+nyb0Vl(?Z!>)NLXAE93Z%8qzs>P? z;XDf7i{3##BzNwJKv9c5ujTSgK25~G4KphsQ@%GvZESoplvDPAK$RpSZs{n%YbU1+ z4?04E*gg;4t4|O&Af2pKDrtqC()K^`voC)-Haq)}RA+bz$c`~*&TKiw^=;NA1O54#?n)v3v_3H``|b^S%b=*t)xRAV1N3+Y?E z@iFQZnq&Pz!+tDD=L_Tzw!b}eFHN1H0;F~g1Qoj|EjV4Hg6LYdh4rx|?=9is zGCqqP?1U6vQXj<{VO0>0GvOoJmzR~$9s=Z=6;AXl`R%NUmeO=pxD)G<55NIzhFDoW z_R%Sfyfe%^2BLzbVnL;DmH(${wNzaDMT+F$NEsLb+pJMzTtNBnecfI9PCA*O4dAsjfA6Y9{a@w@A7k~!_MZV62TG1iq)-qsa1t^U zeqfYhD+nl@au7IB{bXAd+@qga(5G?|Sj2ZO>o%Ap%DFiLa>%`L>o5qlN9BqT~Gi6Fz*}?H70@ z7E+5h%S_nSO?UsEnEqPqX}7+a9U$97O9p4OI9nB-k~GzOG; zCRG@p+%=PO>PhCrjB2V1{EZ!O#i!1lgJ3dru> zMB9t_l)$btjzZJ8W}Zp~QqCK$E`Bs?%`UgJdb4kTkV9oKmFVWNN-_ylR;B0l{fH@%~+`x^tN$kSKol)P0X{VSDD-U!KxZc=1GayMn zY}lZpu|*o(6Ifeyi11j~Ybq(AHyO-cY@=F#!+w^+E?)0l*j$_Ad(KXtgHgBiHEO7e z^)&NLhCkor6K-R})F$o7xb6xl4q-QCdXLL|YH2KErygD=zL%3NV5Ontx(iFxxu573 zt+9m}6>fQ`%JEd>9P|WLlhH%HD~fBddwIuJYN^7V)m=R5faoDTAz>7Q#btR}<8Ih* zS=_mVT4yTGv1G7L$j;xd=^)Lcp4H?aPGibDR->($F+btV)A5Pd{qt9a4*C37&P~JV zC~U9Nw2x;It4^ol0GCEV``O4JDFre#^}1hZ>8+BxPYZKW=klnV@6PR7P4zGe@}0$- z`VpKs%}DQa_3x;B#gYYnnk{%_D_R6}+fwm#+YfvDjStJ!t@5$&tB4s6AJb2|po(kT z3e1?4s2z#*HZ&kqPz}k`3bpSc== zNJ|iLi@*YMX9}#F(ZTW-pe>0>U93FR327ClHBOp`-^FoGQ0h7kopPBqkl9gj39cV! ztd7oYXUXBTTDKK{lDj|zmgcB)9K|ld)stn&UWboZA0#KoqVJ~;cQ9I$!`It2jGj>q z*$tT@lyTcj0(cZoarC|r8)?X*$WX&CG80gf<;IFvYX&2fS=Lr%6U-fVH!-*bZk$=7 zgk&Vz9G_c+^J_@HvJ~oQ^O577Hkp=_xoW29cC%KFBT3qpkcd|!7PQSRG%kOow%0ce zfARh}9YtaKwR;vfx`DN6z)(|vwkK3hL<> zMjgeO(B?oPL$NTFLp%1&>vTD6xQoU4d?K{JiULrov#w5e*N$l~92I>L0y!S78cvVTB0v$-}JcHvNm|+0`Hf(uX|sU31>-{dNo3HQCjLC)EQq>ycEyAgxy>?e0Aw0^%}{c z$eQg6z# z53XUyzA35hS}b;2?Y@ z_7YATc;4(jez*WxyzPym2I>nGKNW2~4<76zwwDAsEIUR)VYi@V=;44E;UJ-4j5f?W zhN)L|tJVICFizsEI;AVl=Ty>oT1kKs-Fo}sO-^?jXDIDs6yb@^{e=PMLAU^u@=Q7U zA)4P6I~7Idl~A|880v7Rt}@m3Ci7M>W!`HC8!nB|R7t?e{ulQR!oY@mfd?w)kKaH6 zmqxz?Jk)}v43~M)b_cVziMiirxr8xQV6L$Ch|&>nUn-44V8hk%8_8uFXa)khi0Hht zk(8Qu8#iiuHdgr~vCMY)7YEY%1|Mv~_L_~O(d4!aU;}jyEjDc6hilPz{U*GlJxEM` z8uvnv;ny2kCZ}|I6ufzv_~Gdh8%wFSTv5oD_QSEW<0B~3OZcAITeTfB(RrTQ@8?3Z zPnhS&s=br3kIlnCUM=;d{WTy!N!2F9q|Xx@{YR?Z$5Uji=h6OT;5ji9mg26Vz~PVD zFtVH_a1YUkxne5JJu0txcYKL6SF|b*_(^I(e&%P5$h^v$_`vy|@AW?nEQrhU3e!c% zGJ6J6+beRn9Vl1QVk&C+1r=A+y!Va}in@HA)c z94ZEWrON0WjlQ{2F1GVj>ntP}uUY?Yv>{s^^B{0qcEwRMcxHF@G2i3tL^rZlv$%ik zCb56(jHTK+aU(m4n^QdV8#fGV$$ZoYQ%$RHrNt=u@%Xwh^NT%KfIx-W&ew!^U_Hzc z_|*>7;+AV_k>enW|5EPugs@@4`E#``LwdENi+`RN-d5&wSB{h2&Q8oaruda+%;#k; zsGsvAJ{yN!A=Cb9VDdYIYzmXtUzB=qk&rL?HVJAEDPKs+Q@S(=+;|Q()ro?*B0ihh zhz4er&tkF6lgh!V02;;HKD-$1Zj4_W{)&l zBNrM&HLhWto~44fr;YcDW;>%$C$JrpUq^=Uly4E=A)6w>G6AT2^|SJ+j_I{IBYZpp zKQu&O3`S|f+lu!1FgN%pQ_bs`XF9Rx*w6b0$f`vletWg)@KHAICB;bW2wnJ)z#Xg> zzL$KN5GHXSXyG{{923TS_ozTQo+mK7ge0suRwSDkYch9V9Bcb=Hbr>kW5#WI474W$Pi z`nWs~8(>Q+*rV#)?ZWTpBJb2BItUviL6M^wD~JYm=~9%5`15i_F!Qolv%>1Ys;xg` zWry58Z@{6i*I{Gl6Fan_t?MB1r+e{VgL&@I>PLL)cYFolVDDfT`$L|46BF`;D`h~) zTNcP4=Icexk{_&)mzmWzkumVsDL;_VbswkDJJ)Z7rVB*03G_Xd)f@H12Ks=fja5D+ zcZJa(c(rN%cz=3O+a@a17t71bpq%m&LQ`xQxbflTxeNXF3X|aQ3|ygknZwqSr*mPj zVBUMp-yaiT6vE_EMS5GA7W6J+y za^4qGfeBkPgOaZajp9$xc1|r_vC>yGmF_{Wc-sT5$G5|3VNUM^b2X}wjs<$3fp@i# zjPmV;bcU5zLWs(PG$_ZO*V|&0j*}wjjOC%uiyEPT7<3nY$&DSdU0VS~=5?|G`AN>2 zbM-dXP|C>^#zpDVu3SE&#M%+RbV{9lQ2feTxy7Y&UYsEt-WAWB_~#ejMV3@J-3mgM z-m0$@sSC8B<#+=pki%P5IFqB#cU;G5U;%7tPt6f#gl2UatXo6r4ps;$J^Z+}?GupH zbbRappNOX;(v{SmwWY%^K-u!xLumGA2h#F)J&$#)km>={fdt z8D4s62kO8Na_dCb_Qe8)<*&|A<7;#u>awqNl(h|Jr7-k)Lp2x|ZTty`Y&%S$?2bFw zzjiOSaDR<7kp*-WTFQQSB4kCBo6wD_PfWlBd}5+B7YyTQXyBBVb7bMBwW!RbB-Pa- zQ9JD>z6}BAj=>$uz~FlCQ?xF**BUQ~gMg9i0cCZIQ880I(DPnE?}5}h?8vzne**Dq zKhJW}F*Ymd!Uxlk1|6Fttx;n;Zmr3rH5*BxFy&_H8T}(OUz*g^Yld!{)Yvij{uT2^ z!1{+gZH>0o7ltXj+mErDqNgM+Gx-M^w0=`%w31NW)nV%dMgBVb4qL?%AFfv>75d?c zl*_)9C@|D{yXo|ZraJOQd%?alMVDVPkCf6be9< zb^|_tK<=;X?w^6gv1R!=Y{V1GfX-u3+MZx4}0Uff9%U+5oc0 zFB*OIX{mzp-5MF?g}kvvMMuKL_pj2y6>dw)ZHFT~nW@+BQcG$AV-+8SKkdp0I#0b_ z!&KUb?qL zDuuE6?Ui~C_2C|8-@x=+B4O&8*Iw(&H>#9;N4f|HZ{!cS4BuBC{ zM`brgqwszYZr?O}2X*D1DH&&Ik37iSp^w+^oSfbBe`rCig6HnMw?`H%suI#&)%S33 zE}PQZ&vCwWG0+X>R9#(q`Ft;DrUg3g}+D29WK z8c}y*xw*TTlJ+V2&pj?s9u5`v1Y#fC$Ds2RUUT(wm@I0m(^~1mz?{@$0}a2fP(nJH zKyOhMf9jul^wUUNkhr)Y0NU5y`cZXDgRAMt zIWP?Ioao!L8va`Mevau;bK0aMKo)N;zO>-GHQJh!iNA*8J_gj4)6?Vra(!x1RLo7? zQ6g)=!(7Z|A@a`xsHA6M9oM}Kw;`^Ri;15Hz6}by=9#bCC-l-e-H_QVgnrQVY0hVa z@0V{WurR{ojkkeyM6K)ZXD?sXN__~eewyXoeL8M7ailA-kFVB-9FF!uRgH3qantW* z?X8dBqfD;P+XHufaO+yA++&MNa|^&4rsoNa+DqA(KJvyKuH-e`o9t~Ss3re?Pav$= z5&J}Lcysha_)q;$qgT38!UywrepFIm zPyGi929^c;|H)K=yTfR|z<*}N`8W6k`~Sg6f9A*m_6}hDs{3cs znSa+^#raj&8I1%;H;C}}A0EMjh#>xTetLxJ7lA*s0{oi*Guhw3zj6c+{sJGJX}eW` zFzcWX*}t)1gp43C%Wp2mLwFD{OrYObz(6u2VE)kWKKWlnR$4GH5Ve05e9phY&_I?E zwBJPZL3bcP=2r`9nGyc^3w(ok5GeA%f&nt1FfI--VemI`(rjWk^bVi7dB%=1gZ#qV5tX~EB@9*DV zjuyb)(cfMFM&wiZ=^xy zOnDG*)<1xg_P}}@0-(Sg`R{v?Fo6eQ=J@Lzk{9y-IQ`@M{@*_DcLITF{^=R}aXg4I z4>KN!={MpPF&tJeVmT!R6)1<$^e|Uxc(NuZgzrkn>{~ZSY zaLW0kl1RX>N<}l&zo`Fr%l<#u(4b$y3MWdS{`l|i{b$!TNRIwNf{rLde}Pq|Xnt9N zf9*>H{+z~yFpBc0;64^hg7{r0Vv_RxGEFjU}gUKJeEB;`q zn)nO+aqjmJ^@oA_51>^t2*~$8ioYz>Aokgy$OY_w0L@c>QKTNjA^A&2{;?4Lx1F*X zzkqJDWWRuanQ&l06gxo@!}bS7vTP8L9EdpkTaN!y`|p5&jvxm=;Xi;rxxaw%lXSl* z{$m69uXME*fPiGcm&xD5r=GWCdNPRGFla9L^U+Uf1OoEOfcw*bk0}b%cn}VqpmR)r ziRLdZ(W0F8{-B2d9wdrBIf2T0^0@RzXvehB=h@F1i=1JkFZe^o^O*{=nfa=<_# yZor8DsEF4GB~awIlTzZrr4!a(0&m;Mh0Bgr)Y delta 32229 zcmY&YN+qUg|nM`ckwryu(+qUgH=bVRI|HH2C>gva}yH~5d479Hl z6hTo26buyz2nq_w#$8o99)S$%KXQaHUm~7I9RvF!{nq);85rpQyXpSNt&9-tzjBh| zfAWRlzq0X{E;RIiwL}`a)tAf-s#1WiDckmXr?Gm12(ox8>M{n(p>UxpoJLYE3Yv<){duiwUWmEu|Gs57^ z6So+_7a3!bv3f6(8?f&wKNuB5DsBDHrQJOngR%5U=60WeO<%ER#-@pFzM-T(5fP&= znO#C}m1Z;A6@w@33u%j&TAyc+i>KChb(_?!&C|09P2h$HjLluMYYlQ&^nbXDTX5`y-n-N?p4Ivw}1=d0T^ zTzAG+&LgR-oVNi(aRXNRbz0*Uqv8m9W>AmomWJD`$HPe>|3(f|3dxnZGfL*uaR z>TkWX*75~P3czMcDpxR3-II_pC1$^_yD9-E+&#L_y}@jTj>FfWLx|mhE9RavK@07v zeQlxvm(t{3d+HejYu`%Px$8c#?^<%Uc~R0_s-3K3xGFeMb|`A!yy_M%bs*)pp!7X z?yQAiAMM?wip?eOmra(?+(&L9nM~y~-5eOA@D)C%Y;RH!3#d{SlV`?Fzv9A5`a1-@ z;e=|iK98ktt+S+^mFzWIIbng*0*6~t`SUyWmYAB`E1i^E!Dyo%W);T&{gjen0+zQS z94Un72*CE~T)F#!FF#{cY-@C6w06%8bVq5>o_bhg$4cVE?i`cu;|XSa?*X z{5=W?|A<^@*OY>7BkxpMw24gL6LO)X6SLti>owp5`0iR>G8XSe^W9)W=aP_CxKCUM z8_&_c&bFGplHUfqQ6V}I{^1u@i{!(onD3fbL9w=c8X^&L5<{7AEa<_TnbTE(Q*5zm zZGf7-y@Cb%MY+_`PW3M}?}I1tXmoH@3#hJB$=$vZ1&e5+;k$E?3+(RLlff4A6;OMg ztM`hSd67PoMzSpZA ziiD)&G3;XoC6A)2JFy}K8rRN+;Od4}3&6y+FpaI>^m{?IFS0v7F7DuMF-diY?jL9C zdi=lCmB-pOrDZb^&H0gxVRci60R|7FZ`Jl9Fjl67jDPjuxZhQ0b~_ZB;isLp;YlX$ zpgdTTtWEsu*b$o%e^bt_y$F3OWLU7!SMZgv0K-h=QNsGtM87eIxfCl8_ zAk`!lVy@(lSWt>_)Waa3f()t1gw5bu6W0eFPTE=Ows6eNmAY6KJg`SKigZm4tK5-y z*zcERbnb|iX870}8$x%p&~5eDsTR2IG+dLsh|&`|ONBJ}-6Do<)x}s5uf(6f(u^!> z^*$fd;pz;;r04g1Z+Nn%N|I%G(gIRt$ucE_17CjPrMLU1RRclgnzq{h=-q7nG%_X z5=7u1*Gbr_uuv0|Gw*%JWu#lF)vjpL#KC+>fr=W;aYFCKC!tzAxK{7#OI2Zkw;GNNco4TK5@W5L$5x1Isbf6Mqo}u!zYS5Nk0}6 zy6-iuP8|COcwlYg^_%{U#~4e)zMdacnLTZm65z^-hn(ozvkt-+YkS9yN#yvjdU)Wq z5z&4`9xHp-iv%FgKsS^H_5w&^Ena<|NSC6~rkt#Etmi&ZUWNbefc(78St)&m-y&G{ z{`q~iYVfrMGn%;f7W}IbX{_n?>>Oor9`M_R)|VO}w6d#*i|UDZxBtN#qf!@XPvY_= z8N@&%kCr`lV@%v}=WN-N%e<8}v#)zmFT1am44H+vC;LV4zf=bGpOp8XwA6?%0|5f{ zAMM4vsxMI%QW)gQJ~0lG2w($)qS?4bG)Q=)CF=|EWr8E;3q&yP30a0LU3MMY?s3ia zvh8AF4)}h51{K7LwIhvh+#|FwqWhi6zFZ&QXAUwk(rsn}+iE8o-&$w4hamEqPVoND zCBka3Y7(|&s=`RS^rhH!jfW5Q6hZ)o>U7c2|A()}w~+wSq~pp18nB^sZ>e~7)&kYM zv#U)FaiWF^qXz5QN)x71A+vO^9l-&*_k?!i8g#G!*B?`Idy`iuZ=h}y**kRpLz#_& z(I5m4=S}#F@29U@(b9pv+<1>36m$8(#V3`<{PwR>IFScJeE)Vb-_kDzKNkOURBCK0 z1ZB-4?32I7nzlAuQ~>wMzYd+kT5TtJP_ff@42~H#aS6cV1uRN8+;QjC;*%Jj|xkGz)u2e!mrjrRfw&Gy+6AEe?t`7y}NPdP@&~!=880@cU&~ z3-o5##o1GT{<9eOdt8v>TYC@|d)va0tp?Mw{{#LX){{mF5(Y!ve24lZ?wGiIH~T1V zr9g8BN{?>S$*te2VrH;jd3*Byk*OY2!UzV){BJl3H{antjXMsAZ*+r&_=L#bM1XJ) zy+=>Y9?pD_!}y*U*Jn3w4_TL^Vj+i4a?VXBElegY)Um&YvR1{ zJbK}dS=RiEg0Vg)qf_Hxdf9O_8h}-}@GyOn^W?^J=hb9GhleKX-IlCn> zF%U3I&eXcS!N@)D1`1Sc$Mo=Z6EvjWXMY-*Rl5!RR^7?cionbt&sH;IXiVg^$CVQ>VvpWlH4?;LdzTgn4Yy z6FYWhn(%O!g#vreqN>niOPgLFd~285;4_jlPa={ZAD7j%*RGMt1O~9nWz|%dzSg-A zWja++t^3H0kI9!>+}CuY0u(Hr#63G-_?7LEjBIi#Z9k{%T8rv zINQZ`WZFoDzb9S2o!LscyU;PzU-YImxZKB0(nWF~XzjQ+s)vjmZcQSW|1q_h_G$64 z9HIA0t5Y~GEiIfYU?TAnNPP+K zw3|}$4gi{4g=f>oQr6-jqaza&$vC+f|Gcwh>pa$4cy7x?U+n^G$CH`cdz#N!mDC9{ ztUW4Lk?F24q<@{TOR#5DK4Qb8B#N*o#XFuWI$GOT}mFYq&UQ;8nxB*a9H0|8BSD~uDB$5_B(kcJ4SP& zd4kw%oJ%tvZU<#&CmdOcIVn*iRMJQ!2kv?yk87+umM@8ikFqjmE%>4u~CdMvPo~?}&scQO3K1mNLPI?N8~+){uDo#D@*iWqC| z<|l@Zgd7Y?6dd3mPyk z8p62^15k+{(ZxnGsgMpqqa%#r6t2rwX(Z#zMP(WbXBA1%umvx9Nxf(67ZYp2q*y=W zjN?uXXE+Z~t*a`l>1nY#jiZ(hX9szG4hgQ{t7IX0EX~q2)Re2(gB3Wx7+>z|lC!5z z%MT;y^c>Bc*e+{x3w8^upHTKOWGqj3WKJlq0yL4>M>yoXr)v_t%$X)hcinss#2AXc z)+%55uf!T-2%hfSvqW%83N|w>%);<9F_rVZIc!v!YE6o}Qql)sq_2)G%L}A-ve|;k zTx65WR^OESnPn=KiL}*pr`6n9M_V6u}x4X2$#%IvAC@N_dbDIS!5N)rOJ{&q^@@wcE%VYI)mD z)n<4y>q>)-UxUw0$uqa$_2uWmDk7z(X-j1BZxq#ay7Q`YH&p>KP$={Z48~5aN^Xk1j<*Um30E-l)C|d(HmU^e~hz#?x=5J_{1jDGcm*X{H z_1i7|(vPy8Pj-~}is=Zla+rkm6dSp0yJx4GbKpOAr9K`*Ho5@g7SE=HU{&Fswi>@; z3=b-Qv-L=gZTO|^ow6#hiK(*n5`Q)NziPEN2{CW!JJ7D}y5{BgCDzA1S`%`T0K-PA z&XQ=ZqOzkEplU6hnJw0nz|3bXLu{k)(PH4}Pq=-5>I2UPM54>^#VR@#-Gk4vgSX)| zN}E`i9#1Q~w@Hue#se=MbfI)9&>A+D()Ys6nWM8Kp1U7{%r2?0JWVVI=;h)Rm1EhJ znWc{ueYXa@#|Z~)FNLR+f?S&cfT-Oy&4`T}1~rR4mR7rvp2kbS=>)Zka^uwxqq|c5 zbFv4QzvamL@}9C-NDQSmL+U9j(E!l-iKcE`bmEt+VZ|%EdR_iEXr!n=9$ljh)=(@ zD>fJg*hn?A<92{u!DKLq02Cs?S@i;y=C)<2cg0Uv<*Rv;#2f!=%u_lNTvIeBamiat z^;R?npn<1RZ18Yn)H#>8$wyr5^Og*WMbaL@Rt+%hnn@2+cj5L*P8;m=_GKGQ6KJZE z`-@ss9gam_R`>+srOxX1RpiW?HIXuyxFtjk!fLYMLZj8SP|R*40ibCO@#^ia=7@ja zzK5yzg-GTFNGdo!J*T{!@_8@VlORW(g4@boTU&dgh|?RX0I%={x+(0f-yVas=!&yq zZFdA*;+xB1tcJvkIzmd^d!R_}|ZSSsn>IE^@szQ}-C{a#hT*C@3E zzYGJb6^sRgwY=#V02lz{#qPc1H-5L1&yXCuDBRBreNyS~1{?IDJ<$rkJCA@nvS_r% z8Dki2Ok^3C$e-P^`!e^I;kOTXbfDaYX+@}fJkeF)+` z@By>Bv)vp3>Wl6e=cF+fHWdV&R)j|-%q&J&n!e658NrI@UPC>Mn9|R!32{N_AKJ$n z=Y#04QT$r4q;!3+Qk{0W57hjZ`JV9xpaa~B=oW&A2AIXUw(&&|g*_#>hC}@O6c4mA zHp0f4v1_l8Clg1g-&dbwNcs!2b1;=NXfDXc4c(I;3hBUm0OX zV$P0W1VG}>2P{9c`R;`a*3km=TafDt*NE<#Pg0^68t_*u(CbbjYYgPk5oq` z$@mA;LB0O(&8za3uUfhD4P36_7A{Pz3+{DSAl>A$99eAR=as`5m0>~U=^X_o0R;`y zN<P2A3KAPZdE_5GCA7E=KH z|CVA9b_5xCC_q4$R6sz4|EenVL|HZ@fa+1R00m1rPr5E4m@wutQn)E15B4v3skqf& zadnu#?#Nvdb<@eV+eMHs)CttJuf(_PhViVe(2~KTBkZ=CThuG7o10sfpPQe%dx~%V zy{?~j4|8TIdJytn-z68F>Q>Agt-76Q5WxGmj5d zKr_d21Et`W*fY?#XS^ET(nVY%dtSg9QwN~B<7U7W2hML*aV5$b6}~mc*uf_sUcU!m z%|;4Y|%aE@i+j)*Q0n4|Z0uD(hDfBc6*UuT_XJS@g>qmbb@x9HI4v@fEK6D+(G~4 zuT83Z_ai3`oPwod|81(7Fenr?PV_u^O=LOVT%T8FE7@Qa;PtWSc}-@f@>}{~AJ9b- zmxE0T*mtqH3D8fi9%264xK^5B3JpqMG!&+Cx%xEwWr-$HVFgBT9BhphJL~PX!u)c# zgOC!nOm_Bao3;8L`vU-W$-uEpv!1q`Xr$XxlXeNxh4wUS4L`n&ruO7|l~}^;ku|vi z>Go1_rtCuIfw_iUYI!h;w_I)c)8nbRTq9pt^0#9b2YR@TQHhp4N+!1Q!9cM@W5)%d zaT6bL(n%YgW-cFOWXYKyUcBkRYH=+)vA3Q?XpUsnl5qx|PBZ`~c;tW{h-(Li#9Wgm zou2*+teame5hYTuC4EeX0P#W=B_ld*J0Ys&;#eI1&;D=EQ1rE`^bp@t?r!x~;F&4M zBif#DQ9{4G!9_M12S#M{1+5xvTc;dH%hI`IR;c|A(^kb=Q$DmxL_=wlyA5nAt(}~BI=Q&$Q%IFiaIKKX!>N7A zFh$e-CR1gf7Sc3)NIH_Wrp1zZ&(dkU!zwc8oR6uN@ZL;69pVEm&HRFnEA?YEGT0St(~X-Au%*pS=nI>S$vCKr1V~A_Ns+c$El4z$UWXb6ti!TgVWYr? zI?le6q2)K_*GL5i1o!Y-kKHT^Udh}++awOVY?;b#Ri9^3$y(i07Blkw7oXK?sQ8o~ zQ^JO{RwrO0o)69MY0GP*v0p$r~GC7fG70KOT4rd-Tc;e>2os!^o%F01zC z=@c&ozeVB`2~t^+?hql=R;@e3YFaGL7RQdmK{VEga8xjH#oBe4mB#AaM2|6}BvPt` z+_kbEF|T1L;=+x^niLttG-%$^Iy2ae_z%(}&njSc5XY77@^B~!Ery~R?w8$i<$<|s zBdt#$M<6Z)H{aFYQ7v&jhY_;Q8fk2#P~>OU3|9BRs8bTh9(okt2^PXS4c6hldD-W_ z*EJOod16hJ*uZJdlR|#{Xlo|X^awO37rT*4apOp&!5*+`zG5?-d_&&3g0bj#yz^&R^srSY2tF`b)bbM zWtotIZ9I&Wijz1Il+EHdj0wKke;E}TJ`wtK3+~)>d?aq zTcpJ~Y5lv-c?WNyO82ExRwpW-%&9Va8gHnw+-r$huK48CD|x%rpc23; z_=ox{%D-k_<*`Y6WnQ4n72Z$2IP?rD`T4fl&{rC*gcc-vX5oqYs^kK7yZYYk(<{05 zgbxNF#NShP5ARzzZm^G2&qrWT-VPhInyU5<13;rTwF$Gd*Hh65CKlVPE$>S0jVYVX zi9@R-6rQ2+O&sTVprhUyZ!P!b*#Z1s+}CHJ^er9V*>$M!#kf&!rT4GttI7@i24HjMt7Pi!vGS;WWT|vp$+=R*hY+@xrpEv$WGdFIG zmI0|mU@LLojzdFqBaRGxYK;`X=>UU2-y{BzeF=dFh8!VK} zigSL>o-zF*7Ke=pvY&wBD_3&v3FuiFp33mv4Kyq#|zMw=XJg3n;+Zsj3 zcM4t8-9ES{yDwwBS-|g!{;o?f4x&Wed5n1^e53xu7Bw@uS;{q(Wm+o0>|Wm@hJ5%g z9bF<$LO2OaqMuBf!|)26K?-Uzd;9)W=z(@^w6$Pr^cBt4EvR8*(m zyP0HvxRUDp<)P$NR#En8t&PGEiIhyLCw9Bkb0Kp80pBWd!_3bG(bTP$dx8wdJrzlCV+G&LgkJYPT2!RN@DG$W<}~lu(2Jg-5>WPevnFqd zGW|X!Tk+x%MBj9(V7HYH^G4ht1_8>b>-b0!7J7^Rho+12t&~9>Sgen2@`Jmsp;@T0 zIvkpXS!Mi7q{N0byLyKdg?Qj#Ky2a8#LpfTQZB1HN?ww#_1?OFL3r_*$tl}E90`WKIp)I zg{HvJss&nHe+;!9fv~8fd1$?@oJ0JPl9>f4kznDYYVqV0o&}{5X7W_m<*k4xyK;56 z4uCVdxwvS$VK_v$cz4UZ7M-Hn7vF}-){2p?SGrJ^J03=v8t4kHCnc+~M-y68BFv?8 z(5;BD{){4F`Vs!XoRi4tf#?T(g>mNwPw9D=rNb}jbtHmnNi&%%$pD|=oi>uJflFT8 zbL*u+F84RWRnt4KPiUX)FVCu$Ya;r1G$wPd%Lwea`$l^qeV~ zY|4Y7d8s5B}=Mey7<8s7Qz8w1PB((EO z&YlMGJ+M6)P3?~=tDs6w@xFxkm=*-ygit$jgZi9nMabcU9oGuyCbM%*QSF?*Bp^w~ zVs7P(ToHQKxC86?$?sw%&OV;Qf?%o)<``i%s(73DMsM_68Ef(hRcI{z zBi2uoOR&*8|LC$s2xf^or}&!~0GNH5>}CZJWn6zRTnhD(e*@{D!F2fr4Pw>pG{vx za0xo&owovYnmvU9v?tQ<2!0s$_-|%w_W4Bj>3EKQK+G4r>8MnTvVstnL^;Q8l4d1Nfmz>uI`XE)mVD%G znO(WJdHG5sYb(^8BSUaSgfqtSdteW+wm(mKvd|7n6LDzEoGcYu@2I5tI)0v;1oA38R1qr@5`S@l0pTXPeh{LpW5-eD!SwB_Uz?0g=WAEwMyn~ z4$*qQJ1goXD`)WZt;cSiVE2a0dt0jX6Tj^+|A&O|-1aa+L_~E{U8&7EZdz-CPQ=wd z^Tw*e<^i=P@B-#ykMp%Q-z^S1`?Cf64Zeow27wz7S{|zaz{aSqviAo1h~>nJ54y-J zX!EjgPGoI`Q{ZOD4EQ3{W0b@pRcSKrAJG<@Y%Q-|{sBRQOdgm*Sp4(747}a|?j?pi z5KQ-B6*1^eqyLb-5~&T;*Pa&Y%>-MfH+Sq>PL56D?HgsGT?)BvO?J7ASinyGQ=A|$qB@b*uNdS`^BXB&S-1` z<;V*|*aNxyg;0mQ^9+>L9X5h-DyI2`Z7aYqH?i9mYCcaBP(ZLL>z%CsC)LJ^;ww%+ zG?idrlVC1(&STZzXE5Yh0&4~!Dp1cS5WYQhlid;maG2F$Z*n-o$5i=SE3U;|J)x8m#>6bl4Tjz}d5tx}r&9kFcB*B(-qAc>PWX;*GAEcJB zpHT6|4@e4}GDCCcRXxbBeX7dR3YXh$a>mh5X2Ae4_;Z*He~2*tgu8haui3u{J}At2 z_d^T^ctqChjxzKFC-*_4x@05$Otm6H#mGnhqX%u?Ez=vYdVqwVFw3Xu0x|g`qjPA6 zIXPRfe0aRvE^v+B;%vbJN~T=d$F#d8f_l^tyY zU?_vRgo(=pAXec2t%JnAmz$Ac1$rI%H{*)m{d=9l-ZRC z3v5f$yTONkq<`XJ;<0(n)N4q|J?1M|`iY{4f1ve7>7TPV_j~&Vr}x)Yk#Emy!BR@@CvmWA?#>QZruMGAuseUOdlt1d0C|J{6?ELip^wN&3<-@65^t*IC7--Tb}OZl60A# zspbW52L2KFzb&@baKnoN7$6{O%zy8{EjB}9QUGrpym$~1)GoL>rc{`mB;H0qKWJAN z5j5A~AbPy3I5$(qQoJjv-THiblbpwbYeG}<7AN$XZ05D=P4|5F%WH3EBdtv6U9G_G z+4f7%m*34t&uHS0*DDiH<`6m>k7H}ZlxMiEK6Pp;6=z|AWMJg2GkERoL9&0B^tFEV zK7g%lG}hZ($-QAij-c;KuKOlK{AR1k!<4-Ukc0bLW@_>S&d-mF4}zE0mTwBL51nOLzG z;Ye1O{5YXe(!}QbU|3RtG7r%23Z=9pJq$F|p+Xz1SYDLJZD?knyrS#Q0CDHjF#Ys# z6B!Jy=i+KhT3*mpckV8T@=JRbd7em<U%5!rGlV^Ddb+;i-?Al3@+L_oRVvS5)tYkNE%fK#m&b}a{ zV8{>d4+RR^FI9D;{Z|uNfX-XC92SOJ$2=N~DX9v(_)}9<_x;@m`O-R;me;K4pTVyE;^TKzT|g zKI=-pZ3b0j!j-VtE2|P|1Y161!GOY&D73u=R(r~xd<`1q6d6(lWwI;w#IUb*7x6f& z5#+$r=o;UKRyI%Fj>2 zs)Rfx5)FiB{ZVwFNtgs;3(0~wh?t2l8N1X%L}JSHuNueDG!l0P>p?zL<|Y!KS&;Qg zv2~_-vDHnyiTKd`kaWGYG@O-jGb#q$28Wl)eEWE#ZzR@v zN;fl|e9IP5?qeu&VKTA%AaNO+(okJn}b1!&Cw9p?SoG_AgOmB)-mEnbDE^aPb0OrK6(aCYSi`xfg2$ zE`3!L-IJFOmuPXdy4Dkj+glr}`&6(5H1$NMCt+_R&yuxGza(SrnrVxf*H`uI#kR;v zf$v%nKu>_eq_%`n@0Cx%V#!k{z<5=C_EALtZI5c;j3>uJ->*N#rT)Y+9%zurvRVU7r%KqT${%CI466<;pre2YQoFCc&)X4Bc>C%hRf+5n?3aSn6${u{&|1 zXaQOWU^-d1gFkZDgkRW;ev-gL*HrvXh~#;6zhvysXi>S*2g-V&a?TT*Rv)7_hb- zK>*?hV+sPr4XNF;2bOLlm|m;gB$!+Sq&fj8EezyghzJ;UYbi+KxHLh<;8A`du2Y7# zqi^&jxBad>CKMb+`c5GXL^6)o%*t<59>C8X3alBCqP;xczepFJy9JBL^b<0G82_DD zd#dyriUA@09_k0&EbwO@t_jOA9V}Jm_BWMkTth=Ur6#Er2Dl$Q7Fb3kh0;9^im9(7Cay-E@$Y-dg>S^&n~rBBV@7U7(HO5vjTyA#3o` zpwJK4vh40YRTWvO8&*|ry$>RY?#kTMg_RZEmRc+}t06dcJsM6Oj@+t3soo#C$0>Bo zpqv4-Huw!k$c#H;+fgjta2LyFfFH;8YpAEh)h^$F#R2A*Rv@(K8yV>RFM>D|O-U}q zUGbr?W&-kk$=MT*+gK_3;X_BL(fA-?t!iBU(cRLfYTvBlu`9SI?%#<~qf|OEf*ieX z-Y$cB)G_hgqaU5itd$_+NI-#JqgHPcy_)XiTY4Q*r-1xv$~^=Q+Epg(qStl$G!y3D`j z-Yz>_R+miI?vk$?I%8`Ry>H3~j^SEN>)8Itu(a9Ud{JIx47BWxKSYM850+TN?^DieCzH8t-rizV6j7&)-=^G>3MG&ao{g^86eIQ79Xq&K#3g#}>Di zmL%oe|4mz1Ru{UBuuW=*R%ZtbYoaYOkKoT?-lwmcXS_Y9d}iW50Mt#h{qtjX&kT-e ziM^RSK9>fgIa7}muWG_m6PiHQX_A#`5jN@5(T{d%`aOY44o2(OMg!Mo4bnI`l=<-~ z+d>;=(bmHcx4r`!Nbexz^@QeBe7C|p;#8Yw>)kW*dhhi_iV6KaK8jbQG#no+r-}Tz zqCc{S*_Ta}MA2rloImMsnpOrlV_O4y^e=YwFZWb%aaLGlvWAQTvG(J8%Gb_FUDn7K z!#|+^m(4b&5EO#^_u^<0USB*O1PJI2A~BBuD^YF?yU|H26XbvUyLe_gU@HH%b`yQg zXpsJ+NX(gECj9fx0tW(ONt|;hO^l0&NQ_B`NUTjk04yN3BsJ@er&4AFs;$$RQSDQN zjbNjY0HeS`{J>vnrr3I9ZVjInzJh%xixSQaLEh#^d6duyZ-BkJoNV*BT=ShwPu>U! z_yd>iuMyVdC6Swy#0zPKxKOFir-c?95y8WoSyjx_mN;tU=*>GC41$JmzGT9+H}ieR z>mYb!0+!8BH|$-~jrwdtTTT)hjXT}j#u;@k`BpNi?3hTc^+gy>S8O$^Zd%=geo}5Y zh28JZH`n%i=ng2;p**evgmx6+dCVw%k2(fwxp<+#uC#4(cA7Hy9XJOncv{pRwCS$d zO(Qur5rYgkqbY#XOP~x^g*NtbSG*$MqtIo(06`_fwFfqye}O_)Fy_7Zb1O2$E*An> z)vVC5U@-cb;O@Njz=ZNUngnmP?-I^GVB{RUKm7H&nvP~ieW)j8!eWdtxt%fNkKLOw;(&lfI@|~&9;YNPmad>2_a#uKBB4;So2?fAj{=ysl;?g01k}R5ViN4Sh zf7nB&ZGCz6SP5T7Nb2G-%ty3(5syptnh_yAYyYtD0mD-BBmsE;S(eV^3#vn zO@meW*PCO1P7xsem~mh2eicx*lnH}iSKu$TUn&ZRn9X_QtJ#A5qBhD zZe8=~ieYnD1;@X`{(s2-2f7A`{PTs0`rcXqC10p9Q54tkE+!8fyrmj853xIvS3O^% zaOr|@f<8nu-qy;(hWJ1xIqw;+m(3lnlWmuc+}@rqAjOdg2($(4hO{#ZDGjDdqG&I8 za&*-sHCpDwbN|LMzRG=1_Ce2K4ERQ(wxf0PEw@Pu-6mTbw;hXMBA1D~tX=lOL)Qkt zhio!Y_qh%jgXG}5d!u<|Y1eUrS=;_fyUx)-ytk<=q>g+f5#YqkFmluZWb~z|&2N*+W<1Zt#p4ae>^TLt-;3ibi0h_uxJC?F8 ztEsbIA{=NBhDcf40OMlHhLRO?9yU9`C(dU`n!X^C?qw(Te&%hvfh8VaqOrLEh!uPjhaOk*9`hk%br7I$5&r`HPiYL3q#~2Nobd^-b5im zMg&>Nk?1?iP4h|bgLl^Us*wuwh#MNmz2=BqNV~}s;ozlHORmw~>y{7)rW z(ZWY%WdfcmxI?nd2&N1nZuf%(MK0sXBeD&oFs16H6#%=|n z?iX;eYYb`d;X@l{{*5@BO@g(rnD|bqwQ~rxsTNI2#WInNowE`;KmOfyd~8(iTr^+Z z7ARIvm|5DHBXb+7eP$9lBbK=4xc!aPnh`OfCz9|Q2+IvggH?!h732fhff$_g0hJYl2oJ! z)hZ|%P$VUiCswZ}p&GBNbv*yk{RP|gSbbEC*rYO0H0k<2Bx3PS@h-CNFQIO_)*w@o z7(Sh|l(XgF(aU#F0QeU=0#fhnaCsQXOt@p%W!(&Uwom)u%!40GJSWKIDCPL!;G1KSefpM%v-6TZ?p0p!*qmB}kJJJ2WD#)CcQ4wXtrAB;^O)C#i zQ?ycM+59ECE03vT><>#=Ei{Eklk{2DN{wxhpO<^_%I)EoXpc*9bvPmiDZGT0u8hs3 zShCL`$?(^I)nT(OI;WFoV!M%GIRTiJX2-pBJo+UiL$*}3W~EzFG=j&ftTPv-!!FEw z8U(XfB{`rvEOnCStFCFKIX9u!8zS2as?p)-QaK(s%bJ^tGJ>797Rk5%+9S^)Z7pUe zA}gN(MKMV8tLto-Avjf6igH_5xTnpMCiQ z>nhf$j5c7g?bDuL4&-2%RMqCk$_Oj?IkxnH&eF!B<4xAAsV@@gFJ_IYf!IkR22nQE zDy z--NzbpsjC;3eNMdg3$W?ryJ%uOhVj}8s>UGC+Y(R-%z&y<5f`D!vvsU>RYx;;ya13 ztQ&h_*21$?umSUI)ElU9TOJ51{0^5Jd4=)FWMCt_V@SZztOGNTX}EV{%13};-RZNS+(zOFsaGyLy(@+=^eudV*rk9+~HwWKkL?wsB1n} zmy(Np?<3qfQ--vlcMb?Gh6xW{Sy2kWTnfxH;kKoL!c&tWn=0xzT(Gj@vsV&fi45$o z>Q4*0I-C1xh~ZLKBO^wK!6ia)iK{M5G5VF5R|Gq;oKn?^?f&r4`Df>yG9l2+u&~Xh zut)CK)XvL8ZkFQ_==OMxiyRF7yStYE2pO_h+&z)CzXT7lE(5?UM|hl9WMfmMNkEA7 zfn}LbsHr5rktR&4&Djwg4;kMWC%A3sAv}DNAq=iY&}#6q@ZYgp`1X4IfeWIs?{(1+ zYR7CO{&7R5W=QxEZ!wd0muMs$T}b@yP5Kva`f;X)W7=yNj07WC+q^t3*}X{;T8-M2 zlR&KoRd!ygwK{<7I%tX;_^RF}&LxsE>0>ibjpCvUNR5JIu{$I&C(%Y19EvLuE!p$( z1kGa!lsC&s?@4vax2j@(d9Z7`6v`zE+h`$vEo{g-uSGCVgf|D)@cI@+ zigRmm?A=@*q4PC^i|dcl%vi4ez&eX-!%{S-vL}*DFZ!BNkpX6K1hIb_?)=30;V>cp@Hl;Q z3VjUkHbLe?7W-asEd4J^k?^$rLOOOI$%p5NA3k^~!y2cbcH$Xm4J)2r`(53(vn$1> zkLkQifft$-G(}fi%e^(Su{rn#<#J7#d`%xR0|8s&Qay;8^xLZP_OK3)MgG|Pfp79W zn?}bs!~YH4%(faW(*LM2*uU^C{$FbRJVgd5R?%}n7DDA?@ul50j&FI@8jeU|=q!FW zCXALg7ACb8UU&h9$TDBEb59-V-3ROrr)Inw`u>}x+|c64!a|^kr1_jox1UV&c|4!g zI_v`7h)>IMa^j(mP|tdch|y`1c#${^w$Hh zAZ6e^THv5Uy5j~pz>kzO|3Qg~$WNWSC#3V*aPT^Rr@cXxMp zcb8xRLU0Z45ZuW^a1U&7cXxMp2@b(MxVz=Q;kn=Y+}v-grs~w}ulw|z={eeR{+-jl z709_6)^&q77QHQ7X@|I;`2D=)$jij$I4qmF+`pWuM=6kVR$UbCN1}lhvKg=&FHo>$ zz@XWiVIs&3(ZY5-c6?VhUy}b+J4>%H`$-#uDH^r77LZL4g{Sok;pyqMm$~*O43Fwv|DL>gXKT+n4T(1=K ze*65L#NMcQr9+7$wwoIh)-s6?iaxnj-pm+N7bb(f?RlO3lW`_*UsZhxW$@~aHM{M* zn7zf5NMgVOutlWzHXJq&HpL(dKm2H44kJK>cO(au4W+_0CtXf3f(e;4>`?QZb;rTf zO7W0Pc}w77kH`;sCp!~f4v#tpj+i#Ja*h>EaOokkZ{q#a#m}$wmFPl2RLYdSoNUeb zH5$K?(MxX|RNxqQ9f3kh?re^Tjp(E8IVtWrDWCPwb4kCI&wn9PDf|r`R~wJZI^iFI zp}o@IUL}PixN|`y8)hu^{FN!@yJ2ZO-55Ax4-~pc-W8skHQ&b->w?|$HKtF~JIj>-R&9PRbMQT{+Z zXtvZ0p}@ch5P@QrQUG@Xb*xtur1u=jdtbA;Y0Bl0upyAk8?2bQarPPTl;(TCUHJ(B z>i{h(%NMdtkwBf+PrOzp+Z3TpT}Clpn0YZJ43A$Xr!_c$#sj!`KRe)+ah28E!($1;e_;>S739C5x`6I(-O=yq4=>x;2R*93XF9EBQQ5B1x$i}E*t?Hrkp_LbTk~(IEab} zc=oN6d^8cntr&_N)(slbmGpB`JAG*!n%s2oOp0<|IV1pk`rVY4kCiDUX8hkE+83`a zo%>uuin*wzs*y<|7m)@I(W3~71Jvv+l1bBm`x9=YX}yORo6Ym(DK5P(3JFb}@m}I~ z6j&F?X1t~GF8yvbPuql7KMR+K=({U!k%xXZ$F6H4x>0Q5sEiyYdOGI|=AP_s0rYze zG+8}M9Ebq7weQB6irl#~dMp9BzW&Q`7d$k0@06F~FIWo9#te1(Oz_Vn(PI-;#8d{D zKB-hQ=JaXaN?CH;UPwu4zk_aplYEE0KEl>r*~N^{V~zC9(eKQ3)^RBH41dC7;yezK-uY$rm%m;DK)yv&{}gzdpO%{A3B6D_F& zy(ZS)-n!D#9hTtVw4oJ8J>QN88*Dx;_x8VX6<1A`ZmFqmk)xfKf#HvDY1%jG_ONBu zgLcl_E0BrjxHl3$4pYC*&$XNg^`h<@&85rTsV;UL<`m%0Jr1x)R^eh>y;99uK1Ee| zyJz+T%qL4OBo%Kx=nhvz=z1_!~4tRy;fXyK_WaAs6tRwut?aLD@3x3jx;JNMD8>W)1TF zyfO0qf-x61A>QKaf(;l%JrK$zyyF)-MGR3lz-2}U)1MPzDkgRfPCbk5#JtVp8_wM; zt>>L;W`t8GG7=9Nu~Dee%QU)aaAuW604EabW;6YJIR8zUcR0S{>p$=!rd+P!Obl#A z`>Dp;#6Lm$!;|l0lJK5u*c_bUR$J_JA7yojegC=$hmMKZ*Avnw8Ge3(RwEM_AyXw4 z3cx|j{~S3PzXFb&Q~Cgeoc#u6 zNM~v;{bhU>`Y*$HCa2VCAFf-BZDgp-n=w0}cJYa}M9r>t53|JT!Qjm0HM@x8NHDN^wOf?@gmT0v?_L(juh8zbXk{m=j->NRM{1RRvBAr;Ee1w~5kS ztn>x&kLQ2(8YIti-CCuk4hsA_Q0od-dJvM>jupVZC=#0Z^;L*vhjWKhXPY7&ft?BxSW7~FVI(yiPB=&B0Tc_%>|d`@Qkld!vLoX0D&!H z2O~Xq0FCE9Ze&EVQXXJ|8 zAj>gIY1AWIslH7%6vw7bs_?2GLBX}lcdBT%rp)CI= z5!`(r^2%>((gdH7p#4Xl{DeDUG>P?Z??ky zt|16M?QPTiT!2Z}@yxyEdGM&!`sI|~c#bWQ+BP>ho&*0pl~dbaE@BTHc8dyl-)C9| z7gBDiKNQ(thBuR>o_=9SwSpG|(`)A%8?D4?JwT}v)yS?`!D%ud?l6Wh2>5!jp~RRP zO22N9-eE5|)1=V5+#9QJ}gy7-&^Tz%Pmy)lb;kAW@0JxdH(*S~f2`J3_F~#A)WYq;Ebu@-0GW zXcVvOOO%TZdwR9?%@TGg0ic0vcAj;;rp4`KX*ZFJ?LpI?(>+C9|H80{!Ma|%wNxY3 z(GuHWh>O9Pv9(Na*hG!Mwf!f2%F2MD?qa07ban4;a&5$MCOPMdh8d?;69ZB`n^;Bd1eS}qz+!>p!V*soMt#p;rpK2X` zSahg_OEm$p4BT}h1bu8;ne2)Z^d$)yxRJ@ak~mDK`dCP?+X_i~)cHqAE3UCP3OtDQ z1T6v$I#cx$a4L+H_{bw?eOZEQB!L8~B1WGZETnwo; z1T!#Zs7)T_4u~8urw0C$;Z)n2OlMggeu3tg<2_5V5)GqRDE!@4LsfO5YER@gh|lH1u~8wKnPG!Zd94fwC;IeCR?I7?atfw8+g$RT-g-vQeEwo68y&X-~^5dIjk zSf$9QJKJ?};*n_(2AYu?W1qR|H2^RsImI@ubI6N}R>3V~vnD~?Di7@|_7NPho+$(g>ai6~P+7UbLt<%? z#D{!CrjB2n@VF>BzXv;Ipq2U0&l#PXr=-}451ywd)Mw9pV|G~zo?+i^@;aRy1a1r5 zHOQi&HxyCX`RY?))uhA^rb{e=mkIIF^bH@#Hdr6=umR9lRDsps8EeeCu-O^ahddhH z>Knq92aqx9-j9biY0#5${I~-Tjub^0(BXId?$wL|@7>|+TNo=C5Ff6!<2{Syg^&yg#|{vDGCL<(V?+|A z%q&eV2@$#_I?~bhjT(4D>PV=Z@#yT%+&w~mB?1`|rj1532YlXv3=IfJ2oU|j%dU<@ z&((g2qs_aGS5&m<@vt?%3$xw>i_{U{X?Sk;EFJLqmmruWwSq}Le0YDn8O-`HY|uVS zz}cQ8m>oCk42MEUpOt4=b@+I^nd~SRpQ1+UXzrBk>_%_S^)a8!%OeSi2-s>~8!8#)h1Byju?bEkW3D;-~i!#C!K)PK?14)6|N&TfG zeRHE;W%O%6vN>|CA7PVHm}@6Z<{(M_@mSD>?d9`2E>GeXKq>`iwr0OtX51Wm75nfwzWr93q!koF&s}1st-0J zyK32&Hh$g11Ux->!X;O<1aX|@(60b!$r`>@g&v2k)rWL{tJ}g( z8D!XS<*Rq>?j8;T`@_af4{0wB-B|ZriTRrwzI(Yc4+jUtA6Z}84x;AdQCC|0$TPgvT;U)EAcUp;}9&jH(IJ(9Fj#TAX~b`u%9=$D)O#f0QtGU zxq?dfx#k}RVvmg09CekK_*YlIKx4^;G^@?GmMkbt$HP;y`be9LZ8Spvp@&JSFkRdAVuZkv7(=m-%Po>!_z4t9@mWQQjq0`R4Rr+93_ zEnK*;O9>KDeY)8pgEDC;C$?hZMm$zG2?hCbhuo3ZWPeOq$`YrB>W4h{ub`@>5Br!K zum?FNlEonbUn7YcNe$nbQ)JmqUX^J%b0ztl9DS#ad_dvBFNkkjF1I(!h=l~+6le`n zg2Q*-&)S6NT!=plJVo_KQ~-!YZW)KW5XHUVkid@)Sm`m-IK0Ugh03!l@ahOoOcjap zdLvi+p1Qs&=i8Wn5X_;}t0+C>Fb~ntxyZb555lSdEjoPtREQY{-ffg(+c$97nzB|l z;xfBz=wKs zd%RKyKo@g*#OhRc$|StM`(gq*48IgD38HQ+x%IJ|Dfl6nq9u-V-PXtrPe-!d#ye9VUJ-$FDS zLSLB)ajw=Mp#=fRA*i%nK0C=BA(9%y+uT)@Ra=^Bg1QDj1Xy#GjW*x zQ$naUWFpqhI_k&SQ8s@_(d3zeJ#NV)IDW?RM)3sm2sTh%RO+gl@j1?Syl9G3`w%|C zD|~k)_@&urXLeM^lHO%lPLr1%bdZahpNMuaVs=Fk?IQ%J%?a6qrOMD_$cX+3wjRY5 z%`>Ie=fSM6ggb?!qoDaM46tm)=&H)8ugL6zsV!TrA*D?ytZ;IT0e#R~7xe|E~? z^doF~4qFT;Ojy2BhOA&yQjVUyV}^|Wimad~<;j-a?0C8h^;v%DJ=n>nj1{YB^!lJB zsi^Y8MQI%%bG?A@9>ObHX3@it!{YTV-$Bt9f8^za|GfaP)#` zm-%MPQ6SFQn-RpqlMZ90x_@*{bwDIJAsU3;JZW8;awBeUpQ9;XIWvnzU2g%rxRcqx}moaJF z3w0`VYj$&Rwc=O8_PVT&w(Kpb`epSK`b(^4QVDq+PxA#2$l;Ze;chqFy~)QHlD;!m z2;VwDXmNHA3?_kYY*$?WS2lkV9jBeyCo@QPe&~4`vSieTWT@6LDP3gNGJn$f-XDY; zyi@L&&)o2ihThULQ~=CUy{=1)M;yx)HL;n^Oxmhm?ktaFgYHFRv5Nb#d_JmbXUz7J zs+o`>0P@-oInNOiPf7d>#m5Fa^aX}<$dpTf?n_-A$klNI+Gid@Bas^%`pD~`EjS#j z<95m^DJOFx3d8?>^khutJsU?FbH z8|TCPNP{R$0! z>l`@s1edr@9w;I)>GPgeyRZ=~Y<<(mEA`i;`-9#i$->lKbJW_V{x!?Gyy%YR{@}B~ zOQ7;s1&lS69AiFuL+J&uBx+M<@+WpL#5Qi(&h!q+&y+&zg;rp#wCqoUfwyKB;0?mR1-`IQG{|F&>mJ`3w; z*yFE6%WPQvS!K7aij#xH-iurF*9o-l0qJ&)u`jLJBGDHIe%m+WBg4M_zGy>qi*@c*y zF3^q~LDD8Pm8?pihM`VXh{bxlMahtt(yBzd$6YPg z{)+i1%QQ13x!DV!BFi)Wg%|8;;ET=*RlWtQ>pU#hectw6Ubq@VYrMg!7zX$nA`%hn z92dm8=#=FnC)tZ+iZa08P6UuMy8oGu;#J9;&7C>Y36T?In8&^-{bRdGPU6Y(JD$uO zdujj@n&l61K;>6A++&~ouWr03f#?hst9;0X`B^Vg2usRTSuZ&Enobn7>mlzS&iW3t zf;5CEaoj{R)Gag%(<4Y8NsU7Le=BslYaNfUOsC`i?pAS{IH&qe`Z5JDVn>zaIKC;I zEicj;M~e~-aJ&A1rFAMIVZXqsrhzA@bYVevT~|U56CP;2GbD8VT1Mp?T80xzB(2|6 z8D@-|vl=C+%e%xl#UkmAy(DaT_jS->(xCjgDd4u*wFT$I6)!W;O?2r;PCLn!w54ds zEleG6i}OC%(vN^wnmS&J0DI!eYvRwRqW=}*`Oj9CD6Zx2LC`i<2qw@dnHFe0K?GRU zvhl#$#s1Q13e={73=RVG*CPF zlU0LB9u4nmxFs)tc?^lRS%a#aoB15&-?yHRLcWjdndQP3=5DpAt5sp5Prp*H($7{p zoS!C6`+sKuz{LdD;;W(EE3&A`b1?xX81M1PwIby%FFg%x4Tuc%3Y6vWP)#Iy(D4^G zijbh)*{_4xI<)**H%H&QG``>J>{<4v@=+h~@)3^oHnZ*Z<>>JLd^y}`>O;70)N>Ym zAw011$^UE{w(a>tPt5&2AE_wWHXh0Ma}#{ms-Amz0IjDdU1a9voe_S_hQ)ip(-p!q z#GS%Db*ZOXPbF0v+J~|{8?8M*8^XQNKw#j{#Gq`uN~=RRWeI1ZRdmaf+T+-HblnKr z>v^pn%aiJX0WQupi=@Xd<8CgkG^v0PvF1wgjl(TD-9QF-LCA zM2GMuUrZQ0^2v`Y^Gsemu6hc9y!(WB-;jF8a_(J%uz8VQ#{=7bKXzkl`w^OMZp3K! z$EQH^=sK9YQ)9=|qRrVl{nxz?==be2Y{-oY8xp>bmuBy>n|?(IdU;OR;$gwvXgOZa zW51uyBoNG7hOLu??~!^eOG?0-wGFrf=jdC*&~gV_DJFHO^G~f9toZc+%64>ra@D#p48~HB`$sE;vTa%rfZa;;F=zrSj?W;+T6bV)P_rv7GK2;ngDAGK z{u}i`JFR6^VKa`>uC4A0Fx@?hV<6!9bHvvW-k8o1Qe!0gfEO=q@95G}htCq>HcPV` zxhXcA7HWPhq-MFHK6l09et!YMEnB8r!&cLQ*o|&6EQWqxqVcOZ5kVZvCp z=X+N}4$Ha?ABtIgCcn#W7C;TVuXcQfs($^EESMpwn;*UwVZubI+u7qC=+wZVD+1xm zVE6t~s(cg7ob|gFK(5k$Lx<@D>*gKCYt}~0ae(NiMD*FqrOG)+>&p)h>2B#ZhN>^* z{T1J1LyvfF79n$6N;bHkgAx~@dGhA)qX`y(4J4GAeRJj%UXYct9;)5COwV@D>OJdF zv&Qiy8yIWoO}CJ@*8b7d4bemebI=asqle-UilbI!*9Ew&0AK%>t#%GeuGu9k=0aP% znWCA`tmp5Dk9DGVtzgrCp z*{@DOvf#yiFvINaEbQv0=A-<5VNe3eSf};gJuT&Sg2(!&u)=&iJ{W?B(`Npq z0WksMu+>4~HJ||^n)S7AHwrpJxJ#`g+7b6)rHu=QBifh;FS0K7G59&#&4i}tKqMY} zr3yU~?b>pe%_0gX)`!Wgzi97#MG_`;&BD%C^2s4ir74p=x!GOku_lGq3UjWYC-43zlEhgYEIoSNlq;BOd zwc4s(SWbFz?(ihjL-@Q)8VvlV4*eAq7r*@`)^w8t$Z&K?YX>;1E8Ej#ri*#u;=jbX zO)IZCNqOXv(e1zlP3N2@)Ji6Uh#V4eW=@1o& z3J>scyQv#66T*kn&d`|06!9a@5sxRbhTpS`n zQx?Zi2Hq4_Yp01Pdf>EgmAMDFcHE93KVDcNeY1mrb#OM^M$=Z_=CPJj@E}kJ7Mc6j zYSFTV#XD<>j!mpO2x#6gbaWV&Tz%+w&JgIw#VW!SqK1(d5X#T8yqC`y8=|*p^PrCq zO#^IpQrqQu_z}q|;g}r{$<3N+?|YZGWG!f%zY_60>hRt?*plWvhj#G>+Fav#mevO&ge~zP`pEzURfiBwBcv$9*(2EC!c8`jLuzgQhE2SR zpvah+J52Id!ecx$UwHdMR)$_J<@HMc-&TUbgA$j&|7X|-f(a)3fP;ZOgHEyd!N9;i zJ6W(=I2oDRnz7b8bk+TH(EhFg?oJpI3~U4*bkL3stQuni^lKb_ocVzEs-z2-2QClY zCunSz#asuCUgbfr&hn8?OM2>4b{_#9JP_sr+XrkN(!%9Kvg7lw$e1ljzEe2_EQQn_ zw(ZPXZ?`)i3-{Vq{?1pQCls<^Y4q_>u4xSHsjs23HR7zn4hmgWe#?5C3=&;Qeu5AK z(jJb=fuTbZvI4I1I!kftLG=-+X$;vyhuNAW%40r*ftwyw=lnPcP>J*kisTN2pK zdf$IeDXD;$<)~X~^TnoD?D6`UssmgfiES&}rNE#0P_NgfH~s6_6QAc{BO!`NSr4DY zmw&Z}woqO|0oQD4YXFkJ&IEfXzVGM|1CXII zDVhTm062pL{!1EgL$cIQ27`v3+EAwliGmrY%11bsiokv&ER)23+nhlg{Cp$ z)Z8W4Hp2!89~o+CKoqyx0+OrhK|(9{k3_EC^WvqFgrs9a%;lPFqNw6H%Qr#O0R5Tfv&Qy^y4zUf!+xTu?H4l4e#iemyc6IlK zyL?1MCPSTj`+pIRAMq?H&a5e_Aq0!`Vj~5)Z@$WU<1Sg*?Flr53fw{&B#6Tf3&?`P zV*z3!{Q9R%De!x-TgKnL_`!ID(tOR_c!W^CXFSxq_kVnN%{&K%zC?*FARls@YN~~G zOkO_eZY4qh${wz3@|+MgZT<2)=GXa&SXXNXwa7S{p5;5`F9@$E!`s~5OxV{U~0WvAt2ul zjCDQilfHvy;)Cd*17mF9hiTl}pS2mVZ$1kjCE$sRK%eRzD6fjpn_*T)1TjEgdBzZH z@b?d%mhvOhEV2#`-0$sVCZT?QG+$ZSmAJYMziOhEC3CN;PUEbzwp|PmzK|Kn=1^Yr zpl*b4WE3(x6DkZO(46oq|9D7Wr~|ydJ|brYVq>%KsQ0Oa0=cN?N*OSc5-g`_}O z>ZOh<^n?<3FEr6&3G^f3f@G6v|V?fN5e+Q@&{O5|PUWedH3I;|ysTWd>^X?az&_)3yr$85KayZsIdGYl@y) z1Yw1u{b)0DFk53OM<*pKeq4g3xUH+0i{I_SOCa?;vm+kE6vz6UQnNei3;~&07!9yB zN21=sIaNi^0<8C{BY17KaEJNb{&-|tJRVK-c2AbQmiKM+mml9EIK2AIb#5hl$v$54 zREqb*BO~I?RD}`}Ol$($f~g~A#LFIDZ$phr5^*@kZr8+u-`}~hy(cl@`;u!C?A#<- z!h5c-nrLKRBg`6kSZ`cefS5?WI*xDk=+{rKX{DtUKm|?CPcDE@aUxk8+WIh<6WCzhzs)O4DVdo>j zc8d-<`YR{jk)x#o#DrwHGCo=IZ+{13$e?0@?`L*R$|Ni&ggg$zV6@cnd1%A9Y$Sf4 zVc-X-lbj+OBt?05@ji=fM-k05VP)Y635%&j|9EXwjz2v{G(Ij3nemY%O@vT1qVQWG zAFW!if~qkFJ;L`ZHfMX$!G+1iL22gJt(1tb*T>RLSJ|IQW7nQ?YEfupJFb}aaGI@UC8DKt%7ge5UKm%%L}<8x^6&%;zrII0f7h{Ur4LKUOa zBGDT7E{PiPA5YG1yj+5fm@IVS)%riWm+F-0&8ceFYN$r7rrBFIs+U%1<4dp}2HUf; zmnnPoev;waTjkL+w@wuwNoghM#Wz~Co|R8=m0?yN#u!O9t8XdSX-VRZipv^BGnhI} zO=u|4b#0xbg{#l{}sI-Afy`sWDISf@Ipd%G)4W04C2^OEBTP!jAMf$VF z%E4!XZ6|tFtIiTwnLfM%c>~L>t{x>{VyN4qGVG#L&{phzPlNJht_1Et;CZT%lUOKh z2W161We-(RwH?NupTru-upa5C$J3mIB;yZ`gt{)z;909Ac(CWqL77qqur$ZdX+Jjk zhG^c)pqdg&M0DEq9mv`$*)+R7`{n|JLt{C!`^t_QrLDhCrK7j4dxTJ z>|7jkT6qTYFqM9o#*SRW=l%3}SH zgkdnn9yf1VRGJz8uIat32#d4_9dKcQckJ*j!(a07bx|?C@q^cr4Zx)`1?H251a{iT z+JZQyD}9eOL4#tAdKCAcj9V{PFlLL}3mY$}_nm!;X?=_o*I5WNf|1YxIc+mTsF_8# z*LPkq=Db#?g$7~$fFM>J<>T((oa4S8nM*UqQTmdkx)Of+gRrKA1>8L*-+g-VRqCk; zdu5syuOE3~CS}?iPyxkw%2mSGcKu)c&+s2He{}oaLqZ}>hhEc8S3Jxr!<|U73|J9_ zq8oU&#B>|)*If%vV7(0Ya6;X&T|1Fx=Pbq&#Tt;WdoJa8lcepNhaDnE)~H8Tb5kt} zaM%W{Mev8bnk8yQbOgh{$FO5h$%#b;KPC%?BKG~hBWFzT5e-14-Qw9KR4zN~EW_-U zrP1loi<8dAjysLe%dT+9Y2h+Fr4Y%oZSu=o&(TM(KV-J@o14V}zfT5}%HbgOg`R;} znn6GPAv%$t2a5$cNiSlPbQ9Z6rkse6;tOxwGwI)505i7bS6I-9)(SG@Y&?fPoOp^1iL4x%iM$yNDLyMDjw+`MZD!#4auG{vxV%G)68A= zf&y2nKV+AB#fB~>|0c^X73hGIOhnaP6^lxX#gJTgh3WX^^7TS%D7)g@j(Xwra$t{^ z&q1qg@&3N*4s=|V!5JVULSge>B09|=Pl(@|R|#I5wGBZIo_m_fVhfJZKTV>xN`a2% z5qYi9Ied)1wJ9CncJCYFjuBbqP)GX0k7;Lw9kn4r{<=vjzYnFX!2*^?c7&Okm?gh4 z6|20vg9w_=gxl|aNhVy`TUv$#CeD`hb1$>*35ytk_ zybd@rRGpy=p;ZAv!zs=V!%+QRY$?sma^IZ(hIns5mo1fj>>Wm2SKkuBsXv|rF{<%K z2%Y4oXqkoMlPw~_6JjXGFkc1 zyfFA`bWEhMwStoZByG3h(}erVuHjTz?+b`9nt@ut_lt42atRx2K9{xByAIE@<{pHP zie(4A0CPeWI%|X~_4FJ%jy63aXc=lxbVbl1(-yL4=}^Idp57d%OiO)uc*v4`|Qf5Ab3GUJO@vYiV>^UYjV|JQhxW3N@q zM?e`fPOk@RJs!zzCwvOtvJ*kK(S5Kbf%#*4H;1r9z`HFRVQpkRc!gG@rDRhp9kfqP zP`}@!48oN|G7PE8#%5YVIuLGuaF)K53K1oL=V(~y;Gc90-g1ksW9xl!w%U>)9KfEP zPC23b(|I?8yrRBC!h4hjofXY1YtG6i^A#Z3CBr^8_-%JPX%}vQ773xRv6 z5CMao3OQw#s~gaGqJ!Jmx_3GsBXa@&yp5_T6-6cDhiaClo1inDBE6M4F)^0xT;RTU z`ucqH0_*2lM*FP~8Cjs_(n=yXGnIgbJ)ay_vcC=n8)TruO~qDdY#<#=uI-$vcsdJE zNHF1uOw^mAxFYNk@Hsp@d<;Ghq?Q5GHa4NRL4yBgfGoJeOmw}9$(>i2iiVG)+j`Cu6n zY+3Vbh!LGap2zO}SpfbqBgMNf0MaRCapt0gOD5E)ak74Mc8O}F-J;-Q>8uwjZi+rn z_+0QSga-_4&Vo*{hsn(d@e1|o2-^A0uuYDN4;h;b0}vU)NOdaG+nhO4++qp7lE=gx zupiv>X*p*-pM^id${xd1+*aon%fU2+^64HKyS56;~d=oS8}UADqFj38wdWjd?d2LsU8RQvdf_5BkzA)-a&@@ z3sWirc%N0zp{0-rKb!fHA)%)kWg$PDqj}`MEeTpAi}K_3yrtaTS4VJ#-1xT-V|nSEvn*@a$tgr??dOv4{tV zTm4YaIi5n+9FvLaub)ErRiO%GHSzEG+|DKBd+mxvex8uK3U;EVV^#4DkR}px9smU% zaDBQZ?-oQJ7Z2uVBm|Wy#-OtQoIVs+S231G?g)N?C@6DD+rmPAGT~M<-;bDg-{Ea9 zB^2PZ6h0pTh09JinGV$*(?Y}+qSAZ~7xMxv+klr_x#G_-j`S(qH{PZSOSThOtvz=k z9hPX5RsNxuW08=-Nmm%FrAdV9S8iza9*zGhUoI{X=^ihr&!!H+XhO?nq6R!mI*F=> z=qKjT)4kQ${Sgz%q=2~RdsX_H?>}+tD1a1E@}e~=kK)Bz{rmsBrBZ4Z0`X7G2f7|b zC`6Yhd7x(xFV#HfpZvD4aAIeje+o^#!f(momR>`^2jRfLzJoZ@0b%;6K;b7~ftAAqWPeh{{W{iiE&)}u z47w;l*S|k{1Yma`Hc*Kf6$n3w^bb$#Ap!_Y#JBsYL!@sE{!OL}3RdwiHK-(t0i5a= ze*;;QS%0eoZRTo#mehQIfxz+KxG5+i1C@1SbHNjQk^x~a{d2+VSt^aSZM!S3y^4-07A|14Wl?r z^Uu2(2i;>c0Wz9V15rkh{!w<45dw%96QIBdG1;H)|F1YFe@WM20u&FV{I9SlFxdZH z=^x^MB28S3VMAn_zkwOYN#3~r>)j6qM)Mcfcq{DfWUWpyJtIw`9}Q5Bd`#p)dl}Qt%i1f1O5ryQuZAk*g5r|2AG;AfPioX z#&ie)zs>w30WFj)5|+X0eMaVu+rI}l|N9{0X>TßzX{_~Q6>226;pynY1eNasQvICV&vVhgK z6o0+Ze>bWB_kpZ(L14PSzL7tQ^w-YyU);q@-$coXAOxOIAiX(({@E7Y5J diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties index cbf13171d5e2..2c2bbe5f9a89 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Jul 27 14:32:22 BST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradlew b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradlew index 4453ccea33d9..cccdd3d517fc 100755 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradlew +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/gradlew @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -155,7 +155,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc index 82fb802dc599..d16ec8fb8c48 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc @@ -37,7 +37,7 @@ Andy Wilkinson The Spring Boot Gradle Plugin provides Spring Boot support in https://gradle.org[Gradle], allowing you to package executable jar or war archives, run Spring Boot applications, and use the dependency management provided by `spring-boot-dependencies`. Spring Boot's -Gradle plugin requires Gradle 4.0 or later. +Gradle plugin requires Gradle 4.4 or later. In addition to this user guide, {api-documentation}[API documentation] is also available. diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java index f278410a579f..c9b2eca0be04 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java @@ -84,8 +84,8 @@ public void apply(Project project) { } private void verifyGradleVersion() { - if (GradleVersion.current().compareTo(GradleVersion.version("4.0")) < 0) { - throw new GradleException("Spring Boot plugin requires Gradle 4.0 or later." + if (GradleVersion.current().compareTo(GradleVersion.version("4.4")) < 0) { + throw new GradleException("Spring Boot plugin requires Gradle 4.4 or later." + " The current version is " + GradleVersion.current()); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java index 47dd1b3eac09..b7b6e3a844e9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java @@ -53,7 +53,7 @@ */ class BootZipCopyAction implements CopyAction { - private static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = new GregorianCalendar(1980, + static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = new GregorianCalendar(1980, Calendar.FEBRUARY, 1, 0, 0, 0).getTimeInMillis(); private final File output; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java index c25211041dc1..5e8b05199f72 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilitySuite.java @@ -38,8 +38,8 @@ */ public final class GradleCompatibilitySuite extends Suite { - private static final List GRADLE_VERSIONS = Arrays.asList("default", "4.1", - "4.2", "4.3", "4.4.1", "4.5.1", "4.6", "4.7", "4.8.1", "4.9", "4.10"); + private static final List GRADLE_VERSIONS = Arrays.asList("default", "4.5.1", + "4.6", "4.7", "4.8.1", "4.9", "4.10"); public GradleCompatibilitySuite(Class clazz) throws InitializationError { super(clazz, createRunners(clazz)); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.java index 0dd6d0ff16cb..33ae6092d825 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.java @@ -39,19 +39,19 @@ public class SpringBootPluginIntegrationTests { @Test public void failFastWithVersionOfGradleLowerThanRequired() { - BuildResult result = this.gradleBuild.gradleVersion("3.5.1").buildAndFail(); - assertThat(result.getOutput()).contains("Spring Boot plugin requires Gradle 4.0" - + " or later. The current version is Gradle 3.5.1"); + BuildResult result = this.gradleBuild.gradleVersion("4.3").buildAndFail(); + assertThat(result.getOutput()).contains("Spring Boot plugin requires Gradle 4.4" + + " or later. The current version is Gradle 4.3"); } @Test public void succeedWithVersionOfGradleHigherThanRequired() { - this.gradleBuild.gradleVersion("4.0.1").build(); + this.gradleBuild.gradleVersion("4.4.1").build(); } @Test public void succeedWithVersionOfGradleMatchingWhatIsRequired() { - this.gradleBuild.gradleVersion("4.0").build(); + this.gradleBuild.gradleVersion("4.4").build(); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java index f3e6c7a6d8c0..7b4682a3e6e3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java @@ -37,7 +37,6 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask; import org.gradle.api.tasks.bundling.Jar; import org.gradle.testfixtures.ProjectBuilder; -import org.gradle.util.GUtil; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -281,7 +280,7 @@ public void fileTimestampPreservationCanBeDisabled() throws IOException { while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); assertThat(entry.getTime()) - .isEqualTo(GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES); + .isEqualTo(BootZipCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES); } } } From 5bc56671cba2ae3c47a6118d1bb347fdd5fd7a95 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 12 Sep 2018 17:48:25 +0100 Subject: [PATCH 599/701] Upgrade to Jest 6.3.1 Closes gh-14429 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 4d6b4d0ade12..c1efd528346a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -102,7 +102,7 @@ 2.0.6 2.9.0 2.27 - 5.3.4 + 6.3.1 9.4.12.v20180830 2.2.0.v201112011158 8.5.33 From b32887b8eb994f6c3d7e1cb71b759a9d8cb8c0f1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 12 Sep 2018 14:02:42 -0700 Subject: [PATCH 600/701] Add support for logging groups Provide a way for users to quickly group related loggers together for easier configuration. The `loggers.group` property can be used to define a group that can then be configured in the usual `loggers.level.` way. Additionally, provide pre-defined groups for `web` and `sql. Closes gh-14421 --- .../main/asciidoc/spring-boot-features.adoc | 40 ++++++++++ .../logging/LoggingApplicationListener.java | 74 +++++++++++++++---- ...itional-spring-configuration-metadata.json | 6 ++ .../LoggingApplicationListenerTests.java | 32 +++++++- 4 files changed, 136 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 2c3904f86276..1b7a59af5c83 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1731,6 +1731,46 @@ The following example shows potential logging settings in `application.propertie +[[boot-features-custom-log-groups]] +=== Log Groups +It's often useful to be able to group related loggers together so that they can all be +configured at the same time. For example, you might commonly change the logging levels for +_all_ Tomcat related loggers, but you can't easily remember to top level packages. + +To help with this, Spring Boot allows you do define logging groups in your Spring +`Environment`. For example, here's how you could define a "`tomcat`" group by adding +it to your `appplication.properties`: + +[source,properties,indent=0,subs="verbatim,quotes,attributes"] +---- + logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat +---- + +Once defined, you can change the level for all the loggers in the group with a single +line: + +[source,properties,indent=0,subs="verbatim,quotes,attributes"] +---- + logging.level.tomcat=TRACE +---- + +Spring Boot includes the following pre-defined logging groups that can be used +out-of-the-box: + +[cols="1,4"] +|=== +|Name |Loggers + +|web +|`org.springframework.core.codec`, `org.springframework.http`, `org.springframework.web` + +|sql +|`org.springframework.jdbc.core`, `org.hibernate.SQL` + +|=== + + + [[boot-features-custom-log-configuration]] === Custom Log Configuration The various logging systems can be activated by including the appropriate libraries on diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java index 75d9227aae5d..4fb6e429cd0d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java @@ -17,6 +17,7 @@ package org.springframework.boot.context.logging; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -49,6 +50,7 @@ import org.springframework.core.env.Environment; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.util.ObjectUtils; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; @@ -56,7 +58,8 @@ * An {@link ApplicationListener} that configures the {@link LoggingSystem}. If the * environment contains a {@code logging.config} property it will be used to bootstrap the * logging system, otherwise a default configuration is used. Regardless, logging levels - * will be customized if the environment contains {@code logging.level.*} entries. + * will be customized if the environment contains {@code logging.level.*} entries and + * logging groups can be defined with {@code logging.group} . *

    * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when * the environment contains {@code debug} or {@code trace} properties that aren't set to @@ -88,6 +91,9 @@ public class LoggingApplicationListener implements GenericApplicationListener { private static final Bindable> STRING_STRING_MAP = Bindable .mapOf(String.class, String.class); + private static final Bindable> STRING_STRINGS_MAP = Bindable + .mapOf(String.class, String[].class); + /** * The default order for the LoggingApplicationListener. */ @@ -111,19 +117,30 @@ public class LoggingApplicationListener implements GenericApplicationListener { */ public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem"; - private static final MultiValueMap LOG_LEVEL_LOGGERS; + private static final Map> DEFAULT_GROUP_LOGGERS; + static { + MultiValueMap loggers = new LinkedMultiValueMap<>(); + loggers.add("web", "org.springframework.core.codec"); + loggers.add("web", "org.springframework.http"); + loggers.add("web", "org.springframework.web"); + loggers.add("sql", "org.springframework.jdbc.core"); + loggers.add("sql", "org.hibernate.SQL"); + DEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers); + } - private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false); + private static final Map> LOG_LEVEL_LOGGERS; static { - LOG_LEVEL_LOGGERS = new LinkedMultiValueMap<>(); - LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.springframework.boot"); - LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.hibernate.SQL"); - LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.springframework"); - LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.tomcat"); - LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.catalina"); - LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.eclipse.jetty"); - LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl"); + MultiValueMap loggers = new LinkedMultiValueMap<>(); + loggers.add(LogLevel.DEBUG, "sql"); + loggers.add(LogLevel.DEBUG, "web"); + loggers.add(LogLevel.DEBUG, "org.springframework.boot"); + loggers.add(LogLevel.TRACE, "org.springframework"); + loggers.add(LogLevel.TRACE, "org.apache.tomcat"); + loggers.add(LogLevel.TRACE, "org.apache.catalina"); + loggers.add(LogLevel.TRACE, "org.eclipse.jetty"); + loggers.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl"); + LOG_LEVEL_LOGGERS = Collections.unmodifiableMap(loggers); } private static final Class[] EVENT_TYPES = { ApplicationStartingEvent.class, @@ -133,6 +150,8 @@ public class LoggingApplicationListener implements GenericApplicationListener { private static final Class[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class }; + private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false); + private final Log logger = LogFactory.getLog(getClass()); private LoggingSystem loggingSystem; @@ -304,8 +323,32 @@ protected void setLogLevels(LoggingSystem system, Environment environment) { return; } Binder binder = Binder.get(environment); - binder.bind("logging.level", STRING_STRING_MAP).orElseGet(Collections::emptyMap) - .forEach((name, level) -> setLogLevel(system, name, level)); + Map groups = getGroups(binder); + Map levels = binder.bind("logging.level", STRING_STRING_MAP) + .orElseGet(Collections::emptyMap); + levels.forEach((name, level) -> { + String[] groupedNames = groups.get(name); + if (ObjectUtils.isEmpty(groupedNames)) { + setLogLevel(system, name, level); + } + else { + setLogLevel(system, groupedNames, level); + } + }); + } + + private Map getGroups(Binder binder) { + Map groups = new LinkedHashMap<>(); + DEFAULT_GROUP_LOGGERS.forEach( + (name, loggers) -> groups.put(name, StringUtils.toStringArray(loggers))); + binder.bind("logging.group", STRING_STRINGS_MAP.withExistingValue(groups)); + return groups; + } + + private void setLogLevel(LoggingSystem system, String[] names, String level) { + for (String name : names) { + setLogLevel(system, name, level); + } } private void setLogLevel(LoggingSystem system, String name, String level) { @@ -360,8 +403,9 @@ public void setSpringBootLogging(LogLevel springBootLogging) { } /** - * Sets if initialization arguments should be parsed for {@literal --debug} and - * {@literal --trace} options. Defaults to {@code true}. + * Sets if initialization arguments should be parsed for {@literal debug} and + * {@literal trace} properties (usually defined from {@literal --debug} or + * {@literal --trace} command line args. Defaults to {@code true}. * @param parseArgs if arguments should be parsed */ public void setParseArgs(boolean parseArgs) { diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index edd34a3a3ded..ed3127ef84f3 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -93,6 +93,12 @@ "description": "Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`.", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" }, + { + "name": "logging.group", + "type": "java.util.Map", + "description": "Log groups to quickly change multipe loggers at the same time. For instance, `logging.level.db=org.hibernate,org.springframework.jdbc`.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" + }, { "name": "logging.path", "type": "java.lang.String", diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java index 276fd8ac685f..8a7e683655d6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java @@ -92,7 +92,9 @@ public class LoggingApplicationListenerTests { private final LoggingApplicationListener initializer = new LoggingApplicationListener(); - private final Log logger = new SLF4JLogFactory().getInstance(getClass()); + private final SLF4JLogFactory logFactory = new SLF4JLogFactory(); + + private final Log logger = this.logFactory.getInstance(getClass()); private final SpringApplication springApplication = new SpringApplication(); @@ -558,6 +560,34 @@ public void lowPriorityPropertySourceShouldNotOverrideRootLoggerConfig() { assertThat(this.outputCapture.toString()).contains("testatdebug"); } + @Test + public void loggingGroupsDefaultsAreApplied() { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, + "logging.level.web=TRACE"); + this.initializer.initialize(this.context.getEnvironment(), + this.context.getClassLoader()); + assertTraceEnabled("org.springframework.core", false); + assertTraceEnabled("org.springframework.core.codec", true); + assertTraceEnabled("org.springframework.http", true); + assertTraceEnabled("org.springframework.web", true); + } + + @Test + public void loggingGroupsCanBeDefined() { + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, + "logging.group.foo=com.foo.bar,com.foo.baz", "logging.level.foo=TRACE"); + this.initializer.initialize(this.context.getEnvironment(), + this.context.getClassLoader()); + assertTraceEnabled("com.foo", false); + assertTraceEnabled("com.foo.bar", true); + assertTraceEnabled("com.foo.baz", true); + } + + private void assertTraceEnabled(String name, boolean expected) { + assertThat(this.logFactory.getInstance(name).isTraceEnabled()) + .isEqualTo(expected); + } + private void multicastEvent(ApplicationEvent event) { multicastEvent(this.initializer, event); } From bc92becfd8d9007950c29dcd8ff9fe40a75f2673 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 12 Sep 2018 15:50:08 -0700 Subject: [PATCH 601/701] Allow DeferredLogger to replay and switch loggers Add additional `switchTo` methods to allow a `DeferredLogger` to behave like a regular logger once it has been replayed. This commit also improves thread thread safety within the implementation. Closes gh-14452 --- .../config/ConfigFileApplicationListener.java | 2 +- .../boot/logging/DeferredLog.java | 144 ++++++++++++++---- .../boot/logging/DeferredLogTests.java | 11 +- 3 files changed, 122 insertions(+), 35 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 418254f61658..198f41c3a668 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -189,7 +189,7 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, } private void onApplicationPreparedEvent(ApplicationEvent event) { - this.logger.replayTo(ConfigFileApplicationListener.class); + this.logger.switchTo(ConfigFileApplicationListener.class); addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext()); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java index c30e9b674c12..578b8ee4d1c7 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -31,36 +31,50 @@ */ public class DeferredLog implements Log { - private List lines = new ArrayList<>(); + private volatile Log destination; + + private final List lines = new ArrayList<>(); @Override public boolean isTraceEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isTraceEnabled() : true; + } } @Override public boolean isDebugEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isDebugEnabled() : true; + } } @Override public boolean isInfoEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isInfoEnabled() : true; + } } @Override public boolean isWarnEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isWarnEnabled() : true; + } } @Override public boolean isErrorEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isErrorEnabled() : true; + } } @Override public boolean isFatalEnabled() { - return true; + synchronized (this.lines) { + return (this.destination != null) ? this.destination.isFatalEnabled() : true; + } } @Override @@ -124,24 +138,75 @@ public void fatal(Object message, Throwable t) { } private void log(LogLevel level, Object message, Throwable t) { - this.lines.add(new Line(level, message, t)); + synchronized (this.lines) { + if (this.destination != null) { + logTo(this.destination, level, message, t); + } + this.lines.add(new Line(level, message, t)); + } } + /** + * Switch from deferred logging to immediate logging to the specified destination. + * @param destination the new log destination + */ + public void switchTo(Class destination) { + switchTo(LogFactory.getLog(destination)); + } + + /** + * Switch from deferred logging to immediate logging to the specified destination. + * @param destination the new log destination + */ + public void switchTo(Log destination) { + synchronized (this.lines) { + replayTo(destination); + this.destination = destination; + } + } + + /** + * Replay deferred logging to the specified destination. + * @param destination the destination for the deferred log messages + */ public void replayTo(Class destination) { replayTo(LogFactory.getLog(destination)); } + /** + * Replay deferred logging to the specified destination. + * @param destination the destination for the deferred log messages + */ public void replayTo(Log destination) { - for (Line line : this.lines) { - line.replayTo(destination); + synchronized (this.lines) { + for (Line line : this.lines) { + logTo(destination, line.getLevel(), line.getMessage(), + line.getThrowable()); + } + this.lines.clear(); } - this.lines.clear(); } + /** + * Replay from a source log to a destination log when the source is deferred. + * @param source the source logger + * @param destination the destination logger class + * @return the destination + * @deprecated since 2.1.0 in favor of {@link #switchTo(Class)} + */ + @Deprecated public static Log replay(Log source, Class destination) { return replay(source, LogFactory.getLog(destination)); } + /** + * Replay from a source log to a destination log when the source is deferred. + * @param source the source logger + * @param destination the destination logger + * @return the destination + * @deprecated since 2.1.0 in favor of {@link #switchTo(Log)} + */ + @Deprecated public static Log replay(Log source, Log destination) { if (source instanceof DeferredLog) { ((DeferredLog) source).replayTo(destination); @@ -149,6 +214,30 @@ public static Log replay(Log source, Log destination) { return destination; } + private static void logTo(Log log, LogLevel level, Object message, + Throwable throwable) { + switch (level) { + case TRACE: + log.trace(message, throwable); + return; + case DEBUG: + log.debug(message, throwable); + return; + case INFO: + log.info(message, throwable); + return; + case WARN: + log.warn(message, throwable); + return; + case ERROR: + log.error(message, throwable); + return; + case FATAL: + log.fatal(message, throwable); + return; + } + } + private static class Line { private final LogLevel level; @@ -163,27 +252,16 @@ private static class Line { this.throwable = throwable; } - public void replayTo(Log log) { - switch (this.level) { - case TRACE: - log.trace(this.message, this.throwable); - return; - case DEBUG: - log.debug(this.message, this.throwable); - return; - case INFO: - log.info(this.message, this.throwable); - return; - case WARN: - log.warn(this.message, this.throwable); - return; - case ERROR: - log.error(this.message, this.throwable); - return; - case FATAL: - log.fatal(this.message, this.throwable); - return; - } + public LogLevel getLevel() { + return this.level; + } + + public Object getMessage() { + return this.message; + } + + public Throwable getThrowable() { + return this.throwable; } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java index 8d639874c6ab..9b5adfbef444 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -167,4 +167,13 @@ public void clearsOnReplayTo() { verifyZeroInteractions(log2); } + @Test + public void switchTo() { + this.deferredLog.error(this.message, this.throwable); + this.deferredLog.switchTo(this.log); + this.deferredLog.info("Message2"); + verify(this.log).error(this.message, this.throwable); + verify(this.log).info("Message2", null); + } + } From c4caf2705a6c51a2e5b0ee16f0ad3980917a7d7d Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 12 Sep 2018 15:52:47 -0700 Subject: [PATCH 602/701] Defer devtools logging Defer logging from devtools classes until the context is prepared. Closes gh-14453 --- .../devtools/logger/DevToolsLogFactory.java | 70 +++++++++++++++++++ .../boot/devtools/restart/ChangeableUrls.java | 4 +- .../devtools/settings/DevToolsSettings.java | 4 +- .../main/resources/META-INF/spring.factories | 3 +- 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java new file mode 100644 index 000000000000..387160aaf1b7 --- /dev/null +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018-2018 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.devtools.logger; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.logging.DeferredLog; +import org.springframework.context.ApplicationListener; +import org.springframework.data.domain.AbstractPageRequest; + +/** + * Devtools deferred logging support. + * + * @author Phillip Webb + * @since 2.1.0 + */ +public final class DevToolsLogFactory { + + private static final Map> logs = new LinkedHashMap<>(); + + private DevToolsLogFactory() { + } + + /** + * Get a {@link DeferredLog} instance for the specified source that will be + * automatically {@link DeferredLog#switchTo(Class) switched} then the + * {@link AbstractPageRequest context is prepared}. + * @param source the source for logging + * @return a {@link DeferredLog} instance + */ + public static DeferredLog getLog(Class source) { + synchronized (logs) { + DeferredLog log = new DeferredLog(); + logs.put(log, source); + return log; + } + } + + /** + * Listener used to log and switch when the context is ready. + */ + static class Listener implements ApplicationListener { + + @Override + public void onApplicationEvent(ApplicationPreparedEvent event) { + synchronized (logs) { + logs.forEach((log, source) -> log.switchTo(source)); + logs.clear(); + } + } + + } + +} diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java index 5b9f3960e43b..3e91e64aa830 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java @@ -33,8 +33,8 @@ import java.util.stream.Stream; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.springframework.boot.devtools.logger.DevToolsLogFactory; import org.springframework.boot.devtools.settings.DevToolsSettings; import org.springframework.util.StringUtils; @@ -46,7 +46,7 @@ */ final class ChangeableUrls implements Iterable { - private static final Log logger = LogFactory.getLog(ChangeableUrls.class); + private static final Log logger = DevToolsLogFactory.getLog(ChangeableUrls.class); private final List urls; diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/DevToolsSettings.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/DevToolsSettings.java index e21cacfa16f6..ea0ab9f1a9f9 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/DevToolsSettings.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/DevToolsSettings.java @@ -25,8 +25,8 @@ import java.util.regex.Pattern; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.springframework.boot.devtools.logger.DevToolsLogFactory; import org.springframework.core.io.UrlResource; import org.springframework.core.io.support.PropertiesLoaderUtils; @@ -43,7 +43,7 @@ public class DevToolsSettings { */ public static final String SETTINGS_RESOURCE_LOCATION = "META-INF/spring-devtools.properties"; - private static final Log logger = LogFactory.getLog(DevToolsSettings.class); + private static final Log logger = DevToolsLogFactory.getLog(DevToolsSettings.class); private static DevToolsSettings settings; diff --git a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/spring.factories index 232bf112d77d..958c3dfa63c7 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/spring.factories @@ -4,7 +4,8 @@ org.springframework.boot.devtools.restart.RestartScopeInitializer # Application Listeners org.springframework.context.ApplicationListener=\ -org.springframework.boot.devtools.restart.RestartApplicationListener +org.springframework.boot.devtools.restart.RestartApplicationListener,\ +org.springframework.boot.devtools.logger.DevToolsLogFactory.Listener # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ From cef635d86c854b0b767f929f110d974864dd09a1 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 12 Sep 2018 15:57:19 -0700 Subject: [PATCH 603/701] Reinstate devtools debug logging with opt-out Reinstate `web` logging when devtools is in use, making use of the new logging groups support. Devtools now also logs an `INFO` message informing that properties defaults are offers an easy way to disable them. Closes gh-14450 --- ...DevToolsPropertyDefaultsPostProcessor.java | 52 ++++++++++++------- ...itional-spring-configuration-metadata.json | 8 ++- .../src/main/asciidoc/using-spring-boot.adoc | 10 ++++ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index d5e181b33fa4..df075273af29 100755 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -20,7 +20,10 @@ import java.util.HashMap; import java.util.Map; +import org.apache.commons.logging.Log; + import org.springframework.boot.SpringApplication; +import org.springframework.boot.devtools.logger.DevToolsLogFactory; import org.springframework.boot.devtools.restart.Restarter; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.Ordered; @@ -28,7 +31,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; /** * {@link EnvironmentPostProcessor} to add properties that make sense when working at @@ -42,33 +44,40 @@ @Order(Ordered.LOWEST_PRECEDENCE) public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor { + private static final Log logger = DevToolsLogFactory + .getLog(DevToolsPropertyDefaultsPostProcessor.class); + + private static final String ENABLED = "spring.devtools.add-properties"; + private static final Map PROPERTIES; static { - Map devToolsProperties = new HashMap<>(); - devToolsProperties.put("spring.thymeleaf.cache", "false"); - devToolsProperties.put("spring.freemarker.cache", "false"); - devToolsProperties.put("spring.groovy.template.cache", "false"); - devToolsProperties.put("spring.mustache.cache", "false"); - devToolsProperties.put("server.servlet.session.persistent", "true"); - devToolsProperties.put("spring.h2.console.enabled", "true"); - devToolsProperties.put("spring.resources.cache.period", "0"); - devToolsProperties.put("spring.resources.chain.cache", "false"); - devToolsProperties.put("spring.template.provider.cache", "false"); - devToolsProperties.put("spring.mvc.log-resolved-exception", "true"); - devToolsProperties.put("server.error.include-stacktrace", "ALWAYS"); - devToolsProperties.put("server.servlet.jsp.init-parameters.development", "true"); - devToolsProperties.put("spring.reactor.stacktrace-mode.enabled", "true"); - PROPERTIES = Collections.unmodifiableMap(devToolsProperties); + Map properties = new HashMap<>(); + properties.put("spring.thymeleaf.cache", "false"); + properties.put("spring.freemarker.cache", "false"); + properties.put("spring.groovy.template.cache", "false"); + properties.put("spring.mustache.cache", "false"); + properties.put("server.servlet.session.persistent", "true"); + properties.put("spring.h2.console.enabled", "true"); + properties.put("spring.resources.cache.period", "0"); + properties.put("spring.resources.chain.cache", "false"); + properties.put("spring.template.provider.cache", "false"); + properties.put("spring.mvc.log-resolved-exception", "true"); + properties.put("server.error.include-stacktrace", "ALWAYS"); + properties.put("server.servlet.jsp.init-parameters.development", "true"); + properties.put("spring.reactor.stacktrace-mode.enabled", "true"); + properties.put("logging.level.web", "debug"); + PROPERTIES = Collections.unmodifiableMap(properties); } @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { if (isLocalApplication(environment) && canAddProperties(environment)) { - PropertySource propertySource = new MapPropertySource("refresh", - PROPERTIES); - environment.getPropertySources().addLast(propertySource); + logger.info("Devtools property and logging defaults active! Set '" + ENABLED + + "' to 'false' to disable"); + environment.getPropertySources() + .addLast(new MapPropertySource("devtools", PROPERTIES)); } } @@ -77,7 +86,10 @@ private boolean isLocalApplication(ConfigurableEnvironment environment) { } private boolean canAddProperties(Environment environment) { - return isRestarterInitialized() || isRemoteRestartEnabled(environment); + if (environment.getProperty(ENABLED, Boolean.class, true)) { + return isRestarterInitialized() || isRemoteRestartEnabled(environment); + } + return false; } private boolean isRestarterInitialized() { diff --git a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json index d68cdbc0e1ef..081c720427f6 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -19,6 +19,12 @@ "reason": "Remote debug is no longer supported.", "level": "error" } + }, + { + "name": "spring.devtools.add-properties", + "type": "java.lang.Boolean", + "description": "Whether to enable devtool property defaults.", + "defaultValue": true } ] -} \ No newline at end of file +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 42a1c3e12042..1d3c87902332 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -783,6 +783,16 @@ For example, Thymeleaf offers the `spring.thymeleaf.cache` property. Rather than to set these properties manually, the `spring-boot-devtools` module automatically applies sensible development-time configuration. +Because you need more information about web requests while developing Spring MVC and +Spring WebFlux applications, developer tools will enable `DEBUG` logging for the `web` +logging group. This will give you information about the incoming request, which handler is +processing it, the response outcome, etc. If you wish to log all request details +(including potentially sensitive information), you can turn on the +`spring.http.log-request-details` configuration property. + +NOTE: If you don't want property defaults to be applied you can set +`spring.devtools.add-properties` to `false` in your `application.properties`. + TIP: For a complete list of the properties that are applied by the devtools, see {sc-spring-boot-devtools}/env/DevToolsPropertyDefaultsPostProcessor.{sc-ext}[DevToolsPropertyDefaultsPostProcessor]. From d4b11c8fa63e5b409b970d0a1addf796dc390e42 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 12 Sep 2018 18:31:50 -0700 Subject: [PATCH 604/701] Attempt to fix test failures on Java 9+ See gh-14453 --- .../devtools/logger/DevToolsLogFactory.java | 20 ++++++++++++------- .../boot/logging/DeferredLog.java | 4 ---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java index 387160aaf1b7..9454570ac74a 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java @@ -19,6 +19,8 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.apache.commons.logging.Log; + import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.logging.DeferredLog; import org.springframework.context.ApplicationListener; @@ -32,21 +34,21 @@ */ public final class DevToolsLogFactory { - private static final Map> logs = new LinkedHashMap<>(); + private static final Map> logs = new LinkedHashMap<>(); private DevToolsLogFactory() { } /** - * Get a {@link DeferredLog} instance for the specified source that will be - * automatically {@link DeferredLog#switchTo(Class) switched} then the - * {@link AbstractPageRequest context is prepared}. + * Get a {@link Log} instance for the specified source that will be automatically + * {@link DeferredLog#switchTo(Class) switched} then the {@link AbstractPageRequest + * context is prepared}. * @param source the source for logging * @return a {@link DeferredLog} instance */ - public static DeferredLog getLog(Class source) { + public static Log getLog(Class source) { synchronized (logs) { - DeferredLog log = new DeferredLog(); + Log log = new DeferredLog(); logs.put(log, source); return log; } @@ -60,7 +62,11 @@ static class Listener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationPreparedEvent event) { synchronized (logs) { - logs.forEach((log, source) -> log.switchTo(source)); + logs.forEach((log, source) -> { + if (log instanceof DeferredLog) { + ((DeferredLog) log).switchTo(source); + } + }); logs.clear(); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java index 578b8ee4d1c7..2d86075b7128 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java @@ -192,9 +192,7 @@ public void replayTo(Log destination) { * @param source the source logger * @param destination the destination logger class * @return the destination - * @deprecated since 2.1.0 in favor of {@link #switchTo(Class)} */ - @Deprecated public static Log replay(Log source, Class destination) { return replay(source, LogFactory.getLog(destination)); } @@ -204,9 +202,7 @@ public static Log replay(Log source, Class destination) { * @param source the source logger * @param destination the destination logger * @return the destination - * @deprecated since 2.1.0 in favor of {@link #switchTo(Log)} */ - @Deprecated public static Log replay(Log source, Log destination) { if (source instanceof DeferredLog) { ((DeferredLog) source).replayTo(destination); From 1113c356dc0c2e47f317a46bdddff3747b53a800 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 13 Sep 2018 12:07:45 -0700 Subject: [PATCH 605/701] ReactiveOAuth2ClientAutoConfiguration backs off for servlet env Fixes gh-14463 --- .../ReactiveOAuth2ClientAutoConfiguration.java | 16 ++++++++++++++++ ...activeOAuth2ClientAutoConfigurationTests.java | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java index 15b94bf56ed4..05e3ab8aaec4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java @@ -25,6 +25,8 @@ 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.NoneNestedConditions; import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; @@ -52,6 +54,7 @@ @Configuration @AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) @EnableConfigurationProperties(OAuth2ClientProperties.class) +@Conditional(ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.class) @ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ClientRegistration.class }) public class ReactiveOAuth2ClientAutoConfiguration { @@ -89,4 +92,17 @@ public ServerOAuth2AuthorizedClientRepository authorizedClientRepository( authorizedClientService); } + static class NonServletApplicationCondition extends NoneNestedConditions { + + NonServletApplicationCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) + static class ServletApplicationCondition { + + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java index 5275807c27ec..acc2708aedb5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -53,6 +54,15 @@ public class ReactiveOAuth2ClientAutoConfigurationTests { private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration.login"; + @Test + public void autoConfigurationShouldBackOffForServletEnvironments() { + WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(ReactiveOAuth2ClientAutoConfiguration.class)); + contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class)); + } + @Test public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { this.contextRunner.run((context) -> assertThat(context) From d5a197fe66285a9e357125f14febbb3514b97d7c Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Fri, 7 Sep 2018 10:31:49 -0700 Subject: [PATCH 606/701] Support random actuator port in SpringBootTest This commit changes @SpringBootTest(randomPort = true) to generate a random port for the actuator endpoints if the management server runs on a different port from the main server. Closes gh-4424 --- .../main/asciidoc/spring-boot-features.adoc | 4 + ...estRandomPortEnvironmentPostProcessor.java | 77 +++++++++ .../main/resources/META-INF/spring.factories | 4 + ...ndomPortEnvironmentPostProcessorTests.java | 149 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java create mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1b7a59af5c83..bec852c2efb7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6491,6 +6491,10 @@ test method by default. However, as using this arrangement with either `RANDOM_P run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case. +NOTE: `@SpringBootTest` with `webEnvironment = WebEnvironment.RANDOM_PORT` will also +start the management server on a separate random port if your application uses a different +port for the management server. + [[boot-features-testing-spring-boot-applications-detecting-web-app-type]] diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java new file mode 100644 index 000000000000..ce9f6ab91afd --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2018 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.test.web; + +import java.util.Objects; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.test.context.support.TestPropertySourceUtils; + +/** + * {@link EnvironmentPostProcessor} implementation to start the management context on a + * random port if the main server's port is 0 and the management context is expected on a + * different port. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +public class SpringBootTestRandomPortEnvironmentPostProcessor + implements EnvironmentPostProcessor { + + private static final String MANAGEMENT_PORT_PROPERTY = "management.server.port"; + + private static final String SERVER_PORT_PROPERTY = "server.port"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, + SpringApplication application) { + MapPropertySource source = (MapPropertySource) environment.getPropertySources() + .get(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME); + if (isTestServerPortRandom(source)) { + if (source.getProperty(MANAGEMENT_PORT_PROPERTY) == null) { + String managementPort = getPort(environment, MANAGEMENT_PORT_PROPERTY, + null); + String serverPort = getPort(environment, SERVER_PORT_PROPERTY, "8080"); + if (managementPort != null && !managementPort.equals("-1")) { + if (!managementPort.equals(serverPort)) { + source.getSource().put(MANAGEMENT_PORT_PROPERTY, "0"); + } + else { + source.getSource().put(MANAGEMENT_PORT_PROPERTY, ""); + } + } + } + } + + } + + private boolean isTestServerPortRandom(MapPropertySource source) { + return (source != null && "0".equals(source.getProperty(SERVER_PORT_PROPERTY))); + } + + private String getPort(ConfigurableEnvironment environment, String property, + String defaultValue) { + return environment.getPropertySources().stream() + .filter((source) -> !source.getName().equals( + TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME)) + .map((source) -> (String) source.getProperty(property)) + .filter(Objects::nonNull).findFirst().orElse(defaultValue); + } + +} diff --git a/spring-boot-project/spring-boot-test/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test/src/main/resources/META-INF/spring.factories index dace6b7b70af..5a75a417aa1c 100644 --- a/spring-boot-project/spring-boot-test/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test/src/main/resources/META-INF/spring.factories @@ -11,3 +11,7 @@ org.springframework.boot.test.web.reactive.server.WebTestClientContextCustomizer org.springframework.test.context.TestExecutionListener=\ org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener,\ org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener + +# Environment Post Processors +org.springframework.boot.env.EnvironmentPostProcessor=\ +org.springframework.boot.test.web.SpringBootTestRandomPortEnvironmentPostProcessor diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java new file mode 100644 index 000000000000..f439f53993a5 --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2012-2018 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.test.web; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.test.context.support.TestPropertySourceUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SpringBootTestRandomPortEnvironmentPostProcessor}. + * + * @author Madhura Bhave + */ +public class SpringBootTestRandomPortEnvironmentPostProcessorTests { + + private SpringBootTestRandomPortEnvironmentPostProcessor postProcessor = new SpringBootTestRandomPortEnvironmentPostProcessor(); + + private MockEnvironment environment; + + private MutablePropertySources propertySources; + + @Before + public void setup() { + this.environment = new MockEnvironment(); + this.propertySources = this.environment.getPropertySources(); + } + + @Test + public void postProcessWhenServerAndManagementPortIsZeroInTestPropertySource() { + addTestPropertySource("0", "0"); + this.environment.setProperty("management.server.port", "0"); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")).isEqualTo("0"); + } + + @Test + public void postProcessWhenTestServerAndTestManagementPortAreNonZero() { + addTestPropertySource("8080", "8081"); + this.environment.setProperty("server.port", "8080"); + this.environment.setProperty("management.server.port", "8081"); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("8080"); + assertThat(this.environment.getProperty("management.server.port")) + .isEqualTo("8081"); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndTestManagementPortIsNotNull() { + addTestPropertySource("0", "8080"); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")) + .isEqualTo("8080"); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNull() { + addTestPropertySource("0", null); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")) + .isEqualTo(null); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndSameInProduction() { + addTestPropertySource("0", null); + Map other = new HashMap<>(); + other.put("server.port", "8081"); + other.put("management.server.port", "8081"); + MapPropertySource otherSource = new MapPropertySource("other", other); + this.propertySources.addLast(otherSource); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")).isEqualTo(""); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDefaultSameInProduction() { + // mgmt port is 8080 which means its on the same port as main server since that is + // null in app properties + addTestPropertySource("0", null); + Map other = new HashMap<>(); + other.put("management.server.port", "8080"); + MapPropertySource otherSource = new MapPropertySource("other", other); + this.propertySources.addLast(otherSource); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")).isEqualTo(""); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDifferentInProduction() { + addTestPropertySource("0", null); + Map other = new HashMap<>(); + other.put("management.server.port", "8081"); + MapPropertySource otherSource = new MapPropertySource("other", other); + this.propertySources.addLast(otherSource); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")).isEqualTo("0"); + } + + @Test + public void postProcessWhenTestServerPortIsZeroAndManagementPortMinusOne() { + addTestPropertySource("0", null); + Map other = new HashMap<>(); + other.put("management.server.port", "-1"); + MapPropertySource otherSource = new MapPropertySource("other", other); + this.propertySources.addLast(otherSource); + this.postProcessor.postProcessEnvironment(this.environment, null); + assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); + assertThat(this.environment.getProperty("management.server.port")) + .isEqualTo("-1"); + } + + private void addTestPropertySource(String serverPort, String managementPort) { + Map source = new HashMap<>(); + source.put("server.port", serverPort); + source.put("management.server.port", managementPort); + MapPropertySource inlineTestSource = new MapPropertySource( + TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME, source); + this.propertySources.addFirst(inlineTestSource); + } + +} From 0f653e69cd559b225134d785be46130686daa76a Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 15 Sep 2018 16:58:59 -0700 Subject: [PATCH 607/701] Start building against Spring Framework SNAPSHOTs See gh-14481 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index c1efd528346a..2c79c6fac890 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 1.23 7.4.0 - 5.1.0.RC3 + 5.1.0.BUILD-SNAPSHOT 2.1.0.M3 4.1.0.M3 2.0.3.RELEASE From 5cc1a830b2bee8e01c02bb5758664663aea8ec59 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 15 Sep 2018 16:54:22 -0700 Subject: [PATCH 608/701] Fixup abstract configuration following SPR-16839 Spring Framework now requires that all nested configuration classes are contained within a `@Component` class (see SPR-16839). This means that our abstract `JpaBaseConfiguration` class should have a `@Configuration` annotation. Closes gh-14480 --- .../boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index 276f8620117b..d7dd669813ba 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -70,6 +70,7 @@ * @author Kazuki Shimizu * @author Eddú Meléndez */ +@Configuration @EnableConfigurationProperties(JpaProperties.class) @Import(DataSourceInitializedPublisher.Registrar.class) public abstract class JpaBaseConfiguration implements BeanFactoryAware { From 99908fdfe7254d96e78d3cfda86cb85d2f0ef6b2 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 15 Sep 2018 16:59:37 -0700 Subject: [PATCH 609/701] Polish --- .../boot/cli/compiler/grape/AetherGrapeEngineFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java index 946e5cd1d29a..7db4ac1aec5c 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineFactory.java @@ -79,7 +79,6 @@ private static List createRepositories( RemoteRepository.Builder builder = new RemoteRepository.Builder( repositoryConfiguration.getName(), "default", repositoryConfiguration.getUri().toASCIIString()); - if (!repositoryConfiguration.getSnapshotsEnabled()) { builder.setSnapshotPolicy( new RepositoryPolicy(false, RepositoryPolicy.UPDATE_POLICY_NEVER, From d127d071fda1ff14ba42f50238ec2c06e32127cd Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 15 Sep 2018 17:03:14 -0700 Subject: [PATCH 610/701] Ensure classpath resource are also filtered Update `ExtendedGroovyClassLoader` to also filter resources. Closes gh-14482 --- .../boot/cli/compiler/ExtendedGroovyClassLoader.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/ExtendedGroovyClassLoader.java b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/ExtendedGroovyClassLoader.java index 3538dba54ba0..b2be173585f3 100644 --- a/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/ExtendedGroovyClassLoader.java +++ b/spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/ExtendedGroovyClassLoader.java @@ -18,6 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; @@ -25,6 +26,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -230,6 +232,11 @@ private boolean isGroovyJar(String entry) { return false; } + @Override + public Enumeration getResources(String name) throws IOException { + return this.groovyOnlyClassLoader.getResources(name); + } + @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { From b4c6cef526c4ed1d1488c61b94a0a613a508b94e Mon Sep 17 00:00:00 2001 From: artsiom Date: Fri, 14 Sep 2018 23:14:48 +0300 Subject: [PATCH 611/701] Publish ApplicationContextInitializedEvent on contextPrepared See gh-14478 --- .../ApplicationContextInitializedEvent.java | 55 +++++++++++++++++++ .../event/EventPublishingRunListener.java | 4 +- .../boot/SpringApplicationTests.java | 6 ++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java new file mode 100644 index 000000000000..82bdcfbe2221 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2018 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.context.event; + +import org.springframework.boot.SpringApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Event published when a {@link SpringApplication} is starting up and the + * {@link ApplicationContext} is prepared and ApplicationContextInitializers have been + * called but before any bean definitions are loaded. + * + * @author Artsiom Yudovin + */ +@SuppressWarnings("serial") +public class ApplicationContextInitializedEvent extends SpringApplicationEvent { + + private final ConfigurableApplicationContext context; + + /** + * Create a new {@link ApplicationContextInitializedEvent} instance. + * @param application the current application + * @param args the arguments the application is running with + * @param context the context that was being created (maybe null) + */ + public ApplicationContextInitializedEvent(SpringApplication application, + String[] args, ConfigurableApplicationContext context) { + super(application, args); + this.context = context; + } + + /** + * Return the application context. + * @return the context + */ + public ConfigurableApplicationContext getContext() { + return this.context; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java index 6468222163d6..902495b4ef31 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java @@ -40,6 +40,7 @@ * @author Phillip Webb * @author Stephane Nicoll * @author Andy Wilkinson + * @author Artsiom Yudovin */ public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { @@ -77,7 +78,8 @@ public void environmentPrepared(ConfigurableEnvironment environment) { @Override public void contextPrepared(ConfigurableApplicationContext context) { - + this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent( + this.application, this.args, context)); } @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 8fd562e5f940..b249eed191b4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -49,6 +49,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator; +import org.springframework.boot.context.event.ApplicationContextInitializedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; @@ -125,6 +126,7 @@ * @author Craig Burke * @author Madhura Bhave * @author Brian Clozel + * @author Artsiom Yudovin */ public class SpringApplicationTests { @@ -383,6 +385,8 @@ public void eventsArePublishedInExpectedOrder() { inOrder.verify(listener).onApplicationEvent(isA(ApplicationStartingEvent.class)); inOrder.verify(listener) .onApplicationEvent(isA(ApplicationEnvironmentPreparedEvent.class)); + inOrder.verify(listener) + .onApplicationEvent(isA(ApplicationContextInitializedEvent.class)); inOrder.verify(listener).onApplicationEvent(isA(ApplicationPreparedEvent.class)); inOrder.verify(listener).onApplicationEvent(isA(ContextRefreshedEvent.class)); inOrder.verify(listener).onApplicationEvent(isA(ApplicationStartedEvent.class)); @@ -1000,6 +1004,7 @@ public void applicationListenerFromApplicationIsCalledWhenContextFailsRefreshBef catch (ApplicationContextException ex) { verifyListenerEvents(listener, ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, + ApplicationContextInitializedEvent.class, ApplicationPreparedEvent.class, ApplicationFailedEvent.class); } } @@ -1019,6 +1024,7 @@ public void applicationListenerFromApplicationIsCalledWhenContextFailsRefreshAft catch (BeanCreationException ex) { verifyListenerEvents(listener, ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, + ApplicationContextInitializedEvent.class, ApplicationPreparedEvent.class, ApplicationFailedEvent.class); } } From 5e0e9416325cbe6251db76d2bcc2249c94eaf9b5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 17 Sep 2018 10:50:28 +0100 Subject: [PATCH 612/701] Polish "Publish ApplicationContextInitializedEvent on contextPrepared" Closes gh-14478 --- .../context/event/ApplicationContextInitializedEvent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java index 82bdcfbe2221..dd88bbfb055e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java @@ -36,7 +36,7 @@ public class ApplicationContextInitializedEvent extends SpringApplicationEvent { * Create a new {@link ApplicationContextInitializedEvent} instance. * @param application the current application * @param args the arguments the application is running with - * @param context the context that was being created (maybe null) + * @param context the context that has been initialized */ public ApplicationContextInitializedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context) { @@ -48,7 +48,7 @@ public ApplicationContextInitializedEvent(SpringApplication application, * Return the application context. * @return the context */ - public ConfigurableApplicationContext getContext() { + public ConfigurableApplicationContext getApplicationContext() { return this.context; } From 7aaeefbc0e00eff0df0082d2ff21ba56c5c5ebad Mon Sep 17 00:00:00 2001 From: durigon Date: Sun, 16 Sep 2018 11:42:49 +0900 Subject: [PATCH 613/701] Use Matcher from pre-compiled Pattern rather than String for replaceAll Closes gh-14483 --- .../endpoint/web/WebOperationRequestPredicate.java | 5 ++++- .../metrics/web/client/RestTemplateExchangeTags.java | 5 ++++- .../boot/actuate/metrics/web/servlet/WebMvcTags.java | 9 ++++++++- .../boot/configurationprocessor/TypeUtils.java | 5 ++++- .../tasks/bundling/LaunchScriptConfiguration.java | 11 +++++++++-- .../boot/gradle/testkit/GradleBuild.java | 6 +++++- .../org/springframework/boot/maven/RepackageMojo.java | 6 +++++- .../boot/devtools/tests/JvmLauncher.java | 7 +++++-- 8 files changed, 44 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicate.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicate.java index f571c08df4d3..b45993d6d763 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicate.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicate.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.regex.Pattern; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -30,6 +31,8 @@ */ public final class WebOperationRequestPredicate { + private static final Pattern PATH_VAR_PATTERN = Pattern.compile("\\{.*?}"); + private final String path; private final String canonicalPath; @@ -50,7 +53,7 @@ public final class WebOperationRequestPredicate { public WebOperationRequestPredicate(String path, WebEndpointHttpMethod httpMethod, Collection consumes, Collection produces) { this.path = path; - this.canonicalPath = path.replaceAll("\\{.*?}", "{*}"); + this.canonicalPath = PATH_VAR_PATTERN.matcher(path).replaceAll("{*}"); this.httpMethod = httpMethod; this.consumes = consumes; this.produces = produces; diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/RestTemplateExchangeTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/RestTemplateExchangeTags.java index 9725c60c4f1d..2dd9bc8a81c8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/RestTemplateExchangeTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/client/RestTemplateExchangeTags.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.URI; +import java.util.regex.Pattern; import io.micrometer.core.instrument.Tag; @@ -36,6 +37,8 @@ */ public final class RestTemplateExchangeTags { + private static final Pattern STRIP_URI_PATTERN = Pattern.compile("^https?://[^/]+/"); + private RestTemplateExchangeTags() { } @@ -69,7 +72,7 @@ public static Tag uri(String uriTemplate) { } private static String stripUri(String uri) { - return uri.replaceAll("^https?://[^/]+/", ""); + return STRIP_URI_PATTERN.matcher(uri).replaceAll(""); } private static String ensureLeadingSlash(String url) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java index 74249012d29a..0d50564316f9 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java @@ -16,6 +16,8 @@ package org.springframework.boot.actuate.metrics.web.servlet; +import java.util.regex.Pattern; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,6 +52,10 @@ public final class WebMvcTags { private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN"); + private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$"); + + private static final Pattern MULTIPLE_SLASH_PATTERN = Pattern.compile("//+"); + private WebMvcTags() { } @@ -124,7 +130,8 @@ private static String getMatchingPattern(HttpServletRequest request) { private static String getPathInfo(HttpServletRequest request) { String pathInfo = request.getPathInfo(); String uri = StringUtils.hasText(pathInfo) ? pathInfo : "/"; - return uri.replaceAll("//+", "/").replaceAll("/$", ""); + uri = MULTIPLE_SLASH_PATTERN.matcher(uri).replaceAll("/"); + return TRAILING_SLASH_PATTERN.matcher(uri).replaceAll(""); } /** diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java index 58575654250c..0b248964b914 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java @@ -22,6 +22,7 @@ import java.util.EnumMap; import java.util.HashMap; import java.util.Map; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.processing.ProcessingEnvironment; @@ -61,6 +62,8 @@ class TypeUtils { private static final Map WRAPPER_TO_PRIMITIVE; + private static final Pattern NEW_LINE_PATTERN = Pattern.compile("[\r\n]+"); + static { Map primitives = new HashMap<>(); PRIMITIVE_WRAPPERS.forEach( @@ -131,7 +134,7 @@ public String getJavaDoc(Element element) { String javadoc = (element != null) ? this.env.getElementUtils().getDocComment(element) : null; if (javadoc != null) { - javadoc = javadoc.replaceAll("[\r\n]+", "").trim(); + javadoc = NEW_LINE_PATTERN.matcher(javadoc).replaceAll("").trim(); } return "".equals(javadoc) ? null : javadoc; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java index 4d908d1a46be..596057add858 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java @@ -21,6 +21,7 @@ import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.regex.Pattern; import org.gradle.api.Project; import org.gradle.api.tasks.bundling.AbstractArchiveTask; @@ -36,6 +37,10 @@ @SuppressWarnings("serial") public class LaunchScriptConfiguration implements Serializable { + private static final Pattern WHITE_SPACE_PATTERN = Pattern.compile("\\s+"); + + private static final Pattern LINE_FEED_PATTERN = Pattern.compile("\n"); + private final Map properties = new HashMap<>(); private File script; @@ -134,11 +139,13 @@ public int hashCode() { } private String removeLineBreaks(String string) { - return (string != null) ? string.replaceAll("\\s+", " ") : null; + return (string != null) ? WHITE_SPACE_PATTERN.matcher(string).replaceAll(" ") + : null; } private String augmentLineBreaks(String string) { - return (string != null) ? string.replaceAll("\n", "\n# ") : null; + return (string != null) ? LINE_FEED_PATTERN.matcher(string).replaceAll("\n# ") + : null; } private void putIfMissing(Map properties, String key, diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java index d5e4514ef2ed..3f63c69302b7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; @@ -50,6 +51,9 @@ */ public class GradleBuild implements TestRule { + private static final Pattern GRADLE_VERSION_PATTERN = Pattern + .compile("\\[Gradle .+\\]"); + private final TemporaryFolder temp = new TemporaryFolder(); private File projectDir; @@ -95,7 +99,7 @@ private URL getScriptForTestMethod(Description description) { } private String removeGradleVersion(String methodName) { - return methodName.replaceAll("\\[Gradle .+\\]", "").trim(); + return GRADLE_VERSION_PATTERN.matcher(methodName).replaceAll("").trim(); } private URL getScriptForTestClass(Class testClass) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 8444b1a36f0c..dd3d51679500 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.regex.Pattern; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Dependency; @@ -62,6 +63,8 @@ @Mojo(name = "repackage", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME) public class RepackageMojo extends AbstractDependencyFilterMojo { + private static final Pattern WHITE_SPACE_PATTERN = Pattern.compile("\\s+"); + /** * The Maven project. * @since 1.0 @@ -312,7 +315,8 @@ private Properties buildLaunchScriptProperties() { } private String removeLineBreaks(String description) { - return (description != null) ? description.replaceAll("\\s+", " ") : null; + return (description != null) + ? WHITE_SPACE_PATTERN.matcher(description).replaceAll(" ") : null; } private void putIfMissing(Properties properties, String key, diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-devtools-tests/src/test/java/org/springframework/boot/devtools/tests/JvmLauncher.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-devtools-tests/src/test/java/org/springframework/boot/devtools/tests/JvmLauncher.java index ef7f6c30c251..35e00b7d2cf9 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-devtools-tests/src/test/java/org/springframework/boot/devtools/tests/JvmLauncher.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-devtools-tests/src/test/java/org/springframework/boot/devtools/tests/JvmLauncher.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -36,12 +37,14 @@ */ class JvmLauncher implements TestRule { + private static final Pattern NON_ALPHABET_PATTERN = Pattern.compile("[^A-Za-z]+"); + private File outputDirectory; @Override public Statement apply(Statement base, Description description) { - this.outputDirectory = new File("target/output/" - + description.getMethodName().replaceAll("[^A-Za-z]+", "")); + this.outputDirectory = new File("target/output/" + NON_ALPHABET_PATTERN + .matcher(description.getMethodName()).replaceAll("")); this.outputDirectory.mkdirs(); return base; } From 620419f9e43c23acd9037f74553c70cfe8764514 Mon Sep 17 00:00:00 2001 From: davinkevin Date: Fri, 14 Sep 2018 14:08:13 +0200 Subject: [PATCH 614/701] Use ExecutorProvider bean if available when auto-configuring jOOQ See gh-14471 --- .../autoconfigure/jooq/JooqAutoConfiguration.java | 11 +++++++++-- .../jooq/JooqAutoConfigurationTests.java | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java index 5a0507ca0524..cf63b5ade20a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java @@ -21,6 +21,7 @@ import org.jooq.ConnectionProvider; import org.jooq.DSLContext; import org.jooq.ExecuteListenerProvider; +import org.jooq.ExecutorProvider; import org.jooq.RecordListenerProvider; import org.jooq.RecordMapperProvider; import org.jooq.RecordUnmapperProvider; @@ -32,7 +33,6 @@ import org.jooq.impl.DefaultConfiguration; import org.jooq.impl.DefaultDSLContext; import org.jooq.impl.DefaultExecuteListenerProvider; - import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -109,6 +109,8 @@ public static class DslContextConfiguration { private final TransactionListenerProvider[] transactionListenerProviders; + private final ExecutorProvider executorProvider; + public DslContextConfiguration(JooqProperties properties, ConnectionProvider connectionProvider, DataSource dataSource, ObjectProvider transactionProvider, @@ -118,7 +120,8 @@ public DslContextConfiguration(JooqProperties properties, ObjectProvider recordListenerProviders, ExecuteListenerProvider[] executeListenerProviders, ObjectProvider visitListenerProviders, - ObjectProvider transactionListenerProviders) { + ObjectProvider transactionListenerProviders, + ObjectProvider executorProvider) { this.properties = properties; this.connection = connectionProvider; this.dataSource = dataSource; @@ -131,6 +134,7 @@ public DslContextConfiguration(JooqProperties properties, this.visitListenerProviders = visitListenerProviders.getIfAvailable(); this.transactionListenerProviders = transactionListenerProviders .getIfAvailable(); + this.executorProvider = executorProvider.getIfAvailable(); } @Bean @@ -156,6 +160,9 @@ public DefaultConfiguration jooqConfiguration() { if (this.settings != null) { configuration.set(this.settings); } + if (this.executorProvider != null) { + configuration.set(this.executorProvider); + } configuration.set(this.recordListenerProviders); configuration.set(this.executeListenerProviders); configuration.set(this.visitListenerProviders); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java index e968651d36cb..ff4cd0ecef52 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java @@ -17,10 +17,12 @@ package org.springframework.boot.autoconfigure.jooq; import javax.sql.DataSource; +import java.util.concurrent.Executor; import org.jooq.DSLContext; import org.jooq.ExecuteListener; import org.jooq.ExecuteListenerProvider; +import org.jooq.ExecutorProvider; import org.jooq.Record; import org.jooq.RecordListener; import org.jooq.RecordListenerProvider; @@ -141,12 +143,14 @@ public void customProvidersArePickedUp() { TxManagerConfiguration.class, TestRecordMapperProvider.class, TestRecordUnmapperProvider.class, TestRecordListenerProvider.class, TestExecuteListenerProvider.class, TestVisitListenerProvider.class, - TestTransactionListenerProvider.class).run((context) -> { + TestTransactionListenerProvider.class, TestExecutorProvider.class).run((context) -> { DSLContext dsl = context.getBean(DSLContext.class); assertThat(dsl.configuration().recordMapperProvider().getClass()) .isEqualTo(TestRecordMapperProvider.class); assertThat(dsl.configuration().recordUnmapperProvider().getClass()) .isEqualTo(TestRecordUnmapperProvider.class); + assertThat(dsl.configuration().executorProvider().getClass()) + .isEqualTo(TestExecutorProvider.class); assertThat(dsl.configuration().recordListenerProviders().length) .isEqualTo(1); assertThat(dsl.configuration().executeListenerProviders().length) @@ -288,4 +292,13 @@ public TransactionListener provide() { } + protected static class TestExecutorProvider implements ExecutorProvider { + + @Override + public Executor provide() { + return null; + } + + } + } From a1d1a7392fae31ad6cf6b408274e5c3f9decb6ad Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 17 Sep 2018 11:14:08 +0100 Subject: [PATCH 615/701] Polish "Use ExecutorProvider bean if available when auto-configuring jOOQ" Closes gh-14471 --- .../boot/autoconfigure/jooq/JooqAutoConfiguration.java | 1 + .../boot/autoconfigure/jooq/JooqAutoConfigurationTests.java | 6 ++++-- .../src/main/asciidoc/spring-boot-features.adoc | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java index cf63b5ade20a..9074078aacc1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java @@ -33,6 +33,7 @@ import org.jooq.impl.DefaultConfiguration; import org.jooq.impl.DefaultDSLContext; import org.jooq.impl.DefaultExecuteListenerProvider; + import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java index ff4cd0ecef52..10b7c7586ffe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfigurationTests.java @@ -16,9 +16,10 @@ package org.springframework.boot.autoconfigure.jooq; -import javax.sql.DataSource; import java.util.concurrent.Executor; +import javax.sql.DataSource; + import org.jooq.DSLContext; import org.jooq.ExecuteListener; import org.jooq.ExecuteListenerProvider; @@ -143,7 +144,8 @@ public void customProvidersArePickedUp() { TxManagerConfiguration.class, TestRecordMapperProvider.class, TestRecordUnmapperProvider.class, TestRecordListenerProvider.class, TestExecuteListenerProvider.class, TestVisitListenerProvider.class, - TestTransactionListenerProvider.class, TestExecutorProvider.class).run((context) -> { + TestTransactionListenerProvider.class, TestExecutorProvider.class) + .run((context) -> { DSLContext dsl = context.getBean(DSLContext.class); assertThat(dsl.configuration().recordMapperProvider().getClass()) .isEqualTo(TestRecordMapperProvider.class); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index bec852c2efb7..0e7c2dc2fc89 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3966,6 +3966,7 @@ which is used when the jOOQ `Configuration` is created. You can define beans for following jOOQ Types: * `ConnectionProvider` +* `ExecutorProvider` * `TransactionProvider` * `RecordMapperProvider` * `RecordUnmapperProvider` From 1a4ad96dd02839d9a7a63994299e4322f2763748 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 17 Sep 2018 12:29:48 +0100 Subject: [PATCH 616/701] Raised the default version of Mongo to 3.6.5 when using Embedded Mongo. While MongoDB 3.6.7 has been released, 3.6.5 is the latest version that's supported by the version of Embedded Mongo that we're currently using. Closes gh-14476 --- .../EmbeddedMongoAutoConfiguration.java | 20 +++++++++++++++---- .../embedded/EmbeddedMongoProperties.java | 12 +++++------ .../EmbeddedMongoAutoConfigurationTests.java | 11 +++++----- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 2fbd777fefd5..3c46b86434ee 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -35,6 +35,7 @@ import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion; +import de.flapdoodle.embed.mongo.distribution.Version; import de.flapdoodle.embed.mongo.distribution.Versions; import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.io.ProcessOutput; @@ -125,11 +126,8 @@ private MongodStarter getMongodStarter(IRuntimeConfig runtimeConfig) { @Bean @ConditionalOnMissingBean public IMongodConfig embeddedMongoConfiguration() throws IOException { - IFeatureAwareVersion featureAwareVersion = Versions.withFeatures( - new GenericVersion(this.embeddedProperties.getVersion()), - this.embeddedProperties.getFeatures().toArray(new Feature[0])); MongodConfigBuilder builder = new MongodConfigBuilder() - .version(featureAwareVersion); + .version(determineVersion()); EmbeddedMongoProperties.Storage storage = this.embeddedProperties.getStorage(); if (storage != null) { String databaseDir = storage.getDatabaseDir(); @@ -149,6 +147,20 @@ public IMongodConfig embeddedMongoConfiguration() throws IOException { return builder.build(); } + private IFeatureAwareVersion determineVersion() { + if (this.embeddedProperties.getFeatures() == null) { + for (Version version : Version.values()) { + if (version.asInDownloadPath() + .equals(this.embeddedProperties.getVersion())) { + return version; + } + } + } + return Versions.withFeatures( + new GenericVersion(this.embeddedProperties.getVersion()), + this.embeddedProperties.getFeatures().toArray(new Feature[0])); + } + private InetAddress getHost() throws UnknownHostException { if (this.properties.getHost() == null) { return InetAddress.getByAddress(Network.localhostIsIPv6() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java index 9814ba06f345..3ba0f415ca76 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +16,6 @@ package org.springframework.boot.autoconfigure.mongo.embedded; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; import de.flapdoodle.embed.mongo.distribution.Feature; @@ -37,15 +35,15 @@ public class EmbeddedMongoProperties { /** * Version of Mongo to use. */ - private String version = "3.2.2"; + private String version = "3.6.5"; private final Storage storage = new Storage(); /** - * Comma-separated list of features to enable. + * Comma-separated list of features to enable. Uses the defaults of the configured + * version by default. */ - private Set features = new HashSet<>( - Collections.singletonList(Feature.SYNC_DELAY)); + private Set features = null; public String getVersion() { return this.version; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index 554e47f4b89a..4d802360993a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -60,19 +60,20 @@ public void close() { @Test public void defaultVersion() { - assertVersionConfiguration(null, "3.2.2"); + assertVersionConfiguration(null, "3.6.5"); } @Test public void customVersion() { - assertVersionConfiguration("2.7.1", "2.7.1"); + assertVersionConfiguration("3.6.3", "3.6.3"); } @Test public void customFeatures() { - load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY"); + load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY, ONLY_WITH_SSL, NO_HTTP_INTERFACE_ARG"); assertThat(this.context.getBean(EmbeddedMongoProperties.class).getFeatures()) - .contains(Feature.TEXT_SEARCH, Feature.SYNC_DELAY); + .containsExactly(Feature.TEXT_SEARCH, Feature.SYNC_DELAY, + Feature.ONLY_WITH_SSL, Feature.NO_HTTP_INTERFACE_ARG); } @Test From 19cea75e746bf733ca9b9c2b80dae3f615bb641b Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 11 Sep 2018 16:56:04 -0400 Subject: [PATCH 617/701] Start building against Spring Kafka 2.2.0 snapshots See gh-14491 Closes gh-14420 --- .../kafka/KafkaStreamsAnnotationDrivenConfiguration.java | 2 +- .../kafka/KafkaAutoConfigurationIntegrationTests.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java index e6eeca66a859..8639b10b6d74 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaStreamsAnnotationDrivenConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.core.env.Environment; import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration; import org.springframework.kafka.config.KafkaStreamsConfiguration; -import org.springframework.kafka.core.StreamsBuilderFactoryBean; +import org.springframework.kafka.config.StreamsBuilderFactoryBean; /** * Configuration for Kafka Streams annotation-driven support. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java index 8dad270aece4..54841becddcb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationIntegrationTests.java @@ -31,9 +31,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.kafka.annotation.EnableKafkaStreams; import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.config.StreamsBuilderFactoryBean; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.core.StreamsBuilderFactoryBean; import org.springframework.kafka.support.KafkaHeaders; import org.springframework.kafka.test.rule.EmbeddedKafkaRule; import org.springframework.messaging.handler.annotation.Header; diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2c79c6fac890..16071a0a386e 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ ${spring.version} 0.25.0.RELEASE 5.1.0.M2 - 2.2.0.M3 + 2.2.0.BUILD-SNAPSHOT 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 51f9cdd14a191c2552bca0853bb8505ea461ece3 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 17 Sep 2018 11:22:01 -0700 Subject: [PATCH 618/701] Update pipeline badge configuration --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 36381005a171..e31172aea882 100755 --- a/README.adoc +++ b/README.adoc @@ -1,4 +1,4 @@ -= Spring Boot image:https://ci.spring.io/api/v1/teams/spring-boot/pipelines/spring-boot-2.0.x/jobs/build/badge["Build Status", link="https://ci.spring.io/teams/spring-boot/pipelines/spring-boot-2.0.x?groups=Build"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] += Spring Boot image:https://ci.spring.io/api/v1/teams/spring-boot/pipelines/spring-boot/jobs/build/badge["Build Status", link="https://ci.spring.io/teams/spring-boot/pipelines/spring-boot?groups=Build"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] :docs: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference Spring Boot makes it easy to create Spring-powered, production-grade applications and From 7127098f86d7eca1a2d5ff42897958e1a0bed812 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 17 Sep 2018 13:25:30 -0700 Subject: [PATCH 619/701] Remove call to stop_docker --- ci/images/docker-lib.sh | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ci/images/docker-lib.sh b/ci/images/docker-lib.sh index 497a422ceb3f..d16a9a67fc21 100644 --- a/ci/images/docker-lib.sh +++ b/ci/images/docker-lib.sh @@ -66,22 +66,10 @@ start_docker() { docker daemon --data-root /scratch/docker ${server_args} >/tmp/docker.log 2>&1 & echo $! > /tmp/docker.pid - trap stop_docker EXIT - sleep 1 until docker info >/dev/null 2>&1; do echo waiting for docker to come up... sleep 1 done -} - -stop_docker() { - local pid=$(cat /tmp/docker.pid) - if [ -z "$pid" ]; then - return 0 - fi - - kill -TERM $pid - wait $pid } \ No newline at end of file From 9201e23f67c51d75089d88810fb7eb4f1b2cf221 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Mon, 17 Sep 2018 15:25:54 -0700 Subject: [PATCH 620/701] Revert "Raised the default version of Mongo to 3.6.5 when using Embedded Mongo." This reverts commit 1a4ad96dd02839d9a7a63994299e4322f2763748. Reverting to see if this fixes CI timeouts. --- .../EmbeddedMongoAutoConfiguration.java | 20 ++++--------------- .../embedded/EmbeddedMongoProperties.java | 12 ++++++----- .../EmbeddedMongoAutoConfigurationTests.java | 11 +++++----- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 3c46b86434ee..2fbd777fefd5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -35,7 +35,6 @@ import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion; -import de.flapdoodle.embed.mongo.distribution.Version; import de.flapdoodle.embed.mongo.distribution.Versions; import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.io.ProcessOutput; @@ -126,8 +125,11 @@ private MongodStarter getMongodStarter(IRuntimeConfig runtimeConfig) { @Bean @ConditionalOnMissingBean public IMongodConfig embeddedMongoConfiguration() throws IOException { + IFeatureAwareVersion featureAwareVersion = Versions.withFeatures( + new GenericVersion(this.embeddedProperties.getVersion()), + this.embeddedProperties.getFeatures().toArray(new Feature[0])); MongodConfigBuilder builder = new MongodConfigBuilder() - .version(determineVersion()); + .version(featureAwareVersion); EmbeddedMongoProperties.Storage storage = this.embeddedProperties.getStorage(); if (storage != null) { String databaseDir = storage.getDatabaseDir(); @@ -147,20 +149,6 @@ public IMongodConfig embeddedMongoConfiguration() throws IOException { return builder.build(); } - private IFeatureAwareVersion determineVersion() { - if (this.embeddedProperties.getFeatures() == null) { - for (Version version : Version.values()) { - if (version.asInDownloadPath() - .equals(this.embeddedProperties.getVersion())) { - return version; - } - } - } - return Versions.withFeatures( - new GenericVersion(this.embeddedProperties.getVersion()), - this.embeddedProperties.getFeatures().toArray(new Feature[0])); - } - private InetAddress getHost() throws UnknownHostException { if (this.properties.getHost() == null) { return InetAddress.getByAddress(Network.localhostIsIPv6() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java index 3ba0f415ca76..9814ba06f345 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2017 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,6 +16,8 @@ package org.springframework.boot.autoconfigure.mongo.embedded; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; import de.flapdoodle.embed.mongo.distribution.Feature; @@ -35,15 +37,15 @@ public class EmbeddedMongoProperties { /** * Version of Mongo to use. */ - private String version = "3.6.5"; + private String version = "3.2.2"; private final Storage storage = new Storage(); /** - * Comma-separated list of features to enable. Uses the defaults of the configured - * version by default. + * Comma-separated list of features to enable. */ - private Set features = null; + private Set features = new HashSet<>( + Collections.singletonList(Feature.SYNC_DELAY)); public String getVersion() { return this.version; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index 4d802360993a..554e47f4b89a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2017 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. @@ -60,20 +60,19 @@ public void close() { @Test public void defaultVersion() { - assertVersionConfiguration(null, "3.6.5"); + assertVersionConfiguration(null, "3.2.2"); } @Test public void customVersion() { - assertVersionConfiguration("3.6.3", "3.6.3"); + assertVersionConfiguration("2.7.1", "2.7.1"); } @Test public void customFeatures() { - load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY, ONLY_WITH_SSL, NO_HTTP_INTERFACE_ARG"); + load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY"); assertThat(this.context.getBean(EmbeddedMongoProperties.class).getFeatures()) - .containsExactly(Feature.TEXT_SEARCH, Feature.SYNC_DELAY, - Feature.ONLY_WITH_SSL, Feature.NO_HTTP_INTERFACE_ARG); + .contains(Feature.TEXT_SEARCH, Feature.SYNC_DELAY); } @Test From c1b864c826bca8ed7a8b7619a40adfaba935440e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 18 Sep 2018 11:18:28 +0100 Subject: [PATCH 621/701] Polish --- .../rest/RestClientAutoConfigurationTests.java | 6 ++++-- .../cli/compiler/grape/DetailedProgressReporterTests.java | 4 ++-- .../boot/gradle/tasks/bundling/BootZipCopyAction.java | 1 + .../boot/testsupport/testcontainers/Container.java | 4 +++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java index 1fe8e2f7229f..6b367255ef27 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfigurationTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.junit.Test; @@ -87,9 +88,10 @@ public void restClientCanQueryElasticsearchNode() { source.put("b", "bravo"); IndexRequest index = new IndexRequest("foo", "bar", "1") .source(source); - client.index(index); + client.index(index, RequestOptions.DEFAULT); GetRequest getRequest = new GetRequest("foo", "bar", "1"); - assertThat(client.get(getRequest).isExists()).isTrue(); + assertThat(client.get(getRequest, RequestOptions.DEFAULT).isExists()) + .isTrue(); })); } diff --git a/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java b/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java index c4d6834b9189..d5b2a349be65 100644 --- a/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java +++ b/spring-boot-project/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java @@ -39,8 +39,8 @@ public final class DetailedProgressReporterTests { private static final String ARTIFACT = "org/alpha/bravo/charlie/1.2.3/charlie-1.2.3.jar"; - private final TransferResource resource = new TransferResource(REPOSITORY, ARTIFACT, - null, null); + private final TransferResource resource = new TransferResource(null, REPOSITORY, + ARTIFACT, null, null); private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java index b7b6e3a844e9..416a44fe4a0b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java @@ -119,6 +119,7 @@ public WorkResult execute(CopyActionProcessingStream stream) { return () -> true; } + @SuppressWarnings("unchecked") private Spec createExclusionSpec( Spec loaderEntries) { return Specs.union(loaderEntries, this.exclusions); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/Container.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/Container.java index c60b2393a22a..3c2f5dea4793 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/Container.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/Container.java @@ -24,6 +24,7 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.FailureDetectingExternalResource; import org.testcontainers.containers.GenericContainer; /** @@ -68,7 +69,8 @@ public Statement apply(Statement base, Description description) { return new SkipStatement(); } this.container = this.containerFactory.get(); - return this.container.apply(base, description); + return ((FailureDetectingExternalResource) this.container).apply(base, + description); } public int getMappedPort() { From 9e9dd4095986e28f2b93ec244864c2b66d827b89 Mon Sep 17 00:00:00 2001 From: Michael McFadyen Date: Sun, 16 Sep 2018 17:18:14 +0100 Subject: [PATCH 622/701] Add outcome tag to MVC and WebFlux HTTP request metrics See gh-14486 --- .../server/DefaultWebFluxTagsProvider.java | 3 +- .../web/reactive/server/WebFluxTags.java | 34 ++++++++++++++++++ .../servlet/DefaultWebMvcTagsProvider.java | 3 +- .../metrics/web/servlet/WebMvcTags.java | 32 +++++++++++++++++ .../endpoint/web/servlet/WebMvcTagsTests.java | 28 +++++++++++++++ .../web/reactive/server/WebFluxTagsTests.java | 35 +++++++++++++++++++ 6 files changed, 133 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/DefaultWebFluxTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/DefaultWebFluxTagsProvider.java index 94b02b938ac4..21e640cab1cb 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/DefaultWebFluxTagsProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/DefaultWebFluxTagsProvider.java @@ -35,7 +35,8 @@ public class DefaultWebFluxTagsProvider implements WebFluxTagsProvider { public Iterable httpRequestTags(ServerWebExchange exchange, Throwable exception) { return Arrays.asList(WebFluxTags.method(exchange), WebFluxTags.uri(exchange), - WebFluxTags.exception(exception), WebFluxTags.status(exchange)); + WebFluxTags.exception(exception), WebFluxTags.status(exchange), + WebFluxTags.outcome(exchange)); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java index db95cad6f745..782579279a05 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java @@ -30,6 +30,7 @@ * * @author Jon Schneider * @author Andy Wilkinson + * @author Michael McFadyen * @since 2.0.0 */ public final class WebFluxTags { @@ -42,6 +43,14 @@ public final class WebFluxTags { private static final Tag EXCEPTION_NONE = Tag.of("exception", "None"); + private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN"); + + private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS"); + + private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR"); + + private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR"); + private WebFluxTags() { } @@ -112,4 +121,29 @@ public static Tag exception(Throwable exception) { return EXCEPTION_NONE; } + /** + * Creates a {@code outcome} tag based on the response status of the given + * {@code exchange}. + * @param exchange the exchange + * @return the "outcome" tag derived from the response status + */ + public static Tag outcome(ServerWebExchange exchange) { + if (exchange != null && exchange.getResponse().getStatusCode() != null) { + HttpStatus status = exchange.getResponse().getStatusCode(); + if (status.is1xxInformational() || status.is2xxSuccessful() + || status.is3xxRedirection()) { + return OUTCOME_SUCCESS; + } + else if (status.is4xxClientError()) { + return OUTCOME_CLIENT_ERROR; + } + else { + return OUTCOME_SERVER_ERROR; + } + } + else { + return OUTCOME_UNKNOWN; + } + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/DefaultWebMvcTagsProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/DefaultWebMvcTagsProvider.java index 3f78a203bb91..5c10b584861e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/DefaultWebMvcTagsProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/DefaultWebMvcTagsProvider.java @@ -34,7 +34,8 @@ public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider { public Iterable getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) { return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), - WebMvcTags.exception(exception), WebMvcTags.status(response)); + WebMvcTags.exception(exception), WebMvcTags.status(response), + WebMvcTags.outcome(response)); } @Override diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java index d8006365937a..a7ba72a4272e 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java @@ -34,6 +34,7 @@ * @author Jon Schneider * @author Andy Wilkinson * @author Brian Clozel + * @author Michael McFadyen * @since 2.0.0 */ public final class WebMvcTags { @@ -50,6 +51,14 @@ public final class WebMvcTags { private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN"); + private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN"); + + private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS"); + + private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR"); + + private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR"); + private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN"); private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$"); @@ -149,4 +158,27 @@ public static Tag exception(Throwable exception) { return EXCEPTION_NONE; } + /** + * Creates a {@code outcome} tag based on the status of the given {@code response}. + * @param response the HTTP response + * @return the outcome tag derived from the status of the response + */ + public static Tag outcome(HttpServletResponse response) { + if (response != null) { + int status = response.getStatus(); + if (status < 400) { + return OUTCOME_SUCCESS; + } + else if (status < 500) { + return OUTCOME_CLIENT_ERROR; + } + else { + return OUTCOME_SERVER_ERROR; + } + } + else { + return OUTCOME_UNKNOWN; + } + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java index f871b918a092..df3e15d5abc7 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java @@ -31,6 +31,7 @@ * * @author Andy Wilkinson * @author Brian Clozel + * @author Michael McFadyen */ public class WebMvcTagsTests { @@ -91,4 +92,31 @@ public void uriTagIsUnknownWhenRequestIsNull() { assertThat(tag.getValue()).isEqualTo("UNKNOWN"); } + @Test + public void outcomeTagIsUnknownWhenResponseIsNull() { + Tag tag = WebMvcTags.outcome(null); + assertThat(tag.getValue()).isEqualTo("UNKNOWN"); + } + + @Test + public void outcomeTagIsSuccessWhenResponseIs2XX() { + this.response.setStatus(200); + Tag tag = WebMvcTags.outcome(this.response); + assertThat(tag.getValue()).isEqualTo("SUCCESS"); + } + + @Test + public void outcomeTagIsClientErrorWhenResponseIs4XX() { + this.response.setStatus(400); + Tag tag = WebMvcTags.outcome(this.response); + assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); + } + + @Test + public void outcomeTagIsServerErrorWhenResponseIs5XX() { + this.response.setStatus(500); + Tag tag = WebMvcTags.outcome(this.response); + assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java index a25a30da1df3..b342ffaf5587 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java @@ -36,6 +36,7 @@ * Tests for {@link WebFluxTags}. * * @author Brian Clozel + * @author Michael McFadyen */ public class WebFluxTagsTests { @@ -88,4 +89,38 @@ public void methodTagToleratesNonStandardHttpMethods() { assertThat(tag.getValue()).isEqualTo("CUSTOM"); } + @Test + public void outcomeTagIsUnknownWhenResponseIsNull() { + Tag tag = WebFluxTags.outcome(null); + assertThat(tag.getValue()).isEqualTo("UNKNOWN"); + } + + @Test + public void outcomeTagIsUnknownWhenResponseStatusIsNull() { + this.exchange.getResponse().setStatusCode(null); + Tag tag = WebFluxTags.outcome(this.exchange); + assertThat(tag.getValue()).isEqualTo("UNKNOWN"); + } + + @Test + public void outcomeTagIsSuccessWhenResponseIs2XX() { + this.exchange.getResponse().setStatusCode(HttpStatus.OK); + Tag tag = WebFluxTags.outcome(this.exchange); + assertThat(tag.getValue()).isEqualTo("SUCCESS"); + } + + @Test + public void outcomeTagIsClientErrorWhenResponseIs4XX() { + this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); + Tag tag = WebFluxTags.outcome(this.exchange); + assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); + } + + @Test + public void outcomeTagIsServerErrorWhenResponseIs5XX() { + this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY); + Tag tag = WebFluxTags.outcome(this.exchange); + assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); + } + } From c974192497e2ebc9594756d163131bed51925122 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 18 Sep 2018 11:58:52 +0100 Subject: [PATCH 623/701] Polish "Add outcome tag to MVC and WebFlux HTTP request metrics" Closes gh-14486 --- .../web/reactive/server/WebFluxTags.java | 29 ++++++---- .../metrics/web/servlet/WebMvcTags.java | 20 ++++--- .../endpoint/web/servlet/WebMvcTagsTests.java | 20 ++++++- .../web/reactive/server/WebFluxTagsTests.java | 24 +++++--- .../asciidoc/production-ready-features.adoc | 56 +++++++++++++++---- 5 files changed, 107 insertions(+), 42 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java index 782579279a05..3325c1950918 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java @@ -45,8 +45,12 @@ public final class WebFluxTags { private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN"); + private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL"); + private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS"); + private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION"); + private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR"); private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR"); @@ -125,25 +129,26 @@ public static Tag exception(Throwable exception) { * Creates a {@code outcome} tag based on the response status of the given * {@code exchange}. * @param exchange the exchange - * @return the "outcome" tag derived from the response status + * @return the outcome tag derived from the response status */ public static Tag outcome(ServerWebExchange exchange) { - if (exchange != null && exchange.getResponse().getStatusCode() != null) { - HttpStatus status = exchange.getResponse().getStatusCode(); - if (status.is1xxInformational() || status.is2xxSuccessful() - || status.is3xxRedirection()) { + HttpStatus status = exchange.getResponse().getStatusCode(); + if (status != null) { + if (status.is1xxInformational()) { + return OUTCOME_INFORMATIONAL; + } + if (status.is2xxSuccessful()) { return OUTCOME_SUCCESS; } - else if (status.is4xxClientError()) { - return OUTCOME_CLIENT_ERROR; + if (status.is3xxRedirection()) { + return OUTCOME_REDIRECTION; } - else { - return OUTCOME_SERVER_ERROR; + if (status.is4xxClientError()) { + return OUTCOME_CLIENT_ERROR; } + return OUTCOME_SERVER_ERROR; } - else { - return OUTCOME_UNKNOWN; - } + return OUTCOME_UNKNOWN; } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java index a7ba72a4272e..bf587d4c583a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java @@ -53,8 +53,12 @@ public final class WebMvcTags { private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN"); + private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL"); + private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS"); + private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION"); + private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR"); private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR"); @@ -166,19 +170,21 @@ public static Tag exception(Throwable exception) { public static Tag outcome(HttpServletResponse response) { if (response != null) { int status = response.getStatus(); - if (status < 400) { + if (status < 200) { + return OUTCOME_INFORMATIONAL; + } + if (status < 300) { return OUTCOME_SUCCESS; } + if (status < 400) { + return OUTCOME_REDIRECTION; + } else if (status < 500) { return OUTCOME_CLIENT_ERROR; } - else { - return OUTCOME_SERVER_ERROR; - } - } - else { - return OUTCOME_UNKNOWN; + return OUTCOME_SERVER_ERROR; } + return OUTCOME_UNKNOWN; } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java index df3e15d5abc7..043b12268b61 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java @@ -99,21 +99,35 @@ public void outcomeTagIsUnknownWhenResponseIsNull() { } @Test - public void outcomeTagIsSuccessWhenResponseIs2XX() { + public void outcomeTagIsInformationalWhenResponseIs1xx() { + this.response.setStatus(100); + Tag tag = WebMvcTags.outcome(this.response); + assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); + } + + @Test + public void outcomeTagIsSuccessWhenResponseIs2xx() { this.response.setStatus(200); Tag tag = WebMvcTags.outcome(this.response); assertThat(tag.getValue()).isEqualTo("SUCCESS"); } @Test - public void outcomeTagIsClientErrorWhenResponseIs4XX() { + public void outcomeTagIsRedirectionWhenResponseIs3xx() { + this.response.setStatus(301); + Tag tag = WebMvcTags.outcome(this.response); + assertThat(tag.getValue()).isEqualTo("REDIRECTION"); + } + + @Test + public void outcomeTagIsClientErrorWhenResponseIs4xx() { this.response.setStatus(400); Tag tag = WebMvcTags.outcome(this.response); assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); } @Test - public void outcomeTagIsServerErrorWhenResponseIs5XX() { + public void outcomeTagIsServerErrorWhenResponseIs5xx() { this.response.setStatus(500); Tag tag = WebMvcTags.outcome(this.response); assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java index b342ffaf5587..83d042239c28 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java @@ -90,34 +90,42 @@ public void methodTagToleratesNonStandardHttpMethods() { } @Test - public void outcomeTagIsUnknownWhenResponseIsNull() { - Tag tag = WebFluxTags.outcome(null); + public void outcomeTagIsUnknownWhenResponseStatusIsNull() { + this.exchange.getResponse().setStatusCode(null); + Tag tag = WebFluxTags.outcome(this.exchange); assertThat(tag.getValue()).isEqualTo("UNKNOWN"); } @Test - public void outcomeTagIsUnknownWhenResponseStatusIsNull() { - this.exchange.getResponse().setStatusCode(null); + public void outcomeTagIsInformationalWhenResponseIs1xx() { + this.exchange.getResponse().setStatusCode(HttpStatus.CONTINUE); Tag tag = WebFluxTags.outcome(this.exchange); - assertThat(tag.getValue()).isEqualTo("UNKNOWN"); + assertThat(tag.getValue()).isEqualTo("INFORMATIONAL"); } @Test - public void outcomeTagIsSuccessWhenResponseIs2XX() { + public void outcomeTagIsSuccessWhenResponseIs2xx() { this.exchange.getResponse().setStatusCode(HttpStatus.OK); Tag tag = WebFluxTags.outcome(this.exchange); assertThat(tag.getValue()).isEqualTo("SUCCESS"); } @Test - public void outcomeTagIsClientErrorWhenResponseIs4XX() { + public void outcomeTagIsRedirectionWhenResponseIs3xx() { + this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); + Tag tag = WebFluxTags.outcome(this.exchange); + assertThat(tag.getValue()).isEqualTo("REDIRECTION"); + } + + @Test + public void outcomeTagIsClientErrorWhenResponseIs4xx() { this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST); Tag tag = WebFluxTags.outcome(this.exchange); assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR"); } @Test - public void outcomeTagIsServerErrorWhenResponseIs5XX() { + public void outcomeTagIsServerErrorWhenResponseIs5xx() { this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY); Tag tag = WebFluxTags.outcome(this.exchange); assertThat(tag.getValue()).isEqualTo("SERVER_ERROR"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 7effaadbe601..3671d5e8eafd 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1723,12 +1723,28 @@ customized by setting the `management.metrics.web.server.requests-metric-name` p By default, Spring MVC-related metrics are tagged with the following information: -* `method`, the request's method (for example, `GET` or `POST`). -* `uri`, the request's URI template prior to variable substitution, if possible (for -example, `/api/person/{id}`). -* `status`, the response's HTTP status code (for example, `200` or `500`). -* `exception`, the simple class name of any exception that was thrown while handling the -request. +|=== +|Tag |Description + +|`exception` +|Simple class name of any exception that was thrown while handling the request. + +|`method` +|Request's method (for example, `GET` or `POST`) + +|`outcome` +|Request's outcome based on the status code of the response. 1xx is +`INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx `CLIENT_ERROR`, and 5xx is +`SERVER_ERROR` + +|`status` +|Response's HTTP status code (for example, `200` or `500`) + +|`uri` +|Request's URI template prior to variable substitution, if possible (for example, +`/api/person/{id}`) + +|=== To customize the tags, provide a `@Bean` that implements `WebMvcTagsProvider`. @@ -1744,12 +1760,28 @@ the name by setting the `management.metrics.web.server.requests-metric-name` pro By default, WebFlux-related metrics are tagged with the following information: -* `method`, the request's method (for example, `GET` or `POST`). -* `uri`, the request's URI template prior to variable substitution, if possible (for -example, `/api/person/{id}`). -* `status`, the response's HTTP status code (for example, `200` or `500`). -* `exception`, the simple class name of any exception that was thrown while handling the -request. +|=== +|Tag |Description + +|`exception` +|Simple class name of any exception that was thrown while handling the request. + +|`method` +|Request's method (for example, `GET` or `POST`) + +|`outcome` +|Request's outcome based on the status code of the response. 1xx is +`INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx `CLIENT_ERROR`, and 5xx is +`SERVER_ERROR` + +|`status` +|Response's HTTP status code (for example, `200` or `500`) + +|`uri` +|Request's URI template prior to variable substitution, if possible (for example, +`/api/person/{id}`) + +|=== To customize the tags, provide a `@Bean` that implements `WebFluxTagsProvider`. From 1b7325df52256f3722b710b516c10b7c599d1125 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 18 Sep 2018 19:35:04 +0200 Subject: [PATCH 624/701] Switch to Reactor Californium SNAPSHOTs See gh-14507 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- .../boot/web/embedded/netty/NettyReactiveWebServerFactory.java | 2 +- .../reactive/server/AbstractReactiveWebServerFactoryTests.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 16071a0a386e..7305b448fe15 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -143,7 +143,7 @@ 2.3.0 4.2.1 5.4.1 - Californium-RC1 + Californium-BUILD-SNAPSHOT 3.1.1 1.0.2 1.3.8 diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java index 0bafb6eabaae..0e020556ffb3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java @@ -123,7 +123,7 @@ private HttpServer createHttpServer() { server = compressionCustomizer.apply(server); } server = server.protocol(listProtocols()); - server = (this.useForwardHeaders ? server.forwarded() : server.noForwarded()); + server = server.forwarded(this.useForwardHeaders); return applyCustomizers(server); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 536c7ae033d8..bc1d9ca24548 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -307,7 +307,7 @@ protected WebClient prepareCompressionTest(Compression compression) { .getWebServer(new CharsHandler(3000, MediaType.TEXT_PLAIN)); this.webServer.start(); - HttpClient client = HttpClient.create().wiretap().compress().tcpConfiguration( + HttpClient client = HttpClient.create().wiretap().compress(true).tcpConfiguration( (tcpClient) -> tcpClient.doOnConnected((connection) -> connection .channel().pipeline().addBefore(NettyPipeline.HttpDecompressor, "CompressionTest", new CompressionDetectionHandler()))); From d0a252181be4bac3bd0134a0fc2a3f38d27b05c8 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 13 Sep 2018 02:25:20 +0900 Subject: [PATCH 625/701] Polish Closes gh-14449 --- .../BackgroundPreinitializer.java | 2 +- .../autoconfigure/http/HttpProperties.java | 6 +-- ...fkaListenerContainerFactoryConfigurer.java | 39 ++++++++----------- .../OnPropertyListConditionTests.java | 2 +- .../OnWsdlLocationsConditionTests.java | 6 +-- .../WebServicesAutoConfigurationTests.java | 12 +++--- .../appendix-application-properties.adoc | 4 +- .../main/asciidoc/spring-boot-features.adoc | 2 +- ...tionJsonEnvironmentPostProcessorTests.java | 1 - 9 files changed, 32 insertions(+), 42 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java index 6566b819e65f..308e5e123a07 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/BackgroundPreinitializer.java @@ -55,7 +55,7 @@ public class BackgroundPreinitializer /** * System property that instructs Spring Boot how to run pre initialization. When the - * property is set to {@code true}, no pre intialization happens and each item is + * property is set to {@code true}, no pre-initialization happens and each item is * initialized in the foreground as it needs to. When the property is {@code false} * (default), pre initialization runs in a separate thread in the background. * @since 2.1.0 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java index 0ec8c88137ac..ef8a265a566e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpProperties.java @@ -43,7 +43,7 @@ public class HttpProperties { /** * HTTP encoding properties. */ - private Encoding encoding = new Encoding(); + private final Encoding encoding = new Encoding(); public boolean isLogRequestDetails() { return this.logRequestDetails; @@ -57,10 +57,6 @@ public Encoding getEncoding() { return this.encoding; } - public void setEncoding(Encoding encoding) { - this.encoding = encoding; - } - /** * Configuration properties for http encoding. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java index 11dcb6329311..e1f104b00067 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/ConcurrentKafkaListenerContainerFactoryConfigurer.java @@ -117,38 +117,33 @@ public void configure( private void configureListenerFactory( ConcurrentKafkaListenerContainerFactory factory) { - PropertyMapper map = PropertyMapper.get(); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); Listener properties = this.properties.getListener(); - map.from(properties::getConcurrency).whenNonNull().to(factory::setConcurrency); - map.from(this.messageConverter).whenNonNull().to(factory::setMessageConverter); - map.from(this.replyTemplate).whenNonNull().to(factory::setReplyTemplate); + map.from(properties::getConcurrency).to(factory::setConcurrency); + map.from(this.messageConverter).to(factory::setMessageConverter); + map.from(this.replyTemplate).to(factory::setReplyTemplate); map.from(properties::getType).whenEqualTo(Listener.Type.BATCH) .toCall(() -> factory.setBatchListener(true)); - map.from(this.errorHandler).whenNonNull().to(factory::setErrorHandler); - map.from(this.afterRollbackProcessor).whenNonNull() - .to(factory::setAfterRollbackProcessor); + map.from(this.errorHandler).to(factory::setErrorHandler); + map.from(this.afterRollbackProcessor).to(factory::setAfterRollbackProcessor); } private void configureContainer(ContainerProperties container) { - PropertyMapper map = PropertyMapper.get(); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); Listener properties = this.properties.getListener(); - map.from(properties::getAckMode).whenNonNull().to(container::setAckMode); - map.from(properties::getClientId).whenNonNull().to(container::setClientId); - map.from(properties::getAckCount).whenNonNull().to(container::setAckCount); - map.from(properties::getAckTime).whenNonNull().as(Duration::toMillis) - .to(container::setAckTime); - map.from(properties::getPollTimeout).whenNonNull().as(Duration::toMillis) + map.from(properties::getAckMode).to(container::setAckMode); + map.from(properties::getClientId).to(container::setClientId); + map.from(properties::getAckCount).to(container::setAckCount); + map.from(properties::getAckTime).as(Duration::toMillis).to(container::setAckTime); + map.from(properties::getPollTimeout).as(Duration::toMillis) .to(container::setPollTimeout); - map.from(properties::getNoPollThreshold).whenNonNull() - .to(container::setNoPollThreshold); - map.from(properties::getIdleEventInterval).whenNonNull().as(Duration::toMillis) + map.from(properties::getNoPollThreshold).to(container::setNoPollThreshold); + map.from(properties::getIdleEventInterval).as(Duration::toMillis) .to(container::setIdleEventInterval); - map.from(properties::getMonitorInterval).whenNonNull().as(Duration::getSeconds) + map.from(properties::getMonitorInterval).as(Duration::getSeconds) .as(Number::intValue).to(container::setMonitorInterval); - map.from(properties::getLogContainerConfig).whenNonNull() - .to(container::setLogContainerConfig); - map.from(this.transactionManager).whenNonNull() - .to(container::setTransactionManager); + map.from(properties::getLogContainerConfig).to(container::setLogContainerConfig); + map.from(this.transactionManager).to(container::setTransactionManager); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnPropertyListConditionTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnPropertyListConditionTests.java index 8794881f8d96..d3ca046ecce6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnPropertyListConditionTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnPropertyListConditionTests.java @@ -54,7 +54,7 @@ public void propertyDefinedAsList() { @Test public void propertyDefinedAsCommaSeparatedRelaxed() { - this.contextRunner.withPropertyValues("spring.test.my-list=value1") + this.contextRunner.withPropertyValues("spring.test.myList=value1") .run((context) -> assertThat(context).hasBean("foo")); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/OnWsdlLocationsConditionTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/OnWsdlLocationsConditionTests.java index 69605a9e030a..4de3a6f673f4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/OnWsdlLocationsConditionTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/OnWsdlLocationsConditionTests.java @@ -37,18 +37,18 @@ public class OnWsdlLocationsConditionTests { .withUserConfiguration(TestConfig.class); @Test - public void bootstrapHostsNotDefined() { + public void wsdlLocationsNotDefined() { this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean("foo")); } @Test - public void bootstrapHostsDefinedAsCommaSeparated() { + public void wsdlLocationsDefinedAsCommaSeparated() { this.contextRunner.withPropertyValues("spring.webservices.wsdl-locations=value1") .run((context) -> assertThat(context).hasBean("foo")); } @Test - public void bootstrapHostsDefinedAsList() { + public void wsdlLocationsDefinedAsList() { this.contextRunner .withPropertyValues("spring.webservices.wsdl-locations[0]=value1") .run((context) -> assertThat(context).hasBean("foo")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java index 1bfc1c7deba5..840d4f34a657 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java @@ -99,9 +99,9 @@ public void withWsdlBeans() { .withPropertyValues("spring.webservices.wsdl-locations=classpath:/wsdl") .run((context) -> { assertThat(context.getBeansOfType(SimpleWsdl11Definition.class)) - .hasSize(1).containsKey("service"); - assertThat(context.getBeansOfType(SimpleXsdSchema.class)).hasSize(1) - .containsKey("types"); + .containsOnlyKeys("service"); + assertThat(context.getBeansOfType(SimpleXsdSchema.class)) + .containsOnlyKeys("types"); }); } @@ -112,9 +112,9 @@ public void withWsdlBeansAsList() { "spring.webservices.wsdl-locations[0]=classpath:/wsdl") .run((context) -> { assertThat(context.getBeansOfType(SimpleWsdl11Definition.class)) - .hasSize(1).containsKey("service"); - assertThat(context.getBeansOfType(SimpleXsdSchema.class)).hasSize(1) - .containsKey("types"); + .containsOnlyKeys("service"); + assertThat(context.getBeansOfType(SimpleXsdSchema.class)) + .containsOnlyKeys("types"); }); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 68a800641ef0..b37c8236658a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -181,7 +181,7 @@ content into your application. Rather, pick only the properties that you need. server.address= # Network address to which the server should bind. server.compression.enabled=false # Whether response compression is enabled. server.compression.excluded-user-agents= # List of user-agents to exclude from compression. - server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript # Comma-separated list of MIME types that should be compressed. + server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml # Comma-separated list of MIME types that should be compressed. server.compression.min-response-size=2048 # Minimum "Content-Length" value that is required for compression to be performed. server.connection-timeout= # Time that connectors wait for another HTTP request before closing the connection. When not set, the connector's container-specific default is used. Use a value of -1 to indicate no (that is, an infinite) timeout. server.error.include-exception=false # Include the "exception" attribute. @@ -328,7 +328,7 @@ content into your application. Rather, pick only the properties that you need. # SPRING HATEOAS ({sc-spring-boot-autoconfigure}/hateoas/HateoasProperties.{sc-ext}[HateoasProperties]) spring.hateoas.use-hal-as-default-json-media-type=true # Whether application/hal+json responses should be sent to requests that accept application/json. - # HTTP ({sc-spring-boot-autoconfigure}/http/HttpEncodingProperties.{sc-ext}[HttpProperties]) + # HTTP ({sc-spring-boot-autoconfigure}/http/HttpProperties.{sc-ext}[HttpProperties]) spring.http.converters.preferred-json-mapper= # Preferred JSON mapper to use for HTTP message conversion. By default, auto-detected according to the environment. spring.http.encoding.charset=UTF-8 # Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly. spring.http.encoding.enabled=true # Whether to enable http encoding support. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 4dfc15a9dda1..17bafd476dfa 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5734,7 +5734,7 @@ container factory. Similarly, if a `RecordMessageConverter`, `ErrorHandler` or factory. TIP: A custom `ChainedKafkaTransactionManager` must be marked `@Primary` as it usually -reference the auto-configured `KafkaTransactionManager` bean. +references the auto-configured `KafkaTransactionManager` bean. diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java index 574ffe8ba142..e19cca9c70f3 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/SpringApplicationJsonEnvironmentPostProcessorTests.java @@ -54,7 +54,6 @@ public void error() { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, "spring.application.json=foo:bar"); this.processor.postProcessEnvironment(this.environment, null); - assertThat(this.environment.resolvePlaceholders("${foo:}")).isEmpty(); } @Test From f42891489d1830c30f2955c136971eb39f2aced0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 19 Sep 2018 10:31:01 +0200 Subject: [PATCH 626/701] Polish key description Closes gh-14450 --- .../META-INF/additional-spring-configuration-metadata.json | 2 +- .../src/main/asciidoc/appendix-application-properties.adoc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 081c720427f6..c11143977271 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -23,7 +23,7 @@ { "name": "spring.devtools.add-properties", "type": "java.lang.Boolean", - "description": "Whether to enable devtool property defaults.", + "description": "Whether to enable development property defaults.", "defaultValue": true } ] diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index b37c8236658a..ebf56b728800 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1491,6 +1491,7 @@ content into your application. Rather, pick only the properties that you need. # ---------------------------------------- # DEVTOOLS ({sc-spring-boot-devtools}/autoconfigure/DevToolsProperties.{sc-ext}[DevToolsProperties]) + spring.devtools.add-properties=true # Whether to enable development property defaults. spring.devtools.livereload.enabled=true # Whether to enable a livereload.com-compatible server. spring.devtools.livereload.port=35729 # Server port. spring.devtools.restart.additional-exclude= # Additional patterns that should be excluded from triggering a full restart. From b416a466745d9357b837afb68f273d5e01fcc31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Onimus?= Date: Mon, 17 Sep 2018 20:33:55 +0200 Subject: [PATCH 627/701] Add reference to ssh shell spring boot starter See gh-14496 --- spring-boot-project/spring-boot-starters/README.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index f915ebc98956..81de05cccadc 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -139,6 +139,9 @@ do as they were designed before this was clarified. | https://github.com/savantly-net/sprout-platform[Sprout Platform] | https://github.com/savantly-net/sprout-platform/tree/master/spring/sprout-spring-boot-starter +| https://github.com/fonimus/ssh-shell-spring-boot[Ssh Spring Shell] +| https://github.com/fonimus/ssh-shell-spring-boot + | SSH Daemon | https://github.com/anand1st/sshd-shell-spring-boot From 390fc03769055c57a141ecb2a5ee416560bcec5e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 19 Sep 2018 11:27:26 +0200 Subject: [PATCH 628/701] Polish "Add reference to ssh shell spring boot starter" Closes gh-14496 --- spring-boot-project/spring-boot-starters/README.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-starters/README.adoc b/spring-boot-project/spring-boot-starters/README.adoc index 81de05cccadc..1aa3c295cf98 100644 --- a/spring-boot-project/spring-boot-starters/README.adoc +++ b/spring-boot-project/spring-boot-starters/README.adoc @@ -136,12 +136,12 @@ do as they were designed before this was clarified. | https://projects.spring.io/spring-batch/[Spring Batch] (Advanced usage) | https://github.com/codecentric/spring-boot-starter-batch-web +| https://projects.spring.io/spring-shell/[Spring Shell] +| https://github.com/fonimus/ssh-shell-spring-boot + | https://github.com/savantly-net/sprout-platform[Sprout Platform] | https://github.com/savantly-net/sprout-platform/tree/master/spring/sprout-spring-boot-starter -| https://github.com/fonimus/ssh-shell-spring-boot[Ssh Spring Shell] -| https://github.com/fonimus/ssh-shell-spring-boot - | SSH Daemon | https://github.com/anand1st/sshd-shell-spring-boot From 11864f2bb61a07e69571354019849e00b7983892 Mon Sep 17 00:00:00 2001 From: yongsungjeon Date: Tue, 18 Sep 2018 16:08:23 +0900 Subject: [PATCH 629/701] Use constant for produces attribute Closes gh-14501 --- .../autoconfigure/web/servlet/error/BasicErrorController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java index a70a62a19488..167909e9ce11 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java @@ -82,7 +82,7 @@ public String getErrorPath() { return this.errorProperties.getPath(); } - @RequestMapping(produces = "text/html") + @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); From 6164c9e8b60a345aafb4d6da70e7a1fc0e7926ff Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 19 Sep 2018 14:20:42 +0100 Subject: [PATCH 630/701] Start building against Spring Data Lovelace snapshots See gh-14510 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f7962286c7d9..b7ea37018771 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -161,7 +161,7 @@ 2.1.0.M3 4.1.0.M3 2.0.3.RELEASE - Lovelace-RC2 + Lovelace-BUILD-SNAPSHOT ${spring.version} 0.25.0.RELEASE 5.1.0.M2 From fd97f072096de0ff83c2000e80df11cabd939594 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Wed, 19 Sep 2018 19:54:42 +0900 Subject: [PATCH 631/701] Use meaningful name for MockServerConfigurer bean Closes gh-14512 --- .../web/reactive/WebTestClientSecurityConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java index 0c09b669299e..3dfb3c36d434 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientSecurityConfiguration.java @@ -33,7 +33,7 @@ class WebTestClientSecurityConfiguration { @Bean - public MockServerConfigurer get() { + public MockServerConfigurer mockServerConfigurer() { return SecurityMockServerConfigurers.springSecurity(); } From efae363974b41332765862a05aaeb33c28e27030 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 19 Sep 2018 19:59:09 +0100 Subject: [PATCH 632/701] Register functional rather than reflective bean definitions where possible Closes gh-14516 --- ...tadataReaderFactoryContextInitializer.java | 8 ++++--- .../condition/BeanTypeRegistry.java | 8 +++++-- .../WebServicesAutoConfiguration.java | 21 ++++++++++--------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java index d42431e9b166..2da74b5fabdc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java @@ -23,9 +23,9 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; @@ -85,8 +85,10 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) } private void register(BeanDefinitionRegistry registry) { - RootBeanDefinition definition = new RootBeanDefinition( - SharedMetadataReaderFactoryBean.class); + BeanDefinition definition = BeanDefinitionBuilder + .genericBeanDefinition(SharedMetadataReaderFactoryBean.class, + SharedMetadataReaderFactoryBean::new) + .getBeanDefinition(); registry.registerBeanDefinition(BEAN_NAME, definition); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java index 694e926d25a1..f032be8b59d2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/BeanTypeRegistry.java @@ -38,6 +38,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.ResolvableType; @@ -93,8 +94,11 @@ static BeanTypeRegistry get(ListableBeanFactory beanFactory) { Assert.isTrue(listableBeanFactory.isAllowEagerClassLoading(), "Bean factory must allow eager class loading"); if (!listableBeanFactory.containsLocalBean(BEAN_NAME)) { - BeanDefinition bd = new RootBeanDefinition(BeanTypeRegistry.class); - bd.getConstructorArgumentValues().addIndexedArgumentValue(0, beanFactory); + BeanDefinition bd = BeanDefinitionBuilder + .genericBeanDefinition(BeanTypeRegistry.class, + () -> new BeanTypeRegistry( + (DefaultListableBeanFactory) beanFactory)) + .getBeanDefinition(); listableBeanFactory.registerBeanDefinition(BEAN_NAME, bd); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java index 6bbae47a7cd3..2541b4b3f0bf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java @@ -19,13 +19,14 @@ import java.io.IOException; import java.util.Collections; import java.util.List; +import java.util.function.Function; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -118,8 +119,9 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) .orElse(Collections.emptyList()); for (String wsdlLocation : wsdlLocations) { registerBeans(wsdlLocation, "*.wsdl", SimpleWsdl11Definition.class, - registry); - registerBeans(wsdlLocation, "*.xsd", SimpleXsdSchema.class, registry); + SimpleWsdl11Definition::new, registry); + registerBeans(wsdlLocation, "*.xsd", SimpleXsdSchema.class, + SimpleXsdSchema::new, registry); } } @@ -128,13 +130,12 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } - private void registerBeans(String location, String pattern, Class type, - BeanDefinitionRegistry registry) { + private void registerBeans(String location, String pattern, Class type, + Function beanSupplier, BeanDefinitionRegistry registry) { for (Resource resource : getResources(location, pattern)) { - RootBeanDefinition beanDefinition = new RootBeanDefinition(type); - ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues(); - constructorArguments.addIndexedArgumentValue(0, resource); - beanDefinition.setConstructorArgumentValues(constructorArguments); + BeanDefinition beanDefinition = BeanDefinitionBuilder + .genericBeanDefinition(type, () -> beanSupplier.apply(resource)) + .getBeanDefinition(); registry.registerBeanDefinition( StringUtils.stripFilenameExtension(resource.getFilename()), beanDefinition); From 521f746151f549cd235d6398631ea0d538ff3b73 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Thu, 20 Sep 2018 02:47:56 +0900 Subject: [PATCH 633/701] Polish Closes gh-14517 --- .../quartz/QuartzAutoConfigurationTests.java | 1 - .../asciidoc/appendix-application-properties.adoc | 3 ++- .../src/main/asciidoc/spring-boot-features.adoc | 6 +++--- .../WebTestClientAutoConfigurationTests.java | 2 +- ...ngBootTestRandomPortEnvironmentPostProcessor.java | 7 ++++--- .../test/mock/mockito/MockitoPostProcessorTests.java | 10 +++++----- ...tTestRandomPortEnvironmentPostProcessorTests.java | 7 +++---- .../context/logging/LoggingApplicationListener.java | 12 ++++++------ .../boot/convert/ApplicationConversionService.java | 3 ++- .../additional-spring-configuration-metadata.json | 8 ++++---- .../sample/simple/service/HelloWorldService.java | 4 ---- 11 files changed, 30 insertions(+), 33 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 0dcf5be66d22..c1cd6f74e23e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -254,7 +254,6 @@ public void withCustomConfiguration() { "spring.quartz.scheduler-name=testScheduler", "spring.quartz.auto-startup=false", "spring.quartz.startup-delay=1m", "spring.quartz.wait-for-jobs-to-complete-on-shutdown=true", - "spring.quartz.wait-for-jobs-to-complete-on-shutdown=true", "spring.quartz.overwrite-existing-jobs=true").run((context) -> { assertThat(context).hasSingleBean(SchedulerFactoryBean.class); SchedulerFactoryBean schedulerFactory = context diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index ebf56b728800..1fc1d2feb023 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -36,6 +36,7 @@ content into your application. Rather, pick only the properties that you need. logging.file= # Log file name (for instance, `myapp.log`). Names can be an exact location or relative to the current directory. logging.file.max-history=0 # Maximum of archive log files to keep. Only supported with the default logback setup. logging.file.max-size=10MB # Maximum log file size. Only supported with the default logback setup. + logging.group.*= # Log groups to quickly change multiple loggers at the same time. For instance, `logging.level.db=org.hibernate,org.springframework.jdbc`. logging.level.*= # Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`. logging.path= # Location of the log file. For instance, `/var/log`. logging.pattern.console= # Appender pattern for output to the console. Supported only with the default Logback setup. @@ -147,10 +148,10 @@ content into your application. Rather, pick only the properties that you need. spring.quartz.jdbc.initialize-schema=embedded # Database schema initialization mode. spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. + spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. spring.quartz.properties.*= # Additional Quartz Scheduler properties. spring.quartz.scheduler-name=quartzScheduler # Name of the scheduler. spring.quartz.startup-delay=0s # Delay after which the scheduler is started once initialization completes. - spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. spring.quartz.wait-for-jobs-to-complete-on-shutdown=false # Whether to wait for running jobs to complete on shutdown. # REACTOR ({sc-spring-boot-autoconfigure}/reactor/core/ReactorCoreProperties.{sc-ext}[ReactorCoreProperties]) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 855c9bdb7d3e..1461b7999e7f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1735,11 +1735,11 @@ The following example shows potential logging settings in `application.propertie === Log Groups It's often useful to be able to group related loggers together so that they can all be configured at the same time. For example, you might commonly change the logging levels for -_all_ Tomcat related loggers, but you can't easily remember to top level packages. +_all_ Tomcat related loggers, but you can't easily remember top level packages. -To help with this, Spring Boot allows you do define logging groups in your Spring +To help with this, Spring Boot allows you to define logging groups in your Spring `Environment`. For example, here's how you could define a "`tomcat`" group by adding -it to your `appplication.properties`: +it to your `application.properties`: [source,properties,indent=0,subs="verbatim,quotes,attributes"] ---- diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java index 3801dbb9734e..174213bcc0cc 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java @@ -116,7 +116,7 @@ public void shouldNotApplySpringSecurityConfigurerWhenSpringSecurityNotOnClassPa .getField(builder, "httpHandlerBuilder"); List filters = (List) ReflectionTestUtils .getField(httpHandlerBuilder, "filters"); - assertThat(filters.size()).isEqualTo(0); + assertThat(filters).isEmpty(); }); } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java index ce9f6ab91afd..282d9ffa34fd 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessor.java @@ -45,10 +45,11 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, .get(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME); if (isTestServerPortRandom(source)) { if (source.getProperty(MANAGEMENT_PORT_PROPERTY) == null) { - String managementPort = getPort(environment, MANAGEMENT_PORT_PROPERTY, + String managementPort = getProperty(environment, MANAGEMENT_PORT_PROPERTY, null); - String serverPort = getPort(environment, SERVER_PORT_PROPERTY, "8080"); if (managementPort != null && !managementPort.equals("-1")) { + String serverPort = getProperty(environment, SERVER_PORT_PROPERTY, + "8080"); if (!managementPort.equals(serverPort)) { source.getSource().put(MANAGEMENT_PORT_PROPERTY, "0"); } @@ -65,7 +66,7 @@ private boolean isTestServerPortRandom(MapPropertySource source) { return (source != null && "0".equals(source.getProperty(SERVER_PORT_PROPERTY))); } - private String getPort(ConfigurableEnvironment environment, String property, + private String getProperty(ConfigurableEnvironment environment, String property, String defaultValue) { return environment.getPropertySources().stream() .filter((source) -> !source.getName().equals( diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java index 88d4ccbf3dee..da7a76a1e3dc 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessorTests.java @@ -190,7 +190,7 @@ public ExampleService example2() { @Configuration static class MultipleQualifiedBeans { - @MockBean(ExampleService.class) + @MockBean @Qualifier("test") private ExampleService mock; @@ -216,7 +216,7 @@ public ExampleService example3() { @Configuration static class MockPrimaryBean { - @MockBean(ExampleService.class) + @MockBean private ExampleService mock; @Bean @@ -236,7 +236,7 @@ public ExampleService examplePrimary() { @Configuration static class MockQualifiedBean { - @MockBean(ExampleService.class) + @MockBean @Qualifier("test") private ExampleService mock; @@ -257,7 +257,7 @@ public ExampleService examplePrimary() { @Configuration static class SpyPrimaryBean { - @SpyBean(ExampleService.class) + @SpyBean private ExampleService spy; @Bean @@ -277,7 +277,7 @@ public ExampleService examplePrimary() { @Configuration static class SpyQualifiedBean { - @SpyBean(ExampleService.class) + @SpyBean @Qualifier("test") private ExampleService spy; diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java index f439f53993a5..f81c399fee21 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/SpringBootTestRandomPortEnvironmentPostProcessorTests.java @@ -50,7 +50,6 @@ public void setup() { @Test public void postProcessWhenServerAndManagementPortIsZeroInTestPropertySource() { addTestPropertySource("0", "0"); - this.environment.setProperty("management.server.port", "0"); this.postProcessor.postProcessEnvironment(this.environment, null); assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); assertThat(this.environment.getProperty("management.server.port")).isEqualTo("0"); @@ -81,8 +80,7 @@ public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNull() { addTestPropertySource("0", null); this.postProcessor.postProcessEnvironment(this.environment, null); assertThat(this.environment.getProperty("server.port")).isEqualTo("0"); - assertThat(this.environment.getProperty("management.server.port")) - .isEqualTo(null); + assertThat(this.environment.getProperty("management.server.port")).isNull(); } @Test @@ -100,7 +98,8 @@ public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndSame @Test public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDefaultSameInProduction() { - // mgmt port is 8080 which means its on the same port as main server since that is + // mgmt port is 8080 which means it's on the same port as main server since that + // is // null in app properties addTestPropertySource("0", null); Map other = new HashMap<>(); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java index 4fb6e429cd0d..2f30d2a23ca6 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java @@ -59,7 +59,7 @@ * environment contains a {@code logging.config} property it will be used to bootstrap the * logging system, otherwise a default configuration is used. Regardless, logging levels * will be customized if the environment contains {@code logging.level.*} entries and - * logging groups can be defined with {@code logging.group} . + * logging groups can be defined with {@code logging.group}. *

    * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when * the environment contains {@code debug} or {@code trace} properties that aren't set to @@ -150,7 +150,7 @@ public class LoggingApplicationListener implements GenericApplicationListener { private static final Class[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class }; - private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false); + private static final AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false); private final Log logger = LogFactory.getLog(getClass()); @@ -323,7 +323,8 @@ protected void setLogLevels(LoggingSystem system, Environment environment) { return; } Binder binder = Binder.get(environment); - Map groups = getGroups(binder); + Map groups = getGroups(); + binder.bind("logging.group", STRING_STRINGS_MAP.withExistingValue(groups)); Map levels = binder.bind("logging.level", STRING_STRING_MAP) .orElseGet(Collections::emptyMap); levels.forEach((name, level) -> { @@ -337,11 +338,10 @@ protected void setLogLevels(LoggingSystem system, Environment environment) { }); } - private Map getGroups(Binder binder) { + private Map getGroups() { Map groups = new LinkedHashMap<>(); DEFAULT_GROUP_LOGGERS.forEach( (name, loggers) -> groups.put(name, StringUtils.toStringArray(loggers))); - binder.bind("logging.group", STRING_STRINGS_MAP.withExistingValue(groups)); return groups; } @@ -405,7 +405,7 @@ public void setSpringBootLogging(LogLevel springBootLogging) { /** * Sets if initialization arguments should be parsed for {@literal debug} and * {@literal trace} properties (usually defined from {@literal --debug} or - * {@literal --trace} command line args. Defaults to {@code true}. + * {@literal --trace} command line args). Defaults to {@code true}. * @param parseArgs if arguments should be parsed */ public void setParseArgs(boolean parseArgs) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java index 33aaab3a24a8..e1d9ec482cdd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java @@ -55,7 +55,8 @@ public ApplicationConversionService(StringValueResolver embeddedValueResolver) { /** * Return a shared default {@code ApplicationConversionService} instance, lazily * building it once needed. - * @return the shared {@code ConversionService} instance (never {@code null}) + * @return the shared {@code ApplicationConversionService} instance (never + * {@code null}) */ public static ApplicationConversionService getSharedInstance() { ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance; diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ed3127ef84f3..d7c990b50f7c 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -88,15 +88,15 @@ "defaultValue": 0 }, { - "name": "logging.level", + "name": "logging.group", "type": "java.util.Map", - "description": "Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`.", + "description": "Log groups to quickly change multiple loggers at the same time. For instance, `logging.level.db=org.hibernate,org.springframework.jdbc`.", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" }, { - "name": "logging.group", + "name": "logging.level", "type": "java.util.Map", - "description": "Log groups to quickly change multipe loggers at the same time. For instance, `logging.level.db=org.hibernate,org.springframework.jdbc`.", + "description": "Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`.", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" }, { diff --git a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java index 69ea7065dd7f..56d79f81d901 100644 --- a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java +++ b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java @@ -34,8 +34,4 @@ public String getHelloMessage() { return "Hello " + this.name + " for " + this.duration.getSeconds() + " seconds"; } - public Duration getDuration() { - return this.duration; - } - } From 9bca95e499281d42135ab163ec4f1ba31d99dd75 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 10:47:19 +0200 Subject: [PATCH 634/701] Upgrade to Reactor Californium RELEASE Closes gh-14507 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index a7ec4bc451fd..17f94dab7018 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -143,7 +143,7 @@ 2.3.0 4.2.1 5.4.1 - Californium-BUILD-SNAPSHOT + Californium-RELEASE 3.1.1 1.0.2 1.3.8 From d10ba396731e96a22466a5a0741ea759541bd8a8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 20 Sep 2018 09:48:31 +0100 Subject: [PATCH 635/701] Update GitHub pull request template to align with issue template --- .github/PULL_REQUEST_TEMPLATE.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9ae7f83f4470..f97d9f541a2f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,26 @@ \ No newline at end of file +Thanks for contributing to Spring Boot. Please review the following notes before +submitting you pull request. + +Security Vulnerabilities + +STOP! If your contribution fixes a security vulnerability, please do not submit it. +Instead, please head over to https://pivotal.io/security to learn how to disclose a +vulnerability responsibly. + +Dependency Upgrades + +Please do not open a pull request for a straightforward dependency upgrade (one that +only updates the version property). We have a semi-automated process for such upgrades +that we prefer to use. However, if the upgrade is more involved (such as requiring +changes for removed or deprecated API) your pull request is most welcome. + +Describing Your Changes + +If, having reviewed the notes above, you're ready to submit your pull request, please +provide a brief description of the proposed changes. If they fix a bug, please +describe the broken behaviour and how the changes fix it. If they make an enhancement, +please describe the new functionality and why you believe it's useful. If your pull +request relates to any existing issues, please reference them by using the issue number +prefixed with #. +--> From 8652f4078115b2ba12c38b1a110e443546fc683f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:27:57 +0200 Subject: [PATCH 636/701] Allow Quartz property to set the scheduler name This commit makes sure that "org.quartz.scheduler.instanceName" is honoured if set. Previously, "spring.quartz.scheduler-name" had a default value and was always set. As a result, `SchedulerFactoryBean` did not take the quartz property into account. Closes gh-14243 --- .../quartz/QuartzAutoConfiguration.java | 4 +- .../quartz/QuartzProperties.java | 2 +- ...itional-spring-configuration-metadata.json | 5 ++ .../quartz/QuartzAutoConfigurationTests.java | 46 +++++++++++++++++-- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 09b9685512e9..658010ae7c39 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -90,7 +90,9 @@ public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory( this.applicationContext.getAutowireCapableBeanFactory())); - schedulerFactoryBean.setBeanName(this.properties.getSchedulerName()); + if (this.properties.getSchedulerName() != null) { + schedulerFactoryBean.setSchedulerName(this.properties.getSchedulerName()); + } schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup()); schedulerFactoryBean .setStartupDelay((int) this.properties.getStartupDelay().getSeconds()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index 1f4e4984a998..733b3ba2dafe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -41,7 +41,7 @@ public class QuartzProperties { /** * Name of the scheduler. */ - private String schedulerName = "quartzScheduler"; + private String schedulerName; /** * Whether to automatically start the scheduler after initialization. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 85dc74583d18..c370ba38c3aa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -504,6 +504,11 @@ "level" : "error" } }, + { + "name": "spring.quartz.scheduler-name", + "type": "java.lang.String", + "defaultValue": "quartzScheduler" + }, { "name": "spring.quartz.jdbc.initialize-schema", "defaultValue": "embedded" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index c1cd6f74e23e..f7d8859e009b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -250,17 +250,14 @@ public void validateDefaultProperties() { @Test public void withCustomConfiguration() { - this.contextRunner.withPropertyValues( - "spring.quartz.scheduler-name=testScheduler", - "spring.quartz.auto-startup=false", "spring.quartz.startup-delay=1m", + this.contextRunner.withPropertyValues("spring.quartz.auto-startup=false", + "spring.quartz.startup-delay=1m", "spring.quartz.wait-for-jobs-to-complete-on-shutdown=true", "spring.quartz.overwrite-existing-jobs=true").run((context) -> { assertThat(context).hasSingleBean(SchedulerFactoryBean.class); SchedulerFactoryBean schedulerFactory = context .getBean(SchedulerFactoryBean.class); DirectFieldAccessor dfa = new DirectFieldAccessor(schedulerFactory); - assertThat(dfa.getPropertyValue("schedulerName")) - .isEqualTo("testScheduler"); assertThat(schedulerFactory.isAutoStartup()).isFalse(); assertThat(dfa.getPropertyValue("startupDelay")).isEqualTo(60); assertThat(dfa.getPropertyValue("waitForJobsToCompleteOnShutdown")) @@ -270,6 +267,45 @@ public void withCustomConfiguration() { }); } + @Test + public void schedulerNameWithDedicatedProperty() { + this.contextRunner + .withPropertyValues("spring.quartz.scheduler-name=testScheduler") + .run(assertSchedulerName("testScheduler")); + } + + @Test + public void schedulerNameWithQuartzProperty() { + this.contextRunner.withPropertyValues( + "spring.quartz.properties.org.quartz.scheduler.instanceName=testScheduler") + .run(assertSchedulerName("testScheduler")); + } + + @Test + public void schedulerNameWithDedicatedPropertyTakesPrecedence() { + this.contextRunner.withPropertyValues( + "spring.quartz.scheduler-name=specificTestScheduler", + "spring.quartz.properties.org.quartz.scheduler.instanceName=testScheduler") + .run(assertSchedulerName("specificTestScheduler")); + } + + @Test + public void schedulerNameUseBeanNameByDefault() { + this.contextRunner.withPropertyValues() + .run(assertSchedulerName("quartzScheduler")); + } + + private ContextConsumer assertSchedulerName( + String schedulerName) { + return (context) -> { + assertThat(context).hasSingleBean(SchedulerFactoryBean.class); + SchedulerFactoryBean schedulerFactory = context + .getBean(SchedulerFactoryBean.class); + DirectFieldAccessor dfa = new DirectFieldAccessor(schedulerFactory); + assertThat(dfa.getPropertyValue("schedulerName")).isEqualTo(schedulerName); + }; + } + @Import(ComponentThatUsesScheduler.class) @Configuration protected static class BaseQuartzConfiguration { From 1ce6fdeeb838143478e7bdaf9f2f3c71a7bac161 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:29 +0200 Subject: [PATCH 637/701] Upgrade to Hazelcast 3.10.5 Closes gh-14537 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e3b44dae2806..7fe741817cbc 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -67,7 +67,7 @@ 2.8.5 1.4.197 1.3 - 3.10.4 + 3.10.5 1.2.3 5.3.6.Final 6.0.13.Final From 310d6a5c794207e5bba215ec318a866ae3e04082 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:30 +0200 Subject: [PATCH 638/701] Upgrade to Lettuce 5.1.0.RELEASE Closes gh-14538 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 7fe741817cbc..049bf84748f4 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -121,7 +121,7 @@ 5.3.1 2.0.0 1.2.61 - 5.1.0.RC1 + 5.1.0.RELEASE 3.6.2 2.11.1 1.2.3 From a176e64ad83fad878fb7d66bb0b19f60de6a37c4 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:31 +0200 Subject: [PATCH 639/701] Upgrade to Htmlunit 2.33 Closes gh-14539 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 049bf84748f4..6e0cabec999e 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -73,7 +73,7 @@ 6.0.13.Final 3.2.0 2.4.1 - 2.32 + 2.33 4.1.4 4.5.6 4.4.10 From 705ac1b4f36f0c85ad9ff8e1ce5b99362ac3299f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:32 +0200 Subject: [PATCH 640/701] Upgrade to Elasticsearch 6.4.1 Closes gh-14540 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 6e0cabec999e..abcafc1a1a72 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -60,7 +60,7 @@ 2.1.1 5.1.4 2.3.28 - 6.4.0 + 6.4.1 3.0.0 2.3.0.1 2.5.2 From ad340d253c212068e379260218aa185804b905f0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:32 +0200 Subject: [PATCH 641/701] Upgrade to Influxdb Java 2.13 Closes gh-14541 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index abcafc1a1a72..b8056837f9b3 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -78,7 +78,7 @@ 4.5.6 4.4.10 9.3.3.Final - 2.12 + 2.13 2.9.7 3.0.10 1.2.0 From fd8c074371cdad4a17918fd737be2cf1e51a4be7 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:33 +0200 Subject: [PATCH 642/701] Upgrade to Kotlin 1.2.70 Closes gh-14542 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index b8056837f9b3..383209e9a24b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -120,7 +120,7 @@ 4.12 5.3.1 2.0.0 - 1.2.61 + 1.2.70 5.1.0.RELEASE 3.6.2 2.11.1 From 2a2f1e4023420cd40da5ae81122f5627859deec1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:34 +0200 Subject: [PATCH 643/701] Upgrade to Jooq 3.11.5 Closes gh-14543 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 383209e9a24b..aa296d0d6d39 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -112,7 +112,7 @@ 2.10 1.6.0 1.1.10 - 3.11.4 + 3.11.5 1.5.0 2.4.0 1.2 From 8b2bf3e0d9fd96ed48dd251c12451ead7e0e9ff3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:34 +0200 Subject: [PATCH 644/701] Upgrade to Mongodb 3.8.2 Closes gh-14544 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index aa296d0d6d39..2f263ee5bcc6 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -130,7 +130,7 @@ 1.0.6 2.22.0 1.9.1 - 3.8.1 + 3.8.2 6.4.0.jre8 8.0.12 1.9.22 From 90f4da0dac6b043bea6c5ea1d5610adcf7db03a2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:35 +0200 Subject: [PATCH 645/701] Upgrade to Mongo Driver Reactivestreams 1.9.2 Closes gh-14545 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 2f263ee5bcc6..79602aaffaad 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -129,7 +129,7 @@ 2.3.0 1.0.6 2.22.0 - 1.9.1 + 1.9.2 3.8.2 6.4.0.jre8 8.0.12 From cd45343d4153e7482fb97a0f58b4b12fb2e5757e Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 11:45:36 +0200 Subject: [PATCH 646/701] Upgrade to Maven Shade Plugin 3.2.0 Closes gh-14546 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 79602aaffaad..0efa90c31331 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -208,7 +208,7 @@ 3.1.0 3.0.1 3.1.0 - 3.1.1 + 3.2.0 3.7.1 3.0.1 2.22.0 From cea95c303fe9944dbcad694395db777a03c1ef16 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 19 Sep 2018 14:20:16 +0200 Subject: [PATCH 647/701] Add support for SAP Hana Database See gh-14513 --- .../java/org/springframework/boot/jdbc/DatabaseDriver.java | 6 ++++++ .../org/springframework/boot/jdbc/DatabaseDriverTests.java | 3 +++ 2 files changed, 9 insertions(+) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java index 367f0dcd309c..d17e1b47c44f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java @@ -99,6 +99,12 @@ public String getId() { POSTGRESQL("PostgreSQL", "org.postgresql.Driver", "org.postgresql.xa.PGXADataSource", "SELECT 1"), + /** + * SAP - SAP Hana Database - HDB. + */ + SAP("HDB", "com.sap.db.jdbc.Driver", "com.sap.db.jdbcext.XADataSourceSAP", + "SELECT 1 FROM DUMMY"), + /** * jTDS. As it can be used for several databases, there isn't a single product name we * could rely on. diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java index 0396a75b8892..2778231653db 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java @@ -74,6 +74,7 @@ public void databaseProductNameLookups() { assertThat(DatabaseDriver.fromProductName("Apache Derby")) .isEqualTo(DatabaseDriver.DERBY); assertThat(DatabaseDriver.fromProductName("H2")).isEqualTo(DatabaseDriver.H2); + assertThat(DatabaseDriver.fromProductName("HDB")).isEqualTo(DatabaseDriver.SAP); assertThat(DatabaseDriver.fromProductName("HSQL Database Engine")) .isEqualTo(DatabaseDriver.HSQLDB); assertThat(DatabaseDriver.fromProductName("SQLite")) @@ -113,6 +114,8 @@ public void databaseJdbcUrlLookups() { .isEqualTo(DatabaseDriver.DERBY); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:h2:~/sample")) .isEqualTo(DatabaseDriver.H2); + assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sap:localhost")) + .isEqualTo(DatabaseDriver.SAP); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:hsqldb:hsql://localhost")) .isEqualTo(DatabaseDriver.HSQLDB); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sqlite:sample.db")) From 22e77e02b6b9063d36b94f00c9e3892e8b8fc891 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 12:02:55 +0200 Subject: [PATCH 648/701] Polish "Add support for SAP Hana Database" Closes gh-14513 --- .../org/springframework/boot/jdbc/DatabaseDriverTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java index 2778231653db..edd85a708b4c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -114,8 +114,6 @@ public void databaseJdbcUrlLookups() { .isEqualTo(DatabaseDriver.DERBY); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:h2:~/sample")) .isEqualTo(DatabaseDriver.H2); - assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sap:localhost")) - .isEqualTo(DatabaseDriver.SAP); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:hsqldb:hsql://localhost")) .isEqualTo(DatabaseDriver.HSQLDB); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sqlite:sample.db")) @@ -129,6 +127,8 @@ public void databaseJdbcUrlLookups() { assertThat( DatabaseDriver.fromJdbcUrl("jdbc:jtds:sqlserver://127.0.0.1:1433/sample")) .isEqualTo(DatabaseDriver.JTDS); + assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sap:localhost")) + .isEqualTo(DatabaseDriver.SAP); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:sqlserver://127.0.0.1:1433")) .isEqualTo(DatabaseDriver.SQLSERVER); assertThat(DatabaseDriver.fromJdbcUrl("jdbc:firebirdsql://localhost/sample")) From 5323095e44d8e2a7d10a9dac61ecb5593c9b4dec Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 20 Sep 2018 13:32:21 +0200 Subject: [PATCH 649/701] Fix broken build --- .../boot/jdbc/DatabaseDriverClassNameTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverClassNameTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverClassNameTests.java index fe5751f674ee..d7193d4bd7f4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverClassNameTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/DatabaseDriverClassNameTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -46,7 +46,7 @@ public class DatabaseDriverClassNameTests { private static final Set EXCLUDED_DRIVERS = Collections .unmodifiableSet(EnumSet.of(DatabaseDriver.UNKNOWN, DatabaseDriver.ORACLE, DatabaseDriver.DB2, DatabaseDriver.DB2_AS400, DatabaseDriver.INFORMIX, - DatabaseDriver.TERADATA)); + DatabaseDriver.SAP, DatabaseDriver.TERADATA)); private final String className; From cc6cf880cf0323fce34a35fd63ecb8d6d2661a08 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 19 Sep 2018 21:11:55 +0100 Subject: [PATCH 650/701] Stop using ObjectProvider and ObjectProvider Closes gh-14467 --- .../jmx/JmxEndpointAutoConfiguration.java | 11 +++--- .../web/WebEndpointAutoConfiguration.java | 13 ++++--- .../info/InfoEndpointAutoConfiguration.java | 11 +++--- ...ourceHealthIndicatorAutoConfiguration.java | 6 ++- ...heduledTasksEndpointAutoConfiguration.java | 10 ++--- ...eyManagementChildContextConfiguration.java | 15 +++----- .../MappingsEndpointAutoConfiguration.java | 7 ++-- ...gApplicationAdminJmxAutoConfiguration.java | 10 ++--- .../RabbitAnnotationDrivenConfiguration.java | 14 +++---- .../amqp/RabbitAutoConfiguration.java | 11 +++--- .../cache/CacheAutoConfiguration.java | 7 ++-- .../cache/JCacheCacheConfiguration.java | 29 ++++++-------- .../cassandra/CassandraAutoConfiguration.java | 14 +++---- .../neo4j/Neo4jDataAutoConfiguration.java | 9 +---- .../redis/JedisConnectionConfiguration.java | 16 +++----- .../redis/LettuceConnectionConfiguration.java | 14 +++---- .../jest/JestAutoConfiguration.java | 14 +++---- .../rest/RestClientAutoConfiguration.java | 10 ++--- .../flyway/FlywayAutoConfiguration.java | 15 ++++---- .../FlywaySchemaManagementProvider.java | 18 ++++----- ...ttpMessageConvertersAutoConfiguration.java | 9 ++--- .../jersey/JerseyAutoConfiguration.java | 16 +++----- ...ctiveMQConnectionFactoryConfiguration.java | 10 +++-- ...iveMQXAConnectionFactoryConfiguration.java | 11 +++--- .../ArtemisEmbeddedServerConfiguration.java | 29 +++++++------- .../liquibase/LiquibaseAutoConfiguration.java | 7 +--- .../LiquibaseSchemaManagementProvider.java | 19 +++++----- .../mongo/MongoReactiveAutoConfiguration.java | 7 ++-- .../jpa/HibernateDefaultDdlAutoProvider.java | 19 ++++------ .../orm/jpa/HibernateJpaConfiguration.java | 13 +++---- .../orm/jpa/JpaBaseConfiguration.java | 9 ++--- .../quartz/QuartzAutoConfiguration.java | 15 +++----- .../thymeleaf/ThymeleafAutoConfiguration.java | 14 +++---- .../TransactionAutoConfiguration.java | 7 ++-- .../client/RestTemplateAutoConfiguration.java | 14 +++---- .../reactive/WebFluxAutoConfiguration.java | 36 +++++++----------- .../error/ErrorWebFluxAutoConfiguration.java | 8 ++-- .../client/WebClientAutoConfiguration.java | 14 ++----- .../error/ErrorMvcAutoConfiguration.java | 6 ++- .../WebServiceTemplateAutoConfiguration.java | 11 ++---- .../HibernateDefaultDdlAutoProviderTests.java | 2 +- .../restdocs/RestDocsAutoConfiguration.java | 38 ++++++------------- .../WebTestClientAutoConfiguration.java | 7 ++-- 43 files changed, 245 insertions(+), 330 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java index 54cb45d92be8..efc7a0437230 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.jmx; -import java.util.Collection; -import java.util.Collections; +import java.util.stream.Collectors; import javax.management.MBeanServer; @@ -75,11 +74,11 @@ public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, @ConditionalOnMissingBean(JmxEndpointsSupplier.class) public JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer( ParameterValueMapper parameterValueMapper, - ObjectProvider> invokerAdvisors, - ObjectProvider>> filters) { + ObjectProvider invokerAdvisors, + ObjectProvider> filters) { return new JmxEndpointDiscoverer(this.applicationContext, parameterValueMapper, - invokerAdvisors.getIfAvailable(Collections::emptyList), - filters.getIfAvailable(Collections::emptyList)); + invokerAdvisors.orderedStream().collect(Collectors.toList()), + filters.orderedStream().collect(Collectors.toList())); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.java index b070cae49490..cf5c7f4991d2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; @@ -95,12 +96,12 @@ public EndpointMediaTypes endpointMediaTypes() { public WebEndpointDiscoverer webEndpointDiscoverer( ParameterValueMapper parameterValueMapper, EndpointMediaTypes endpointMediaTypes, PathMapper webEndpointPathMapper, - ObjectProvider> invokerAdvisors, - ObjectProvider>> filters) { + ObjectProvider invokerAdvisors, + ObjectProvider> filters) { return new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, endpointMediaTypes, webEndpointPathMapper, - invokerAdvisors.getIfAvailable(Collections::emptyList), - filters.getIfAvailable(Collections::emptyList)); + invokerAdvisors.orderedStream().collect(Collectors.toList()), + filters.orderedStream().collect(Collectors.toList())); } @Bean @@ -144,10 +145,10 @@ static class WebEndpointServletConfiguration { @ConditionalOnMissingBean(ServletEndpointsSupplier.class) public ServletEndpointDiscoverer servletEndpointDiscoverer( ApplicationContext applicationContext, PathMapper webEndpointPathMapper, - ObjectProvider>> filters) { + ObjectProvider> filters) { return new ServletEndpointDiscoverer(applicationContext, webEndpointPathMapper, - filters.getIfAvailable(Collections::emptyList)); + filters.orderedStream().collect(Collectors.toList())); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfiguration.java index 2b1583f92906..33ec17611546 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.info; -import java.util.Collections; -import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; @@ -42,9 +41,9 @@ public class InfoEndpointAutoConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint - public InfoEndpoint infoEndpoint( - ObjectProvider> infoContributors) { - return new InfoEndpoint(infoContributors.getIfAvailable(Collections::emptyList)); + public InfoEndpoint infoEndpoint(ObjectProvider infoContributors) { + return new InfoEndpoint( + infoContributors.orderedStream().collect(Collectors.toList())); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfiguration.java index 9484ac44fed6..496716247bb8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthIndicatorAutoConfiguration.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; import javax.sql.DataSource; @@ -73,9 +74,10 @@ public class DataSourceHealthIndicatorAutoConfiguration extends public DataSourceHealthIndicatorAutoConfiguration( ObjectProvider> dataSources, - ObjectProvider> metadataProviders) { + ObjectProvider metadataProviders) { this.dataSources = filterDataSources(dataSources.getIfAvailable()); - this.metadataProviders = metadataProviders.getIfAvailable(); + this.metadataProviders = metadataProviders.orderedStream() + .collect(Collectors.toList()); } private Map filterDataSources( diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java index 0c47fd8859a8..e2ec1d5489c5 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.scheduling; -import java.util.Collections; -import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; @@ -41,8 +40,9 @@ public class ScheduledTasksEndpointAutoConfiguration { @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint public ScheduledTasksEndpoint scheduledTasksEndpoint( - ObjectProvider> holders) { - return new ScheduledTasksEndpoint(holders.getIfAvailable(Collections::emptyList)); + ObjectProvider holders) { + return new ScheduledTasksEndpoint( + holders.orderedStream().collect(Collectors.toList())); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java index 72254e309e7b..c9375606bf0d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.web.jersey; -import java.util.Collections; -import java.util.List; +import java.util.stream.Stream; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; @@ -48,12 +47,11 @@ @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet") public class JerseyManagementChildContextConfiguration { - private final List resourceConfigCustomizers; + private final Stream resourceConfigCustomizers; public JerseyManagementChildContextConfiguration( - ObjectProvider> resourceConfigCustomizers) { - this.resourceConfigCustomizers = resourceConfigCustomizers - .getIfAvailable(Collections::emptyList); + ObjectProvider resourceConfigCustomizers) { + this.resourceConfigCustomizers = resourceConfigCustomizers.orderedStream(); } @Bean @@ -65,9 +63,8 @@ public ServletRegistrationBean jerseyServletRegistration() { @Bean public ResourceConfig endpointResourceConfig() { ResourceConfig resourceConfig = new ResourceConfig(); - for (ResourceConfigCustomizer customizer : this.resourceConfigCustomizers) { - customizer.customize(resourceConfig); - } + this.resourceConfigCustomizers + .forEach((customizer) -> customizer.customize(resourceConfig)); return resourceConfig; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java index 0236567801bb..89d6d7898fe3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java @@ -16,8 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.web.mappings; -import java.util.Collection; -import java.util.Collections; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; @@ -50,9 +49,9 @@ public class MappingsEndpointAutoConfiguration { @Bean @ConditionalOnEnabledEndpoint public MappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext, - ObjectProvider> descriptionProviders) { + ObjectProvider descriptionProviders) { return new MappingsEndpoint( - descriptionProviders.getIfAvailable(Collections::emptyList), + descriptionProviders.orderedStream().collect(Collectors.toList()), applicationContext); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java index c21f7ef4068c..0ad49cd7412b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +16,6 @@ package org.springframework.boot.autoconfigure.admin; -import java.util.List; - import javax.management.MalformedObjectNameException; import org.springframework.beans.factory.ObjectProvider; @@ -57,13 +55,13 @@ public class SpringApplicationAdminJmxAutoConfiguration { */ private static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Admin,name=SpringApplication"; - private final List mbeanExporters; + private final Iterable mbeanExporters; private final Environment environment; public SpringApplicationAdminJmxAutoConfiguration( - ObjectProvider> mbeanExporters, Environment environment) { - this.mbeanExporters = mbeanExporters.getIfAvailable(); + ObjectProvider mbeanExporters, Environment environment) { + this.mbeanExporters = mbeanExporters; this.environment = environment; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java index 68f4fd42dbbf..2be022cb6687 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.amqp; -import java.util.List; +import java.util.stream.Collectors; import org.springframework.amqp.rabbit.annotation.EnableRabbit; import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; @@ -47,13 +47,13 @@ class RabbitAnnotationDrivenConfiguration { private final ObjectProvider messageRecoverer; - private final ObjectProvider> retryTemplateCustomizers; + private final ObjectProvider retryTemplateCustomizers; private final RabbitProperties properties; RabbitAnnotationDrivenConfiguration(ObjectProvider messageConverter, ObjectProvider messageRecoverer, - ObjectProvider> retryTemplateCustomizers, + ObjectProvider retryTemplateCustomizers, RabbitProperties properties) { this.messageConverter = messageConverter; this.messageRecoverer = messageRecoverer; @@ -67,8 +67,8 @@ public SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContai SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer(); configurer.setMessageConverter(this.messageConverter.getIfUnique()); configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique()); - configurer.setRetryTemplateCustomizers( - this.retryTemplateCustomizers.getIfAvailable()); + configurer.setRetryTemplateCustomizers(this.retryTemplateCustomizers + .orderedStream().collect(Collectors.toList())); configurer.setRabbitProperties(this.properties); return configurer; } @@ -90,8 +90,8 @@ public DirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContai DirectRabbitListenerContainerFactoryConfigurer configurer = new DirectRabbitListenerContainerFactoryConfigurer(); configurer.setMessageConverter(this.messageConverter.getIfUnique()); configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique()); - configurer.setRetryTemplateCustomizers( - this.retryTemplateCustomizers.getIfAvailable()); + configurer.setRetryTemplateCustomizers(this.retryTemplateCustomizers + .orderedStream().collect(Collectors.toList())); configurer.setRabbitProperties(this.properties); return configurer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java index 17edff75658c..ec30db5fac16 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.amqp; import java.time.Duration; -import java.util.List; +import java.util.stream.Collectors; import com.rabbitmq.client.Channel; @@ -161,11 +161,11 @@ protected static class RabbitTemplateConfiguration { private final ObjectProvider messageConverter; - private final ObjectProvider> retryTemplateCustomizers; + private final ObjectProvider retryTemplateCustomizers; public RabbitTemplateConfiguration(RabbitProperties properties, ObjectProvider messageConverter, - ObjectProvider> retryTemplateCustomizers) { + ObjectProvider retryTemplateCustomizers) { this.properties = properties; this.messageConverter = messageConverter; this.retryTemplateCustomizers = retryTemplateCustomizers; @@ -185,8 +185,9 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitProperties.Template properties = this.properties.getTemplate(); if (properties.getRetry().isEnabled()) { template.setRetryTemplate(new RetryTemplateFactory( - this.retryTemplateCustomizers.getIfAvailable()) - .createRetryTemplate(properties.getRetry(), + this.retryTemplateCustomizers.orderedStream() + .collect(Collectors.toList())).createRetryTemplate( + properties.getRetry(), RabbitRetryTemplateCustomizer.Target.SENDER)); } map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java index d5ff20582771..ec56805d2bce 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.cache; -import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; @@ -67,8 +67,9 @@ public class CacheAutoConfiguration { @Bean @ConditionalOnMissingBean public CacheManagerCustomizers cacheManagerCustomizers( - ObjectProvider>> customizers) { - return new CacheManagerCustomizers(customizers.getIfAvailable()); + ObjectProvider> customizers) { + return new CacheManagerCustomizers( + customizers.orderedStream().collect(Collectors.toList())); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java index ec308ad0b6db..76039134583c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.List; import java.util.Properties; +import java.util.stream.Stream; import javax.cache.CacheManager; import javax.cache.Caching; @@ -42,7 +43,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotatedTypeMetadata; @@ -70,22 +70,22 @@ class JCacheCacheConfiguration implements BeanClassLoaderAware { private final javax.cache.configuration.Configuration defaultCacheConfiguration; - private final List cacheManagerCustomizers; + private final Stream cacheManagerCustomizers; - private final List cachePropertiesCustomizers; + private final Stream cachePropertiesCustomizers; private ClassLoader beanClassLoader; JCacheCacheConfiguration(CacheProperties cacheProperties, CacheManagerCustomizers customizers, ObjectProvider> defaultCacheConfiguration, - ObjectProvider> cacheManagerCustomizers, - ObjectProvider> cachePropertiesCustomizers) { + ObjectProvider cacheManagerCustomizers, + ObjectProvider cachePropertiesCustomizers) { this.cacheProperties = cacheProperties; this.customizers = customizers; this.defaultCacheConfiguration = defaultCacheConfiguration.getIfAvailable(); - this.cacheManagerCustomizers = cacheManagerCustomizers.getIfAvailable(); - this.cachePropertiesCustomizers = cachePropertiesCustomizers.getIfAvailable(); + this.cacheManagerCustomizers = cacheManagerCustomizers.orderedStream(); + this.cachePropertiesCustomizers = cachePropertiesCustomizers.orderedStream(); } @Override @@ -135,11 +135,8 @@ private CachingProvider getCachingProvider(String cachingProviderFqn) { private Properties createCacheManagerProperties() { Properties properties = new Properties(); - if (this.cachePropertiesCustomizers != null) { - for (JCachePropertiesCustomizer customizer : this.cachePropertiesCustomizers) { - customizer.customize(this.cacheProperties, properties); - } - } + this.cachePropertiesCustomizers.forEach( + (customizer) -> customizer.customize(this.cacheProperties, properties)); return properties; } @@ -151,12 +148,8 @@ private Properties createCacheManagerProperties() { } private void customize(CacheManager cacheManager) { - if (this.cacheManagerCustomizers != null) { - AnnotationAwareOrderComparator.sort(this.cacheManagerCustomizers); - for (JCacheManagerCustomizer customizer : this.cacheManagerCustomizers) { - customizer.customize(cacheManager); - } - } + this.cacheManagerCustomizers + .forEach((customizer) -> customizer.customize(cacheManager)); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java index bfc9b4776a18..1fc46a844907 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.cassandra; import java.time.Duration; -import java.util.List; +import java.util.stream.Stream; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.PoolingOptions; @@ -51,12 +51,12 @@ public class CassandraAutoConfiguration { private final CassandraProperties properties; - private final List builderCustomizers; + private final Stream builderCustomizers; public CassandraAutoConfiguration(CassandraProperties properties, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { this.properties = properties; - this.builderCustomizers = builderCustomizers.getIfAvailable(); + this.builderCustomizers = builderCustomizers.orderedStream(); } @Bean @@ -88,11 +88,7 @@ public Cluster cassandraCluster() { } private void customize(Cluster.Builder builder) { - if (this.builderCustomizers != null) { - for (ClusterBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } - } + this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); } private QueryOptions getQueryOptions() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java index 8d5d33fa588a..15b763ab6d52 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -70,15 +70,10 @@ public org.neo4j.ogm.config.Configuration configuration(Neo4jProperties properti @Bean public SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration, ApplicationContext applicationContext, - ObjectProvider> eventListeners) { + ObjectProvider eventListeners) { SessionFactory sessionFactory = new SessionFactory(configuration, getPackagesToScan(applicationContext)); - List providedEventListeners = eventListeners.getIfAvailable(); - if (providedEventListeners != null) { - for (EventListener eventListener : providedEventListeners) { - sessionFactory.register(eventListener); - } - } + eventListeners.stream().forEach(sessionFactory::register); return sessionFactory; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java index e4d5a40b1720..21a19b136b2b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,8 +18,7 @@ import java.net.UnknownHostException; import java.time.Duration; -import java.util.Collections; -import java.util.List; +import java.util.stream.Stream; import org.apache.commons.pool2.impl.GenericObjectPool; import redis.clients.jedis.Jedis; @@ -51,16 +50,15 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { private final RedisProperties properties; - private final List builderCustomizers; + private final Stream builderCustomizers; JedisConnectionConfiguration(RedisProperties properties, ObjectProvider sentinelConfiguration, ObjectProvider clusterConfiguration, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { super(properties, sentinelConfiguration, clusterConfiguration); this.properties = properties; - this.builderCustomizers = builderCustomizers - .getIfAvailable(Collections::emptyList); + this.builderCustomizers = builderCustomizers.orderedStream(); } @Bean @@ -133,9 +131,7 @@ private void customizeConfigurationFromUrl( private void customize( JedisClientConfiguration.JedisClientConfigurationBuilder builder) { - for (JedisClientConfigurationBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } + this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index 7adbc364bde6..2bd846d5812b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -17,8 +17,7 @@ package org.springframework.boot.autoconfigure.data.redis; import java.net.UnknownHostException; -import java.util.Collections; -import java.util.List; +import java.util.stream.Stream; import io.lettuce.core.RedisClient; import io.lettuce.core.resource.ClientResources; @@ -52,16 +51,15 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { private final RedisProperties properties; - private final List builderCustomizers; + private final Stream builderCustomizers; LettuceConnectionConfiguration(RedisProperties properties, ObjectProvider sentinelConfigurationProvider, ObjectProvider clusterConfigurationProvider, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { super(properties, sentinelConfigurationProvider, clusterConfigurationProvider); this.properties = properties; - this.builderCustomizers = builderCustomizers - .getIfAvailable(Collections::emptyList); + this.builderCustomizers = builderCustomizers.orderedStream(); } @Bean(destroyMethod = "shutdown") @@ -139,9 +137,7 @@ private void customizeConfigurationFromUrl( private void customize( LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) { - for (LettuceClientConfigurationBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } + this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java index 02fa06ca9081..109f6d855841 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.elasticsearch.jest; import java.time.Duration; -import java.util.List; +import java.util.stream.Stream; import com.google.gson.Gson; import io.searchbox.client.JestClient; @@ -54,13 +54,13 @@ public class JestAutoConfiguration { private final ObjectProvider gsonProvider; - private final List builderCustomizers; + private final Stream builderCustomizers; public JestAutoConfiguration(JestProperties properties, ObjectProvider gson, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { this.properties = properties; this.gsonProvider = gson; - this.builderCustomizers = builderCustomizers.getIfAvailable(); + this.builderCustomizers = builderCustomizers.orderedStream(); } @Bean(destroyMethod = "shutdownClient") @@ -93,11 +93,7 @@ protected HttpClientConfig createHttpClientConfig() { } private void customize(HttpClientConfig.Builder builder) { - if (this.builderCustomizers != null) { - for (HttpClientConfigBuilderCustomizer customizer : this.builderCustomizers) { - customizer.customize(builder); - } - } + this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index 9598af3432dd..a46a58c75c2d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -16,8 +16,7 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; -import java.util.Collections; -import java.util.List; +import java.util.stream.Stream; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -51,13 +50,12 @@ public class RestClientAutoConfiguration { private final RestClientProperties properties; - private final List builderCustomizers; + private final Stream builderCustomizers; public RestClientAutoConfiguration(RestClientProperties properties, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { this.properties = properties; - this.builderCustomizers = builderCustomizers - .getIfAvailable(Collections::emptyList); + this.builderCustomizers = builderCustomizers.orderedStream(); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java index bd66b057a797..79482d75f2c5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set; import java.util.function.Supplier; +import java.util.stream.Collectors; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -92,9 +93,8 @@ public StringOrNumberToMigrationVersionConverter stringOrNumberMigrationVersionC @Bean public FlywaySchemaManagementProvider flywayDefaultDdlModeProvider( - ObjectProvider> flyways) { - return new FlywaySchemaManagementProvider( - flyways.getIfAvailable(Collections::emptyList)); + ObjectProvider flyways) { + return new FlywaySchemaManagementProvider(flyways); } @Configuration @@ -123,16 +123,17 @@ public FlywayConfiguration(FlywayProperties properties, ObjectProvider dataSource, @FlywayDataSource ObjectProvider flywayDataSource, ObjectProvider migrationStrategy, - ObjectProvider> callbacks, - ObjectProvider> flywayCallbacks) { + ObjectProvider callbacks, + ObjectProvider flywayCallbacks) { this.properties = properties; this.dataSourceProperties = dataSourceProperties; this.resourceLoader = resourceLoader; this.dataSource = dataSource.getIfUnique(); this.flywayDataSource = flywayDataSource.getIfAvailable(); this.migrationStrategy = migrationStrategy.getIfAvailable(); - this.callbacks = callbacks.getIfAvailable(Collections::emptyList); - this.flywayCallbacks = flywayCallbacks.getIfAvailable(Collections::emptyList); + this.callbacks = callbacks.orderedStream().collect(Collectors.toList()); + this.flywayCallbacks = flywayCallbacks.orderedStream() + .collect(Collectors.toList()); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywaySchemaManagementProvider.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywaySchemaManagementProvider.java index f31e92b2892a..47a75ca5de8a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywaySchemaManagementProvider.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/flyway/FlywaySchemaManagementProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,7 +16,7 @@ package org.springframework.boot.autoconfigure.flyway; -import java.util.List; +import java.util.stream.StreamSupport; import javax.sql.DataSource; @@ -33,20 +33,18 @@ */ class FlywaySchemaManagementProvider implements SchemaManagementProvider { - private final List flywayInstances; + private final Iterable flywayInstances; - FlywaySchemaManagementProvider(List flywayInstances) { + FlywaySchemaManagementProvider(Iterable flywayInstances) { this.flywayInstances = flywayInstances; } @Override public SchemaManagement getSchemaManagement(DataSource dataSource) { - for (Flyway flywayInstance : this.flywayInstances) { - if (dataSource.equals(flywayInstance.getDataSource())) { - return SchemaManagement.MANAGED; - } - } - return SchemaManagement.UNMANAGED; + return StreamSupport.stream(this.flywayInstances.spliterator(), false) + .map(Flyway::getDataSource).filter(dataSource::equals).findFirst() + .map((managedDataSource) -> SchemaManagement.MANAGED) + .orElse(SchemaManagement.UNMANAGED); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java index 6a50195520c7..d412a1d46367 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java @@ -16,8 +16,8 @@ package org.springframework.boot.autoconfigure.http; -import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -61,15 +61,14 @@ public class HttpMessageConvertersAutoConfiguration { private final List> converters; public HttpMessageConvertersAutoConfiguration( - ObjectProvider>> convertersProvider) { - this.converters = convertersProvider.getIfAvailable(); + ObjectProvider> convertersProvider) { + this.converters = convertersProvider.orderedStream().collect(Collectors.toList()); } @Bean @ConditionalOnMissingBean public HttpMessageConverters messageConverters() { - return new HttpMessageConverters( - (this.converters != null) ? this.converters : Collections.emptyList()); + return new HttpMessageConverters(this.converters); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java index fd8a54779f5d..2d5b2923abfa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java @@ -18,7 +18,7 @@ import java.util.Arrays; import java.util.EnumSet; -import java.util.List; +import java.util.stream.Stream; import javax.annotation.PostConstruct; import javax.servlet.DispatcherType; @@ -60,7 +60,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.Order; import org.springframework.util.ClassUtils; @@ -94,15 +93,15 @@ public class JerseyAutoConfiguration implements ServletContextAware { private final ResourceConfig config; - private final List customizers; + private final Stream customizers; private String path; public JerseyAutoConfiguration(JerseyProperties jersey, ResourceConfig config, - ObjectProvider> customizers) { + ObjectProvider customizers) { this.jersey = jersey; this.config = config; - this.customizers = customizers.getIfAvailable(); + this.customizers = customizers.orderedStream(); } @PostConstruct @@ -122,12 +121,7 @@ private void resolveApplicationPath() { } private void customize() { - if (this.customizers != null) { - AnnotationAwareOrderComparator.sort(this.customizers); - for (ResourceConfigCustomizer customizer : this.customizers) { - customizer.customize(this.config); - } - } + this.customizers.forEach((customizer) -> customizer.customize(this.config)); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java index 3eeaddceb42b..a7116b379f73 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQConnectionFactoryConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.boot.autoconfigure.jms.activemq; import java.util.List; +import java.util.stream.Collectors; import javax.jms.ConnectionFactory; @@ -61,11 +62,11 @@ static class SimpleConnectionFactoryConfiguration { SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties, ActiveMQProperties properties, - ObjectProvider> connectionFactoryCustomizers) { + ObjectProvider connectionFactoryCustomizers) { this.jmsProperties = jmsProperties; this.properties = properties; this.connectionFactoryCustomizers = connectionFactoryCustomizers - .getIfAvailable(); + .orderedStream().collect(Collectors.toList()); } @Bean @@ -102,9 +103,10 @@ static class PooledConnectionFactoryConfiguration { @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false) public JmsPoolConnectionFactory pooledJmsConnectionFactory( ActiveMQProperties properties, - ObjectProvider> factoryCustomizers) { + ObjectProvider factoryCustomizers) { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory( - properties, factoryCustomizers.getIfAvailable()) + properties, + factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ActiveMQConnectionFactory.class); return new JmsPoolConnectionFactoryFactory(properties.getPool()) .createPooledConnectionFactory(connectionFactory); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQXAConnectionFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQXAConnectionFactoryConfiguration.java index 42d2506e9430..dcb9aa62fe58 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQXAConnectionFactoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQXAConnectionFactoryConfiguration.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.jms.activemq; -import java.util.List; +import java.util.stream.Collectors; import javax.jms.ConnectionFactory; import javax.transaction.TransactionManager; @@ -50,10 +50,11 @@ class ActiveMQXAConnectionFactoryConfiguration { @Primary @Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" }) public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties, - ObjectProvider> factoryCustomizers, + ObjectProvider factoryCustomizers, XAConnectionFactoryWrapper wrapper) throws Exception { ActiveMQXAConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory( - properties, factoryCustomizers.getIfAvailable()) + properties, + factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ActiveMQXAConnectionFactory.class); return wrapper.wrapConnectionFactory(connectionFactory); } @@ -62,9 +63,9 @@ public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties, @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true) public ActiveMQConnectionFactory nonXaJmsConnectionFactory( ActiveMQProperties properties, - ObjectProvider> factoryCustomizers) { + ObjectProvider factoryCustomizers) { return new ActiveMQConnectionFactoryFactory(properties, - factoryCustomizers.getIfAvailable()) + factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ActiveMQConnectionFactory.class); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java index 938875f9bf0b..d6847cafa304 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,6 +18,8 @@ import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.activemq.artemis.jms.server.config.JMSConfiguration; import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration; @@ -33,7 +35,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; /** * Configuration used to create the embedded Artemis server. @@ -49,20 +50,22 @@ class ArtemisEmbeddedServerConfiguration { private final ArtemisProperties properties; - private final List configurationCustomizers; + private final Stream configurationCustomizers; private final List queuesConfiguration; private final List topicsConfiguration; ArtemisEmbeddedServerConfiguration(ArtemisProperties properties, - ObjectProvider> configurationCustomizers, - ObjectProvider> queuesConfiguration, - ObjectProvider> topicsConfiguration) { + ObjectProvider configurationCustomizers, + ObjectProvider queuesConfiguration, + ObjectProvider topicsConfiguration) { this.properties = properties; - this.configurationCustomizers = configurationCustomizers.getIfAvailable(); - this.queuesConfiguration = queuesConfiguration.getIfAvailable(); - this.topicsConfiguration = topicsConfiguration.getIfAvailable(); + this.configurationCustomizers = configurationCustomizers.orderedStream(); + this.queuesConfiguration = queuesConfiguration.orderedStream() + .collect(Collectors.toList()); + this.topicsConfiguration = topicsConfiguration.orderedStream() + .collect(Collectors.toList()); } @Bean @@ -87,12 +90,8 @@ public EmbeddedJMS artemisServer( private void customize( org.apache.activemq.artemis.core.config.Configuration configuration) { - if (this.configurationCustomizers != null) { - AnnotationAwareOrderComparator.sort(this.configurationCustomizers); - for (ArtemisConfigurationCustomizer customizer : this.configurationCustomizers) { - customizer.customize(configuration); - } - } + this.configurationCustomizers + .forEach((customizer) -> customizer.customize(configuration)); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java index 06675abae97a..cb42a581ae73 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration.java @@ -17,8 +17,6 @@ package org.springframework.boot.autoconfigure.liquibase; import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; import java.util.function.Supplier; import javax.annotation.PostConstruct; @@ -75,9 +73,8 @@ public class LiquibaseAutoConfiguration { @Bean public LiquibaseSchemaManagementProvider liquibaseDefaultDdlModeProvider( - ObjectProvider> liquibases) { - return new LiquibaseSchemaManagementProvider( - liquibases.getIfAvailable(Collections::emptyList)); + ObjectProvider liquibases) { + return new LiquibaseSchemaManagementProvider(liquibases); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseSchemaManagementProvider.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseSchemaManagementProvider.java index 53aebf892766..773d40c63cdc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseSchemaManagementProvider.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/liquibase/LiquibaseSchemaManagementProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,12 +16,13 @@ package org.springframework.boot.autoconfigure.liquibase; -import java.util.List; +import java.util.stream.StreamSupport; import javax.sql.DataSource; import liquibase.integration.spring.SpringLiquibase; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.jdbc.SchemaManagement; import org.springframework.boot.jdbc.SchemaManagementProvider; @@ -33,20 +34,18 @@ */ class LiquibaseSchemaManagementProvider implements SchemaManagementProvider { - private final List liquibaseInstances; + private final Iterable liquibaseInstances; - LiquibaseSchemaManagementProvider(List liquibases) { + LiquibaseSchemaManagementProvider(ObjectProvider liquibases) { this.liquibaseInstances = liquibases; } @Override public SchemaManagement getSchemaManagement(DataSource dataSource) { - for (SpringLiquibase liquibaseInstance : this.liquibaseInstances) { - if (dataSource.equals(liquibaseInstance.getDataSource())) { - return SchemaManagement.MANAGED; - } - } - return SchemaManagement.UNMANAGED; + return StreamSupport.stream(this.liquibaseInstances.spliterator(), false) + .map(SpringLiquibase::getDataSource).filter(dataSource::equals) + .findFirst().map((managedDataSource) -> SchemaManagement.MANAGED) + .orElse(SchemaManagement.UNMANAGED); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java index 503889532442..390edb1007d2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoReactiveAutoConfiguration.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.mongo; -import java.util.List; +import java.util.stream.Collectors; import javax.annotation.PreDestroy; @@ -68,9 +68,10 @@ public void close() { @ConditionalOnMissingBean public MongoClient reactiveStreamsMongoClient(MongoProperties properties, Environment environment, - ObjectProvider> builderCustomizers) { + ObjectProvider builderCustomizers) { ReactiveMongoClientFactory factory = new ReactiveMongoClientFactory(properties, - environment, builderCustomizers.getIfAvailable()); + environment, + builderCustomizers.orderedStream().collect(Collectors.toList())); this.mongo = factory.createMongoClient(this.settings); return this.mongo; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProvider.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProvider.java index f5ea37656300..eb1c72e6f8cb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProvider.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,7 +16,7 @@ package org.springframework.boot.autoconfigure.orm.jpa; -import java.util.List; +import java.util.stream.StreamSupport; import javax.sql.DataSource; @@ -32,9 +32,9 @@ */ class HibernateDefaultDdlAutoProvider implements SchemaManagementProvider { - private final List providers; + private final Iterable providers; - HibernateDefaultDdlAutoProvider(List providers) { + HibernateDefaultDdlAutoProvider(Iterable providers) { this.providers = providers; } @@ -52,13 +52,10 @@ public String getDefaultDdlAuto(DataSource dataSource) { @Override public SchemaManagement getSchemaManagement(DataSource dataSource) { - for (SchemaManagementProvider provider : this.providers) { - SchemaManagement schemaManagement = provider.getSchemaManagement(dataSource); - if (SchemaManagement.MANAGED.equals(schemaManagement)) { - return schemaManagement; - } - } - return SchemaManagement.UNMANAGED; + return StreamSupport.stream(this.providers.spliterator(), false) + .map((provider) -> provider.getSchemaManagement(dataSource)) + .filter(SchemaManagement.MANAGED::equals).findFirst() + .orElse(SchemaManagement.UNMANAGED); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 64b189196072..b468a6f875cc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -18,12 +18,12 @@ import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Supplier; +import java.util.stream.Collectors; import javax.sql.DataSource; @@ -89,21 +89,20 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { ObjectProvider transactionManagerCustomizers, HibernateProperties hibernateProperties, ObjectProvider> metadataProviders, - ObjectProvider> providers, + ObjectProvider providers, ObjectProvider physicalNamingStrategy, ObjectProvider implicitNamingStrategy, - ObjectProvider> hibernatePropertiesCustomizers) { + ObjectProvider hibernatePropertiesCustomizers) { super(dataSource, jpaProperties, jtaTransactionManager, transactionManagerCustomizers); this.hibernateProperties = hibernateProperties; - this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider( - providers.getIfAvailable(Collections::emptyList)); + this.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(providers); this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider( metadataProviders.getIfAvailable()); this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers( physicalNamingStrategy.getIfAvailable(), - implicitNamingStrategy.getIfAvailable(), - hibernatePropertiesCustomizers.getIfAvailable(Collections::emptyList)); + implicitNamingStrategy.getIfAvailable(), hibernatePropertiesCustomizers + .orderedStream().collect(Collectors.toList())); } private List determineHibernatePropertiesCustomizers( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index d7dd669813ba..56a03693751d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.orm.jpa; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -121,14 +120,12 @@ public JpaVendorAdapter jpaVendorAdapter() { public EntityManagerFactoryBuilder entityManagerFactoryBuilder( JpaVendorAdapter jpaVendorAdapter, ObjectProvider persistenceUnitManager, - ObjectProvider> customizers) { + ObjectProvider customizers) { EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder( jpaVendorAdapter, this.properties.getProperties(), persistenceUnitManager.getIfAvailable()); - for (EntityManagerFactoryBuilderCustomizer customizer : customizers - .getIfAvailable(Collections::emptyList)) { - customizer.customize(builder); - } + customizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); return builder; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 658010ae7c39..0f9ff19bc476 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -16,9 +16,9 @@ package org.springframework.boot.autoconfigure.quartz; -import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.stream.Stream; import javax.sql.DataSource; @@ -61,7 +61,7 @@ public class QuartzAutoConfiguration { private final QuartzProperties properties; - private final List customizers; + private final Stream customizers; private final JobDetail[] jobDetails; @@ -72,12 +72,12 @@ public class QuartzAutoConfiguration { private final ApplicationContext applicationContext; public QuartzAutoConfiguration(QuartzProperties properties, - ObjectProvider> customizers, + ObjectProvider customizers, ObjectProvider jobDetails, ObjectProvider> calendars, ObjectProvider triggers, ApplicationContext applicationContext) { this.properties = properties; - this.customizers = customizers.getIfAvailable(); + this.customizers = customizers.orderedStream(); this.jobDetails = jobDetails.getIfAvailable(); this.calendars = calendars.getIfAvailable(); this.triggers = triggers.getIfAvailable(); @@ -124,11 +124,8 @@ private Properties asProperties(Map source) { } private void customize(SchedulerFactoryBean schedulerFactoryBean) { - if (this.customizers != null) { - for (SchedulerFactoryBeanCustomizer customizer : this.customizers) { - customizer.customize(schedulerFactoryBean); - } - } + this.customizers + .forEach((customizer) -> customizer.customize(schedulerFactoryBean)); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 97c9d783a665..97e308db1d94 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -17,8 +17,8 @@ package org.springframework.boot.autoconfigure.thymeleaf; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; +import java.util.stream.Stream; import javax.annotation.PostConstruct; @@ -136,14 +136,14 @@ protected static class ThymeleafDefaultConfiguration { private final Collection templateResolvers; - private final Collection dialects; + private final Stream dialects; public ThymeleafDefaultConfiguration(ThymeleafProperties properties, Collection templateResolvers, - ObjectProvider> dialectsProvider) { + ObjectProvider dialectsProvider) { this.properties = properties; this.templateResolvers = templateResolvers; - this.dialects = dialectsProvider.getIfAvailable(Collections::emptyList); + this.dialects = dialectsProvider.orderedStream(); } @Bean @@ -224,14 +224,14 @@ static class ThymeleafReactiveConfiguration { private final Collection templateResolvers; - private final Collection dialects; + private final Stream dialects; ThymeleafReactiveConfiguration(ThymeleafProperties properties, Collection templateResolvers, - ObjectProvider> dialectsProvider) { + ObjectProvider dialectsProvider) { this.properties = properties; this.templateResolvers = templateResolvers; - this.dialects = dialectsProvider.getIfAvailable(Collections::emptyList); + this.dialects = dialectsProvider.orderedStream(); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java index 2f65e1c1464a..4a0b3ad202e8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/transaction/TransactionAutoConfiguration.java @@ -16,7 +16,7 @@ package org.springframework.boot.autoconfigure.transaction; -import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -55,8 +55,9 @@ public class TransactionAutoConfiguration { @Bean @ConditionalOnMissingBean public TransactionManagerCustomizers platformTransactionManagerCustomizers( - ObjectProvider>> customizers) { - return new TransactionManagerCustomizers(customizers.getIfAvailable()); + ObjectProvider> customizers) { + return new TransactionManagerCustomizers( + customizers.orderedStream().collect(Collectors.toList())); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.java index b35208c93c2a..620f044e0a5c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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,8 +16,8 @@ package org.springframework.boot.autoconfigure.web.client; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -30,7 +30,6 @@ import org.springframework.boot.web.client.RestTemplateCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; @@ -48,11 +47,11 @@ public class RestTemplateAutoConfiguration { private final ObjectProvider messageConverters; - private final ObjectProvider> restTemplateCustomizers; + private final ObjectProvider restTemplateCustomizers; public RestTemplateAutoConfiguration( ObjectProvider messageConverters, - ObjectProvider> restTemplateCustomizers) { + ObjectProvider restTemplateCustomizers) { this.messageConverters = messageConverters; this.restTemplateCustomizers = restTemplateCustomizers; } @@ -65,11 +64,10 @@ public RestTemplateBuilder restTemplateBuilder() { if (converters != null) { builder = builder.messageConverters(converters.getConverters()); } + List customizers = this.restTemplateCustomizers - .getIfAvailable(); + .orderedStream().collect(Collectors.toList()); if (!CollectionUtils.isEmpty(customizers)) { - customizers = new ArrayList<>(customizers); - AnnotationAwareOrderComparator.sort(customizers); builder = builder.customizers(customizers); } return builder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index bc8e2a38a591..a58463aebe0b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -18,8 +18,8 @@ import java.time.Duration; import java.util.Collection; -import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -46,7 +46,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.format.Formatter; @@ -115,43 +114,39 @@ public static class WebFluxConfig implements WebFluxConfigurer { private final ListableBeanFactory beanFactory; - private final List argumentResolvers; + private final Stream argumentResolvers; - private final List codecCustomizers; + private final Stream codecCustomizers; private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer; - private final List viewResolvers; + private final Stream viewResolvers; public WebFluxConfig(ResourceProperties resourceProperties, WebFluxProperties webFluxProperties, ListableBeanFactory beanFactory, - ObjectProvider> resolvers, - ObjectProvider> codecCustomizers, + ObjectProvider resolvers, + ObjectProvider codecCustomizers, ObjectProvider resourceHandlerRegistrationCustomizer, - ObjectProvider> viewResolvers) { + ObjectProvider viewResolvers) { this.resourceProperties = resourceProperties; this.webFluxProperties = webFluxProperties; this.beanFactory = beanFactory; - this.argumentResolvers = resolvers.getIfAvailable(); - this.codecCustomizers = codecCustomizers.getIfAvailable(); + this.argumentResolvers = resolvers.orderedStream(); + this.codecCustomizers = codecCustomizers.orderedStream(); this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizer .getIfAvailable(); - this.viewResolvers = viewResolvers.getIfAvailable(); + this.viewResolvers = viewResolvers.orderedStream(); } @Override public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { - if (this.argumentResolvers != null) { - this.argumentResolvers.forEach(configurer::addCustomResolver); - } + this.argumentResolvers.forEach(configurer::addCustomResolver); } @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { - if (this.codecCustomizers != null) { - this.codecCustomizers - .forEach((customizer) -> customizer.customize(configurer)); - } + this.codecCustomizers + .forEach((customizer) -> customizer.customize(configurer)); } @Override @@ -186,10 +181,7 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { @Override public void configureViewResolvers(ViewResolverRegistry registry) { - if (this.viewResolvers != null) { - AnnotationAwareOrderComparator.sort(this.viewResolvers); - this.viewResolvers.forEach(registry::viewResolver); - } + this.viewResolvers.forEach(registry::viewResolver); } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/ErrorWebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/ErrorWebFluxAutoConfiguration.java index 81d14a8e9435..40d66dd0102d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/ErrorWebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/error/ErrorWebFluxAutoConfiguration.java @@ -16,8 +16,8 @@ package org.springframework.boot.autoconfigure.web.reactive.error; -import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureBefore; @@ -67,14 +67,14 @@ public class ErrorWebFluxAutoConfiguration { public ErrorWebFluxAutoConfiguration(ServerProperties serverProperties, ResourceProperties resourceProperties, - ObjectProvider> viewResolversProvider, + ObjectProvider viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) { this.serverProperties = serverProperties; this.applicationContext = applicationContext; this.resourceProperties = resourceProperties; - this.viewResolvers = viewResolversProvider - .getIfAvailable(() -> Collections.emptyList()); + this.viewResolvers = viewResolversProvider.orderedStream() + .collect(Collectors.toList()); this.serverCodecConfigurer = serverCodecConfigurer; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java index f775d4061254..81123298e2da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/WebClientAutoConfiguration.java @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.web.reactive.function.client; -import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.ObjectProvider; @@ -31,9 +30,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; -import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.client.WebClient; /** @@ -56,15 +53,10 @@ public class WebClientAutoConfiguration { private final WebClient.Builder webClientBuilder; public WebClientAutoConfiguration( - ObjectProvider> customizerProvider) { + ObjectProvider customizerProvider) { this.webClientBuilder = WebClient.builder(); - List customizers = customizerProvider.getIfAvailable(); - if (!CollectionUtils.isEmpty(customizers)) { - customizers = new ArrayList<>(customizers); - AnnotationAwareOrderComparator.sort(customizers); - customizers - .forEach((customizer) -> customizer.customize(this.webClientBuilder)); - } + customizerProvider.orderedStream() + .forEach((customizer) -> customizer.customize(this.webClientBuilder)); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java index 7622691600a7..d1f6a8a527ef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.servlet.Servlet; import javax.servlet.http.HttpServletRequest; @@ -103,10 +104,11 @@ public class ErrorMvcAutoConfiguration { public ErrorMvcAutoConfiguration(ServerProperties serverProperties, DispatcherServletPath dispatcherServletPath, - ObjectProvider> errorViewResolversProvider) { + ObjectProvider errorViewResolvers) { this.serverProperties = serverProperties; this.dispatcherServletPath = dispatcherServletPath; - this.errorViewResolvers = errorViewResolversProvider.getIfAvailable(); + this.errorViewResolvers = errorViewResolvers.orderedStream() + .collect(Collectors.toList()); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java index d7a2edfeb244..ced2ec830adb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java @@ -16,8 +16,8 @@ package org.springframework.boot.autoconfigure.webservices.client; -import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -27,7 +27,6 @@ import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.CollectionUtils; @@ -43,10 +42,10 @@ @ConditionalOnClass({ WebServiceTemplate.class, Unmarshaller.class, Marshaller.class }) public class WebServiceTemplateAutoConfiguration { - private final ObjectProvider> webServiceTemplateCustomizers; + private final ObjectProvider webServiceTemplateCustomizers; public WebServiceTemplateAutoConfiguration( - ObjectProvider> webServiceTemplateCustomizers) { + ObjectProvider webServiceTemplateCustomizers) { this.webServiceTemplateCustomizers = webServiceTemplateCustomizers; } @@ -55,10 +54,8 @@ public WebServiceTemplateAutoConfiguration( public WebServiceTemplateBuilder webServiceTemplateBuilder() { WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); List customizers = this.webServiceTemplateCustomizers - .getIfAvailable(); + .orderedStream().collect(Collectors.toList()); if (!CollectionUtils.isEmpty(customizers)) { - customizers = new ArrayList<>(customizers); - AnnotationAwareOrderComparator.sort(customizers); builder = builder.customizers(customizers); } return builder; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java index 65f693f427c8..5045fde148c7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateDefaultDdlAutoProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java index 03ff7808e604..ecef410f02d6 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/restdocs/RestDocsAutoConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.test.autoconfigure.restdocs; -import java.util.List; - import io.restassured.builder.RequestSpecBuilder; import io.restassured.specification.RequestSpecification; @@ -60,17 +58,13 @@ static class RestDocsMockMvcConfiguration { @Bean @ConditionalOnMissingBean public MockMvcRestDocumentationConfigurer restDocsMockMvcConfigurer( - ObjectProvider> configurationCustomizerProvider, + ObjectProvider configurationCustomizers, RestDocumentationContextProvider contextProvider) { MockMvcRestDocumentationConfigurer configurer = MockMvcRestDocumentation .documentationConfiguration(contextProvider); - List configurationCustomizers = configurationCustomizerProvider - .getIfAvailable(); - if (configurationCustomizers != null) { - configurationCustomizers - .forEach((configurationCustomizer) -> configurationCustomizer - .customize(configurer)); - } + configurationCustomizers.orderedStream() + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); return configurer; } @@ -94,17 +88,13 @@ static class RestDocsRestAssuredConfiguration { @Bean @ConditionalOnMissingBean public RequestSpecification restDocsRestAssuredConfigurer( - ObjectProvider> configurationCustomizerProvider, + ObjectProvider configurationCustomizers, RestDocumentationContextProvider contextProvider) { RestAssuredRestDocumentationConfigurer configurer = RestAssuredRestDocumentation .documentationConfiguration(contextProvider); - List configurationCustomizers = configurationCustomizerProvider - .getIfAvailable(); - if (configurationCustomizers != null) { - configurationCustomizers - .forEach((configurationCustomizer) -> configurationCustomizer - .customize(configurer)); - } + configurationCustomizers.orderedStream() + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); return new RequestSpecBuilder().addFilter(configurer).build(); } @@ -125,17 +115,13 @@ static class RestDocsWebTestClientConfiguration { @Bean @ConditionalOnMissingBean public WebTestClientRestDocumentationConfigurer restDocsWebTestClientConfigurer( - ObjectProvider> configurationCustomizerProvider, + ObjectProvider configurationCustomizers, RestDocumentationContextProvider contextProvider) { WebTestClientRestDocumentationConfigurer configurer = WebTestClientRestDocumentation .documentationConfiguration(contextProvider); - List configurationCustomizers = configurationCustomizerProvider - .getIfAvailable(); - if (configurationCustomizers != null) { - configurationCustomizers - .forEach((configurationCustomizer) -> configurationCustomizer - .customize(configurer)); - } + configurationCustomizers.orderedStream() + .forEach((configurationCustomizer) -> configurationCustomizer + .customize(configurer)); return configurer; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java index 2eaa216ce96a..adcadcf1b62e 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java @@ -16,9 +16,8 @@ package org.springframework.boot.test.autoconfigure.web.reactive; -import java.util.Collection; -import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -74,9 +73,9 @@ public WebTestClient webTestClient(ApplicationContext applicationContext, @Bean @ConfigurationProperties(prefix = "spring.test.webtestclient") public SpringBootWebTestClientBuilderCustomizer springBootWebTestClientBuilderCustomizer( - ObjectProvider> codecCustomizers) { + ObjectProvider codecCustomizers) { return new SpringBootWebTestClientBuilderCustomizer( - codecCustomizers.getIfAvailable(Collections::emptyList)); + codecCustomizers.orderedStream().collect(Collectors.toList())); } } From 426ff3ada742d5f79d7ffd23bc187ea937a15147 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 20 Sep 2018 16:16:42 +0100 Subject: [PATCH 651/701] Store ObjectProvider rather than their Streams to allow reuse Generally speaking, methods on configuration classes will only be called once and, therefore, it should be safe to hold a reference to a Stream for later one-time usage. However, there are some scenarios in Spring Fu where functional registration results in an attempt being made to use a Stream more than use. This commit protects against multiple use by storing the ObjectProvider and getting a new ordered Stream each time it's needed. Closes gh-14467 --- ...eyManagementChildContextConfiguration.java | 8 +++----- .../cache/JCacheCacheConfiguration.java | 13 ++++++------- .../cassandra/CassandraAutoConfiguration.java | 8 ++++---- .../redis/JedisConnectionConfiguration.java | 8 ++++---- .../redis/LettuceConnectionConfiguration.java | 8 ++++---- .../jest/JestAutoConfiguration.java | 8 ++++---- .../rest/RestClientAutoConfiguration.java | 9 ++++----- .../jersey/JerseyAutoConfiguration.java | 8 ++++---- .../ArtemisEmbeddedServerConfiguration.java | 7 +++---- .../quartz/QuartzAutoConfiguration.java | 7 +++---- .../thymeleaf/ThymeleafAutoConfiguration.java | 13 ++++++------- .../reactive/WebFluxAutoConfiguration.java | 19 +++++++++---------- 12 files changed, 54 insertions(+), 62 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java index c9375606bf0d..1497d8dee855 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/jersey/JerseyManagementChildContextConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.autoconfigure.web.jersey; -import java.util.stream.Stream; - import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; @@ -47,11 +45,11 @@ @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet") public class JerseyManagementChildContextConfiguration { - private final Stream resourceConfigCustomizers; + private final ObjectProvider resourceConfigCustomizers; public JerseyManagementChildContextConfiguration( ObjectProvider resourceConfigCustomizers) { - this.resourceConfigCustomizers = resourceConfigCustomizers.orderedStream(); + this.resourceConfigCustomizers = resourceConfigCustomizers; } @Bean @@ -63,7 +61,7 @@ public ServletRegistrationBean jerseyServletRegistration() { @Bean public ResourceConfig endpointResourceConfig() { ResourceConfig resourceConfig = new ResourceConfig(); - this.resourceConfigCustomizers + this.resourceConfigCustomizers.orderedStream() .forEach((customizer) -> customizer.customize(resourceConfig)); return resourceConfig; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java index 76039134583c..737ac55fac9a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.java @@ -20,7 +20,6 @@ import java.util.Iterator; import java.util.List; import java.util.Properties; -import java.util.stream.Stream; import javax.cache.CacheManager; import javax.cache.Caching; @@ -70,9 +69,9 @@ class JCacheCacheConfiguration implements BeanClassLoaderAware { private final javax.cache.configuration.Configuration defaultCacheConfiguration; - private final Stream cacheManagerCustomizers; + private final ObjectProvider cacheManagerCustomizers; - private final Stream cachePropertiesCustomizers; + private final ObjectProvider cachePropertiesCustomizers; private ClassLoader beanClassLoader; @@ -84,8 +83,8 @@ class JCacheCacheConfiguration implements BeanClassLoaderAware { this.cacheProperties = cacheProperties; this.customizers = customizers; this.defaultCacheConfiguration = defaultCacheConfiguration.getIfAvailable(); - this.cacheManagerCustomizers = cacheManagerCustomizers.orderedStream(); - this.cachePropertiesCustomizers = cachePropertiesCustomizers.orderedStream(); + this.cacheManagerCustomizers = cacheManagerCustomizers; + this.cachePropertiesCustomizers = cachePropertiesCustomizers; } @Override @@ -135,7 +134,7 @@ private CachingProvider getCachingProvider(String cachingProviderFqn) { private Properties createCacheManagerProperties() { Properties properties = new Properties(); - this.cachePropertiesCustomizers.forEach( + this.cachePropertiesCustomizers.orderedStream().forEach( (customizer) -> customizer.customize(this.cacheProperties, properties)); return properties; } @@ -148,7 +147,7 @@ private Properties createCacheManagerProperties() { } private void customize(CacheManager cacheManager) { - this.cacheManagerCustomizers + this.cacheManagerCustomizers.orderedStream() .forEach((customizer) -> customizer.customize(cacheManager)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java index 1fc46a844907..551b9cddfd04 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.cassandra; import java.time.Duration; -import java.util.stream.Stream; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.PoolingOptions; @@ -51,12 +50,12 @@ public class CassandraAutoConfiguration { private final CassandraProperties properties; - private final Stream builderCustomizers; + private final ObjectProvider builderCustomizers; public CassandraAutoConfiguration(CassandraProperties properties, ObjectProvider builderCustomizers) { this.properties = properties; - this.builderCustomizers = builderCustomizers.orderedStream(); + this.builderCustomizers = builderCustomizers; } @Bean @@ -88,7 +87,8 @@ public Cluster cassandraCluster() { } private void customize(Cluster.Builder builder) { - this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + this.builderCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); } private QueryOptions getQueryOptions() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java index 21a19b136b2b..b98d33e7f40b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java @@ -18,7 +18,6 @@ import java.net.UnknownHostException; import java.time.Duration; -import java.util.stream.Stream; import org.apache.commons.pool2.impl.GenericObjectPool; import redis.clients.jedis.Jedis; @@ -50,7 +49,7 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { private final RedisProperties properties; - private final Stream builderCustomizers; + private final ObjectProvider builderCustomizers; JedisConnectionConfiguration(RedisProperties properties, ObjectProvider sentinelConfiguration, @@ -58,7 +57,7 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { ObjectProvider builderCustomizers) { super(properties, sentinelConfiguration, clusterConfiguration); this.properties = properties; - this.builderCustomizers = builderCustomizers.orderedStream(); + this.builderCustomizers = builderCustomizers; } @Bean @@ -131,7 +130,8 @@ private void customizeConfigurationFromUrl( private void customize( JedisClientConfiguration.JedisClientConfigurationBuilder builder) { - this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + this.builderCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index 2bd846d5812b..bbf03afe8476 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.data.redis; import java.net.UnknownHostException; -import java.util.stream.Stream; import io.lettuce.core.RedisClient; import io.lettuce.core.resource.ClientResources; @@ -51,7 +50,7 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { private final RedisProperties properties; - private final Stream builderCustomizers; + private final ObjectProvider builderCustomizers; LettuceConnectionConfiguration(RedisProperties properties, ObjectProvider sentinelConfigurationProvider, @@ -59,7 +58,7 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { ObjectProvider builderCustomizers) { super(properties, sentinelConfigurationProvider, clusterConfigurationProvider); this.properties = properties; - this.builderCustomizers = builderCustomizers.orderedStream(); + this.builderCustomizers = builderCustomizers; } @Bean(destroyMethod = "shutdown") @@ -137,7 +136,8 @@ private void customizeConfigurationFromUrl( private void customize( LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) { - this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + this.builderCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java index 109f6d855841..eb9a78bc9469 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.elasticsearch.jest; import java.time.Duration; -import java.util.stream.Stream; import com.google.gson.Gson; import io.searchbox.client.JestClient; @@ -54,13 +53,13 @@ public class JestAutoConfiguration { private final ObjectProvider gsonProvider; - private final Stream builderCustomizers; + private final ObjectProvider builderCustomizers; public JestAutoConfiguration(JestProperties properties, ObjectProvider gson, ObjectProvider builderCustomizers) { this.properties = properties; this.gsonProvider = gson; - this.builderCustomizers = builderCustomizers.orderedStream(); + this.builderCustomizers = builderCustomizers; } @Bean(destroyMethod = "shutdownClient") @@ -93,7 +92,8 @@ protected HttpClientConfig createHttpClientConfig() { } private void customize(HttpClientConfig.Builder builder) { - this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + this.builderCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java index a46a58c75c2d..817f59028391 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/rest/RestClientAutoConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.elasticsearch.rest; -import java.util.stream.Stream; - import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; @@ -50,12 +48,12 @@ public class RestClientAutoConfiguration { private final RestClientProperties properties; - private final Stream builderCustomizers; + private final ObjectProvider builderCustomizers; public RestClientAutoConfiguration(RestClientProperties properties, ObjectProvider builderCustomizers) { this.properties = properties; - this.builderCustomizers = builderCustomizers.orderedStream(); + this.builderCustomizers = builderCustomizers; } @Bean @@ -79,7 +77,8 @@ public RestClientBuilder restClientBuilder() { builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder .setDefaultCredentialsProvider(credentialsProvider)); }); - this.builderCustomizers.forEach((customizer) -> customizer.customize(builder)); + this.builderCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(builder)); return builder; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java index 2d5b2923abfa..f6bf034c377b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java @@ -18,7 +18,6 @@ import java.util.Arrays; import java.util.EnumSet; -import java.util.stream.Stream; import javax.annotation.PostConstruct; import javax.servlet.DispatcherType; @@ -93,7 +92,7 @@ public class JerseyAutoConfiguration implements ServletContextAware { private final ResourceConfig config; - private final Stream customizers; + private final ObjectProvider customizers; private String path; @@ -101,7 +100,7 @@ public JerseyAutoConfiguration(JerseyProperties jersey, ResourceConfig config, ObjectProvider customizers) { this.jersey = jersey; this.config = config; - this.customizers = customizers.orderedStream(); + this.customizers = customizers; } @PostConstruct @@ -121,7 +120,8 @@ private void resolveApplicationPath() { } private void customize() { - this.customizers.forEach((customizer) -> customizer.customize(this.config)); + this.customizers.orderedStream() + .forEach((customizer) -> customizer.customize(this.config)); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java index d6847cafa304..0faa74fe6fc8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisEmbeddedServerConfiguration.java @@ -19,7 +19,6 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.activemq.artemis.jms.server.config.JMSConfiguration; import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration; @@ -50,7 +49,7 @@ class ArtemisEmbeddedServerConfiguration { private final ArtemisProperties properties; - private final Stream configurationCustomizers; + private final ObjectProvider configurationCustomizers; private final List queuesConfiguration; @@ -61,7 +60,7 @@ class ArtemisEmbeddedServerConfiguration { ObjectProvider queuesConfiguration, ObjectProvider topicsConfiguration) { this.properties = properties; - this.configurationCustomizers = configurationCustomizers.orderedStream(); + this.configurationCustomizers = configurationCustomizers; this.queuesConfiguration = queuesConfiguration.orderedStream() .collect(Collectors.toList()); this.topicsConfiguration = topicsConfiguration.orderedStream() @@ -90,7 +89,7 @@ public EmbeddedJMS artemisServer( private void customize( org.apache.activemq.artemis.core.config.Configuration configuration) { - this.configurationCustomizers + this.configurationCustomizers.orderedStream() .forEach((customizer) -> customizer.customize(configuration)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 0f9ff19bc476..7e8f09bb00af 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -18,7 +18,6 @@ import java.util.Map; import java.util.Properties; -import java.util.stream.Stream; import javax.sql.DataSource; @@ -61,7 +60,7 @@ public class QuartzAutoConfiguration { private final QuartzProperties properties; - private final Stream customizers; + private final ObjectProvider customizers; private final JobDetail[] jobDetails; @@ -77,7 +76,7 @@ public QuartzAutoConfiguration(QuartzProperties properties, ObjectProvider> calendars, ObjectProvider triggers, ApplicationContext applicationContext) { this.properties = properties; - this.customizers = customizers.orderedStream(); + this.customizers = customizers; this.jobDetails = jobDetails.getIfAvailable(); this.calendars = calendars.getIfAvailable(); this.triggers = triggers.getIfAvailable(); @@ -124,7 +123,7 @@ private Properties asProperties(Map source) { } private void customize(SchedulerFactoryBean schedulerFactoryBean) { - this.customizers + this.customizers.orderedStream() .forEach((customizer) -> customizer.customize(schedulerFactoryBean)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 97e308db1d94..1490a2a94d48 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -18,7 +18,6 @@ import java.util.Collection; import java.util.LinkedHashMap; -import java.util.stream.Stream; import javax.annotation.PostConstruct; @@ -136,14 +135,14 @@ protected static class ThymeleafDefaultConfiguration { private final Collection templateResolvers; - private final Stream dialects; + private final ObjectProvider dialects; public ThymeleafDefaultConfiguration(ThymeleafProperties properties, Collection templateResolvers, ObjectProvider dialectsProvider) { this.properties = properties; this.templateResolvers = templateResolvers; - this.dialects = dialectsProvider.orderedStream(); + this.dialects = dialectsProvider; } @Bean @@ -152,7 +151,7 @@ public SpringTemplateEngine templateEngine() { SpringTemplateEngine engine = new SpringTemplateEngine(); engine.setEnableSpringELCompiler(this.properties.isEnableSpringElCompiler()); this.templateResolvers.forEach(engine::addTemplateResolver); - this.dialects.forEach(engine::addDialect); + this.dialects.orderedStream().forEach(engine::addDialect); return engine; } @@ -224,14 +223,14 @@ static class ThymeleafReactiveConfiguration { private final Collection templateResolvers; - private final Stream dialects; + private final ObjectProvider dialects; ThymeleafReactiveConfiguration(ThymeleafProperties properties, Collection templateResolvers, ObjectProvider dialectsProvider) { this.properties = properties; this.templateResolvers = templateResolvers; - this.dialects = dialectsProvider.orderedStream(); + this.dialects = dialectsProvider; } @Bean @@ -240,7 +239,7 @@ public SpringWebFluxTemplateEngine templateEngine() { SpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine(); engine.setEnableSpringELCompiler(this.properties.isEnableSpringElCompiler()); this.templateResolvers.forEach(engine::addTemplateResolver); - this.dialects.forEach(engine::addDialect); + this.dialects.orderedStream().forEach(engine::addDialect); return engine; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index a58463aebe0b..69c67aabb058 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -19,7 +19,6 @@ import java.time.Duration; import java.util.Collection; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -114,13 +113,13 @@ public static class WebFluxConfig implements WebFluxConfigurer { private final ListableBeanFactory beanFactory; - private final Stream argumentResolvers; + private final ObjectProvider argumentResolvers; - private final Stream codecCustomizers; + private final ObjectProvider codecCustomizers; private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer; - private final Stream viewResolvers; + private final ObjectProvider viewResolvers; public WebFluxConfig(ResourceProperties resourceProperties, WebFluxProperties webFluxProperties, ListableBeanFactory beanFactory, @@ -131,21 +130,21 @@ public WebFluxConfig(ResourceProperties resourceProperties, this.resourceProperties = resourceProperties; this.webFluxProperties = webFluxProperties; this.beanFactory = beanFactory; - this.argumentResolvers = resolvers.orderedStream(); - this.codecCustomizers = codecCustomizers.orderedStream(); + this.argumentResolvers = resolvers; + this.codecCustomizers = codecCustomizers; this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizer .getIfAvailable(); - this.viewResolvers = viewResolvers.orderedStream(); + this.viewResolvers = viewResolvers; } @Override public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { - this.argumentResolvers.forEach(configurer::addCustomResolver); + this.argumentResolvers.orderedStream().forEach(configurer::addCustomResolver); } @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { - this.codecCustomizers + this.codecCustomizers.orderedStream() .forEach((customizer) -> customizer.customize(configurer)); } @@ -181,7 +180,7 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) { @Override public void configureViewResolvers(ViewResolverRegistry registry) { - this.viewResolvers.forEach(registry::viewResolver); + this.viewResolvers.orderedStream().forEach(registry::viewResolver); } @Override From 624cd4059884bc48f39a7ab7487dd2c19cd60fd5 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 17 Sep 2018 10:44:20 -0700 Subject: [PATCH 652/701] Reduce GC pressure creating load descriptions Update `ConfigFileApplicationListener` to build description methods using a `StringBuilder` and not to use `String.format`. See gh-13436 --- .../config/ConfigFileApplicationListener.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 198f41c3a668..7ffcf21ee398 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -500,16 +500,19 @@ private void load(PropertySourceLoader loader, String location, Profile profile, Resource resource = this.resourceLoader.getResource(location); if (resource == null || !resource.exists()) { if (this.logger.isTraceEnabled()) { - this.logger.trace("Skipped missing config " - + getDescription(location, resource, profile)); + StringBuilder description = getDescription( + "Skipped missing config ", location, resource, profile); + this.logger.trace(description); } return; } if (!StringUtils.hasText( StringUtils.getFilenameExtension(resource.getFilename()))) { if (this.logger.isTraceEnabled()) { - this.logger.trace("Skipped empty config extension " - + getDescription(location, resource, profile)); + StringBuilder description = getDescription( + "Skipped empty config extension ", location, resource, + profile); + this.logger.trace(description); } return; } @@ -517,8 +520,9 @@ private void load(PropertySourceLoader loader, String location, Profile profile, List documents = loadDocuments(loader, name, resource); if (CollectionUtils.isEmpty(documents)) { if (this.logger.isTraceEnabled()) { - this.logger.trace("Skipped unloaded config " - + getDescription(location, resource, profile)); + StringBuilder description = getDescription( + "Skipped unloaded config ", location, resource, profile); + this.logger.trace(description); } return; } @@ -534,8 +538,9 @@ private void load(PropertySourceLoader loader, String location, Profile profile, if (!loaded.isEmpty()) { loaded.forEach((document) -> consumer.accept(profile, document)); if (this.logger.isDebugEnabled()) { - this.logger.debug("Loaded config file " - + getDescription(location, resource, profile)); + StringBuilder description = getDescription("Loaded config file ", + location, resource, profile); + this.logger.debug(description); } } } @@ -581,23 +586,27 @@ private List asDocuments(List> loaded) { }).collect(Collectors.toList()); } - private String getDescription(String location, Resource resource, - Profile profile) { - String description = getDescription(location, resource); - return (profile != null) ? description + " for profile " + profile - : description; - } - - private String getDescription(String location, Resource resource) { + private StringBuilder getDescription(String prefix, String location, + Resource resource, Profile profile) { + StringBuilder result = new StringBuilder(prefix); try { if (resource != null) { String uri = resource.getURI().toASCIIString(); - return String.format("'%s' (%s)", uri, location); + result.append("'"); + result.append(uri); + result.append("' ("); + result.append(location); + result.append(")"); } } catch (IOException ex) { + result.append(location); + } + if (profile != null) { + result.append(" for profile "); + result.append(profile); } - return String.format("'%s'", location); + return result; } private Set getProfiles(Binder binder, String name) { From 865b7ae47f942545506934ef0bcc3352fc669a05 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 17 Sep 2018 12:18:18 -0700 Subject: [PATCH 653/701] Reduce object creation when binding Use static finals and private instances to reduce the number of objects created when binding from the `ConfigFileApplicationListener`. Closes gh-13436 --- .../config/ConfigFileApplicationListener.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java index 7ffcf21ee398..1ba833ba2d55 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigFileApplicationListener.java @@ -111,6 +111,8 @@ public class ConfigFileApplicationListener private static final Set NO_SEARCH_NAMES = Collections.singleton(null); + private static final Bindable STRING_ARRAY = Bindable.of(String[].class); + /** * The "active profiles" property name. */ @@ -290,6 +292,8 @@ private class Loader { private final ConfigurableEnvironment environment; + private final PropertySourcesPlaceholdersResolver placeholdersResolver; + private final ResourceLoader resourceLoader; private final List propertySourceLoaders; @@ -306,6 +310,8 @@ private class Loader { Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { this.environment = environment; + this.placeholdersResolver = new PropertySourcesPlaceholdersResolver( + this.environment); this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader(); this.propertySourceLoaders = SpringFactoriesLoader.loadFactories( @@ -577,10 +583,9 @@ private List asDocuments(List> loaded) { return loaded.stream().map((propertySource) -> { Binder binder = new Binder( ConfigurationPropertySources.from(propertySource), - new PropertySourcesPlaceholdersResolver(this.environment)); + this.placeholdersResolver); return new Document(propertySource, - binder.bind("spring.profiles", Bindable.of(String[].class)) - .orElse(null), + binder.bind("spring.profiles", STRING_ARRAY).orElse(null), getProfiles(binder, ACTIVE_PROFILES_PROPERTY), getProfiles(binder, INCLUDE_PROFILES_PROPERTY)); }).collect(Collectors.toList()); @@ -610,7 +615,7 @@ private StringBuilder getDescription(String prefix, String location, } private Set getProfiles(Binder binder, String name) { - return binder.bind(name, String[].class).map(this::asProfileSet) + return binder.bind(name, STRING_ARRAY).map(this::asProfileSet) .orElse(Collections.emptySet()); } From 2bc3d8d01f2d6630c5d48a3a182de195301be024 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 17 Sep 2018 12:59:47 -0700 Subject: [PATCH 654/701] Use shared BindConverter when possible Update the `Binder` so that a single shares static `BindConverter` is used whenever possible. Closes gh-14562 --- .../properties/bind/BindConverter.java | 21 ++++++++++++++++-- .../boot/context/properties/bind/Binder.java | 2 +- .../properties/bind/BindConverterTests.java | 22 +++++++++---------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java index daf60ba5238f..c5b60e758485 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java @@ -47,7 +47,7 @@ * @author Phillip Webb * @author Andy Wilkinson */ -class BindConverter { +final class BindConverter { private static final Set> EXCLUDED_EDITORS; static { @@ -56,9 +56,11 @@ class BindConverter { EXCLUDED_EDITORS = Collections.unmodifiableSet(excluded); } + private static BindConverter sharedInstance; + private final ConversionService conversionService; - BindConverter(ConversionService conversionService, + private BindConverter(ConversionService conversionService, Consumer propertyEditorInitializer) { Assert.notNull(conversionService, "ConversionService must not be null"); List conversionServices = getConversionServices( @@ -97,6 +99,21 @@ public T convert(Object value, ResolvableType type, Annotation... annotation new ResolvableTypeDescriptor(type, annotations)); } + public static BindConverter get(ConversionService conversionService, + Consumer propertyEditorInitializer) { + if (conversionService == ApplicationConversionService.getSharedInstance() + && propertyEditorInitializer == null) { + BindConverter instance = sharedInstance; + if (instance == null) { + instance = new BindConverter(conversionService, + propertyEditorInitializer); + sharedInstance = instance; + } + return instance; + } + return new BindConverter(conversionService, propertyEditorInitializer); + } + /** * A {@link TypeDescriptor} backed by a {@link ResolvableType}. */ diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java index 65009bf5f122..8b102b2fc974 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java @@ -392,7 +392,7 @@ final class Context implements BindContext { private ConfigurationProperty configurationProperty; Context() { - this.converter = new BindConverter(Binder.this.conversionService, + this.converter = BindConverter.get(Binder.this.conversionService, Binder.this.propertyEditorInitializer); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java index bed2ccc51541..07cf1889b5a8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java @@ -65,17 +65,17 @@ public void setup() { public void createWhenConversionServiceIsNullShouldThrowException() { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("ConversionService must not be null"); - new BindConverter(null, null); + BindConverter.get(null, null); } @Test public void createWhenPropertyEditorInitializerIsNullShouldCreate() { - new BindConverter(ApplicationConversionService.getSharedInstance(), null); + BindConverter.get(ApplicationConversionService.getSharedInstance(), null); } @Test public void createWhenPropertyEditorInitializerIsNotNullShouldUseToInitialize() { - new BindConverter(ApplicationConversionService.getSharedInstance(), + BindConverter.get(ApplicationConversionService.getSharedInstance(), this.propertyEditorInitializer); verify(this.propertyEditorInitializer).accept(any(PropertyEditorRegistry.class)); } @@ -128,8 +128,8 @@ public void canConvertWhenConversionServiceCanConvertShouldReturnTrue() { @Test public void canConvertWhenNotPropertyEditorAndConversionServiceCannotConvertShouldReturnFalse() { - BindConverter bindConverter = new BindConverter( - ApplicationConversionService.getSharedInstance(), null); + BindConverter bindConverter = BindConverter + .get(ApplicationConversionService.getSharedInstance(), null); assertThat(bindConverter.canConvert("test", ResolvableType.forClass(SampleType.class))).isFalse(); } @@ -189,8 +189,8 @@ public void convertWhenConversionServiceCanConvertShouldConvert() { @Test public void convertWhenNotPropertyEditorAndConversionServiceCannotConvertShouldThrowException() { - BindConverter bindConverter = new BindConverter( - ApplicationConversionService.getSharedInstance(), null); + BindConverter bindConverter = BindConverter + .get(ApplicationConversionService.getSharedInstance(), null); this.thrown.expect(ConverterNotFoundException.class); bindConverter.convert("test", ResolvableType.forClass(SampleType.class)); } @@ -199,7 +199,7 @@ public void convertWhenNotPropertyEditorAndConversionServiceCannotConvertShouldT public void convertWhenConvertingToFileShouldExcludeFileEditor() { // For back compatibility we want true file conversion and not an accidental // classpath resource reference. See gh-12163 - BindConverter bindConverter = new BindConverter(new GenericConversionService(), + BindConverter bindConverter = BindConverter.get(new GenericConversionService(), null); File result = bindConverter.convert(".", ResolvableType.forClass(File.class)); assertThat(result.getPath()).isEqualTo("."); @@ -207,7 +207,7 @@ public void convertWhenConvertingToFileShouldExcludeFileEditor() { @Test public void fallsBackToApplicationConversionService() { - BindConverter bindConverter = new BindConverter(new GenericConversionService(), + BindConverter bindConverter = BindConverter.get(new GenericConversionService(), null); Duration result = bindConverter.convert("10s", ResolvableType.forClass(Duration.class)); @@ -216,14 +216,14 @@ public void fallsBackToApplicationConversionService() { private BindConverter getPropertyEditorOnlyBindConverter( Consumer propertyEditorInitializer) { - return new BindConverter(new ThrowingConversionService(), + return BindConverter.get(new ThrowingConversionService(), propertyEditorInitializer); } private BindConverter getBindConverter(Converter converter) { GenericConversionService conversionService = new GenericConversionService(); conversionService.addConverter(converter); - return new BindConverter(conversionService, null); + return BindConverter.get(conversionService, null); } private void registerSampleTypeEditor(PropertyEditorRegistry registry) { From 0a187675b5c90d0340b4d6f9cbb27c48928262b6 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 20 Sep 2018 09:49:43 -0700 Subject: [PATCH 655/701] Reduce GC in SpringConfigurationPropertySource Update `SpringConfigurationPropertySource` so that the `DelegatingPropertyMapper` accepts a maximum of two values and does not need to wrap arguments in an array. Also optimize the merge operation to return a single result directly rather than always using a new `List`. Closes gh-14563 --- .../SpringConfigurationPropertySource.java | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java index e19a9a68c061..43e5623d74d2 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java @@ -16,9 +16,6 @@ package org.springframework.boot.context.properties.source; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.function.Function; @@ -30,6 +27,7 @@ import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.SystemEnvironmentPropertySource; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * {@link ConfigurationPropertySource} backed by a non-enumerable Spring @@ -217,34 +215,67 @@ private static ConfigurationPropertyState containsDescendantOfForRandom( */ private static class DelegatingPropertyMapper implements PropertyMapper { - private final PropertyMapper[] mappers; + private static final PropertyMapping[] NONE = {}; - DelegatingPropertyMapper(PropertyMapper... mappers) { - this.mappers = mappers; + private final PropertyMapper first; + + private final PropertyMapper second; + + DelegatingPropertyMapper(PropertyMapper first) { + this(first, null); + } + + DelegatingPropertyMapper(PropertyMapper first, PropertyMapper second) { + this.first = first; + this.second = second; } @Override public PropertyMapping[] map( ConfigurationPropertyName configurationPropertyName) { - return callMappers((mapper) -> mapper.map(configurationPropertyName)); + PropertyMapping[] first = map(this.first, configurationPropertyName); + PropertyMapping[] second = map(this.second, configurationPropertyName); + return merge(first, second); + } + + private PropertyMapping[] map(PropertyMapper mapper, + ConfigurationPropertyName configurationPropertyName) { + try { + return (mapper != null) ? mapper.map(configurationPropertyName) : NONE; + } + catch (Exception ex) { + return NONE; + } } @Override public PropertyMapping[] map(String propertySourceName) { - return callMappers((mapper) -> mapper.map(propertySourceName)); + PropertyMapping[] first = map(this.first, propertySourceName); + PropertyMapping[] second = map(this.second, propertySourceName); + return merge(first, second); } - private PropertyMapping[] callMappers( - Function function) { - List mappings = new ArrayList<>(); - for (PropertyMapper mapper : this.mappers) { - try { - mappings.addAll(Arrays.asList(function.apply(mapper))); - } - catch (Exception ex) { - } + private PropertyMapping[] map(PropertyMapper mapper, String propertySourceName) { + try { + return (mapper != null) ? mapper.map(propertySourceName) : NONE; + } + catch (Exception ex) { + return NONE; + } + } + + private PropertyMapping[] merge(PropertyMapping[] first, + PropertyMapping[] second) { + if (ObjectUtils.isEmpty(second)) { + return first; + } + if (ObjectUtils.isEmpty(first)) { + return second; } - return mappings.toArray(new PropertyMapping[] {}); + PropertyMapping[] merged = new PropertyMapping[first.length + second.length]; + System.arraycopy(first, 0, merged, 0, first.length); + System.arraycopy(second, 0, merged, first.length, second.length); + return merged; } } From d0de4657d4fa7c0b181a2d6ef05402deee5b5785 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 20 Sep 2018 09:49:55 -0700 Subject: [PATCH 656/701] Reduce ConfigurationPropertyName GC pressure Rewrite `ConfigurationPropertyName` in an attempt to consume less memory and to reduce GC pressure from `toString()`. Prior to this commit the `toString()` method would always construct a new value from the name elements. This is sub-optimal since on on many occasions the `ConfigurationPropertyName` is created from an already well-formed String. The updated code now attempts to directly use the original value for both `toString` and `equals` whenever possible. Further refinements have also been made to the way that elements are stored. Rather than a list or objects, we now use arrays that contains the split points and types. This helps to reduce the amount of memory required to store the name. Closes gh-13414 --- .../source/ConfigurationPropertyName.java | 786 +++++++++++------- ...gurationPropertySourcesPropertySource.java | 6 +- .../ConfigurationPropertyNameTests.java | 29 +- ...ringConfigurationPropertySourcesTests.java | 13 + 4 files changed, 543 insertions(+), 291 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java index 152833efd347..f13b3fb62fff 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java @@ -24,7 +24,6 @@ import java.util.function.Function; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * A configuration property name composed of elements separated by dots. User created @@ -59,24 +58,17 @@ public final class ConfigurationPropertyName * An empty {@link ConfigurationPropertyName}. */ public static final ConfigurationPropertyName EMPTY = new ConfigurationPropertyName( - new String[0]); + Elements.EMPTY); - private final CharSequence[] elements; + private Elements elements; private final CharSequence[] uniformElements; - private int[] elementHashCodes; - private String string; - private ConfigurationPropertyName(CharSequence[] elements) { - this(elements, new CharSequence[elements.length]); - } - - private ConfigurationPropertyName(CharSequence[] elements, - CharSequence[] uniformElements) { + private ConfigurationPropertyName(Elements elements) { this.elements = elements; - this.uniformElements = uniformElements; + this.uniformElements = new CharSequence[elements.getSize()]; } /** @@ -84,7 +76,7 @@ private ConfigurationPropertyName(CharSequence[] elements, * @return {@code true} if the name is empty */ public boolean isEmpty() { - return this.elements.length == 0; + return this.elements.getSize() == 0; } /** @@ -93,7 +85,7 @@ public boolean isEmpty() { */ public boolean isLastElementIndexed() { int size = getNumberOfElements(); - return (size > 0 && isIndexed(this.elements[size - 1])); + return (size > 0 && isIndexed(size - 1)); } /** @@ -102,7 +94,7 @@ public boolean isLastElementIndexed() { * @return {@code true} if the element is indexed */ boolean isIndexed(int elementIndex) { - return isIndexed(this.elements[elementIndex]); + return this.elements.getType(elementIndex).isIndexed(); } /** @@ -111,17 +103,7 @@ boolean isIndexed(int elementIndex) { * @return {@code true} if the element is indexed and numeric */ public boolean isNumericIndex(int elementIndex) { - return isIndexed(elementIndex) - && isNumeric(getElement(elementIndex, Form.ORIGINAL)); - } - - private boolean isNumeric(CharSequence element) { - for (int i = 0; i < element.length(); i++) { - if (!Character.isDigit(element.charAt(i))) { - return false; - } - } - return true; + return this.elements.getType(elementIndex) == ElementType.NUMERICALLY_INDEXED; } /** @@ -141,26 +123,57 @@ public String getLastElement(Form form) { * @return the last element */ public String getElement(int elementIndex, Form form) { + CharSequence element = this.elements.get(elementIndex); + ElementType type = this.elements.getType(elementIndex); + if (type.isIndexed()) { + return element.toString(); + } if (form == Form.ORIGINAL) { - CharSequence result = this.elements[elementIndex]; - if (isIndexed(result)) { - result = result.subSequence(1, result.length() - 1); + if (type != ElementType.NON_UNIFORM) { + return element.toString(); } - return result.toString(); + return convertToOriginalForm(element).toString(); } - CharSequence result = this.uniformElements[elementIndex]; - if (result == null) { - result = this.elements[elementIndex]; - if (isIndexed(result)) { - result = result.subSequence(1, result.length() - 1); + if (form == Form.DASHED) { + if (type == ElementType.UNIFORM || type == ElementType.DASHED) { + return element.toString(); } - else { - result = cleanupCharSequence(result, (c, i) -> c == '-' || c == '_', - CharProcessor.LOWERCASE); + return convertToDashedElement(element).toString(); + } + CharSequence uniformElement = this.uniformElements[elementIndex]; + if (uniformElement == null) { + uniformElement = (type != ElementType.UNIFORM) + ? convertToUniformElement(element) : element; + this.uniformElements[elementIndex] = uniformElement.toString(); + } + return uniformElement.toString(); + } + + private CharSequence convertToOriginalForm(CharSequence element) { + return convertElement(element, false, (ch, i) -> ch == '_' + || ElementsParser.isValidChar(Character.toLowerCase(ch), i)); + } + + private CharSequence convertToDashedElement(CharSequence element) { + return convertElement(element, true, ElementsParser::isValidChar); + } + + private CharSequence convertToUniformElement(CharSequence element) { + return convertElement(element, true, + (ch, i) -> ElementsParser.isAlphaNumeric(ch)); + } + + private CharSequence convertElement(CharSequence element, boolean lowercase, + ElementCharPredicate filter) { + StringBuilder result = new StringBuilder(element.length()); + for (int i = 0; i < element.length(); i++) { + char ch = lowercase ? Character.toLowerCase(element.charAt(i)) + : element.charAt(i); + if (filter.test(ch, i)) { + result.append(ch); } - this.uniformElements[elementIndex] = result; } - return result.toString(); + return result; } /** @@ -168,7 +181,7 @@ public String getElement(int elementIndex, Form form) { * @return the number of elements */ public int getNumberOfElements() { - return this.elements.length; + return this.elements.getSize(); } /** @@ -182,20 +195,8 @@ public ConfigurationPropertyName append(String elementValue) { if (elementValue == null) { return this; } - process(elementValue, '.', (value, start, end, indexed) -> Assert.isTrue( - start == 0, - () -> "Element value '" + elementValue + "' must be a single item")); - if (!isIndexed(elementValue)) { - InvalidConfigurationPropertyNameException.throwIfHasInvalidChars(elementValue, - ElementValidator.getInvalidChars(elementValue)); - } - int length = this.elements.length; - CharSequence[] elements = new CharSequence[length + 1]; - System.arraycopy(this.elements, 0, elements, 0, length); - elements[length] = elementValue; - CharSequence[] uniformElements = new CharSequence[length + 1]; - System.arraycopy(this.uniformElements, 0, uniformElements, 0, length); - return new ConfigurationPropertyName(elements, uniformElements); + Elements additionalElements = of(elementValue).elements; + return new ConfigurationPropertyName(this.elements.append(additionalElements)); } /** @@ -209,11 +210,7 @@ public ConfigurationPropertyName chop(int size) { if (size >= getNumberOfElements()) { return this; } - CharSequence[] elements = new CharSequence[size]; - System.arraycopy(this.elements, 0, elements, 0, size); - CharSequence[] uniformElements = new CharSequence[size]; - System.arraycopy(this.uniformElements, 0, uniformElements, 0, size); - return new ConfigurationPropertyName(elements, uniformElements); + return new ConfigurationPropertyName(this.elements.chop(size)); } /** @@ -240,8 +237,8 @@ public boolean isAncestorOf(ConfigurationPropertyName name) { if (this.getNumberOfElements() >= name.getNumberOfElements()) { return false; } - for (int i = 0; i < this.elements.length; i++) { - if (!elementEquals(this.elements[i], name.elements[i])) { + for (int i = 0; i < this.elements.getSize(); i++) { + if (!elementEquals(this.elements, name.elements, i)) { return false; } } @@ -259,38 +256,39 @@ private int compare(ConfigurationPropertyName n1, ConfigurationPropertyName n2) int i1 = 0; int i2 = 0; while (i1 < l1 || i2 < l2) { - boolean indexed1 = (i1 < l1) ? n1.isIndexed(i2) : false; - boolean indexed2 = (i2 < l2) ? n2.isIndexed(i2) : false; - String e1 = (i1 < l1) ? n1.getElement(i1++, Form.UNIFORM) : null; - String e2 = (i2 < l2) ? n2.getElement(i2++, Form.UNIFORM) : null; - int result = compare(e1, indexed1, e2, indexed2); - if (result != 0) { - return result; + try { + ElementType type1 = (i1 < l1) ? n1.elements.getType(i1) : null; + ElementType type2 = (i2 < l2) ? n2.elements.getType(i2) : null; + String e1 = (i1 < l1) ? n1.getElement(i1++, Form.UNIFORM) : null; + String e2 = (i2 < l2) ? n2.getElement(i2++, Form.UNIFORM) : null; + int result = compare(e1, type1, e2, type2); + if (result != 0) { + return result; + } + } + catch (ArrayIndexOutOfBoundsException ex) { + throw new RuntimeException(ex); } } return 0; } - private int compare(String e1, boolean indexed1, String e2, boolean indexed2) { + private int compare(String e1, ElementType type1, String e2, ElementType type2) { if (e1 == null) { return -1; } if (e2 == null) { return 1; } - int result = Boolean.compare(indexed2, indexed1); + int result = Boolean.compare(type2.isIndexed(), type1.isIndexed()); if (result != 0) { return result; } - if (indexed1 && indexed2) { - try { - long v1 = Long.parseLong(e1); - long v2 = Long.parseLong(e2); - return Long.compare(v1, v2); - } - catch (NumberFormatException ex) { - // Fallback to string comparison - } + if (type1 == ElementType.NUMERICALLY_INDEXED + && type2 == ElementType.NUMERICALLY_INDEXED) { + long v1 = Long.parseLong(e1); + long v2 = Long.parseLong(e2); + return Long.compare(v1, v2); } return e1.compareTo(e2); } @@ -307,33 +305,37 @@ public boolean equals(Object obj) { if (getNumberOfElements() != other.getNumberOfElements()) { return false; } - for (int i = 0; i < this.elements.length; i++) { - if (!elementEquals(this.elements[i], other.elements[i])) { + if (this.elements.canShortcutWithSource(ElementType.UNIFORM) + && other.elements.canShortcutWithSource(ElementType.UNIFORM)) { + return toString().equals(other.toString()); + } + for (int i = 0; i < this.elements.getSize(); i++) { + if (!elementEquals(this.elements, other.elements, i)) { return false; } } return true; } - private boolean elementEquals(CharSequence e1, CharSequence e2) { - int l1 = e1.length(); - int l2 = e2.length(); - boolean indexed1 = isIndexed(e1); - int offset1 = indexed1 ? 1 : 0; - boolean indexed2 = isIndexed(e2); - int offset2 = indexed2 ? 1 : 0; - int i1 = offset1; - int i2 = offset2; - while (i1 < l1 - offset1) { - if (i2 >= l2 - offset2) { + private boolean elementEquals(Elements e1, Elements e2, int i) { + int l1 = e1.getLength(i); + int l2 = e2.getLength(i); + boolean indexed1 = e1.getType(i).isIndexed(); + boolean indexed2 = e2.getType(i).isIndexed(); + int i1 = 0; + int i2 = 0; + while (i1 < l1) { + if (i2 >= l2) { return false; } - char ch1 = indexed1 ? e1.charAt(i1) : Character.toLowerCase(e1.charAt(i1)); - char ch2 = indexed2 ? e2.charAt(i2) : Character.toLowerCase(e2.charAt(i2)); - if (!indexed1 && (ch1 == '-' || ch1 == '_')) { + char ch1 = indexed1 ? e1.charAt(i, i1) + : Character.toLowerCase(e1.charAt(i, i1)); + char ch2 = indexed2 ? e2.charAt(i, i2) + : Character.toLowerCase(e2.charAt(i, i2)); + if (!indexed1 && !ElementsParser.isAlphaNumeric(ch1)) { i1++; } - else if (!indexed2 && (ch2 == '-' || ch2 == '_')) { + else if (!indexed2 && !ElementsParser.isAlphaNumeric(ch2)) { i2++; } else if (ch1 != ch2) { @@ -344,9 +346,9 @@ else if (ch1 != ch2) { i2++; } } - while (i2 < l2 - offset2) { - char ch = e2.charAt(i2++); - if (indexed2 || (ch != '-' && ch != '_')) { + while (i2 < l2) { + char ch2 = e2.charAt(i, i2++); + if (indexed2 || !ElementsParser.isAlphaNumeric(ch2)) { return false; } } @@ -355,66 +357,40 @@ else if (ch1 != ch2) { @Override public int hashCode() { - if (this.elementHashCodes == null) { - this.elementHashCodes = getElementHashCodes(); - } - return ObjectUtils.nullSafeHashCode(this.elementHashCodes); - } - - private int[] getElementHashCodes() { - int[] hashCodes = new int[this.elements.length]; - for (int i = 0; i < this.elements.length; i++) { - hashCodes[i] = getElementHashCode(this.elements[i]); - } - return hashCodes; - } - - private int getElementHashCode(CharSequence element) { - int hash = 0; - boolean indexed = isIndexed(element); - int offset = indexed ? 1 : 0; - for (int i = 0 + offset; i < element.length() - offset; i++) { - char ch = (indexed ? element.charAt(i) - : Character.toLowerCase(element.charAt(i))); - hash = (ch == '-' || ch == '_') ? hash : 31 * hash + Character.hashCode(ch); - } - return hash; + return 0; } @Override public String toString() { if (this.string == null) { - this.string = toString(this.elements); + this.string = buildToString(); } return this.string; } - private String toString(CharSequence[] elements) { + private String buildToString() { + if (this.elements.canShortcutWithSource(ElementType.UNIFORM, + ElementType.DASHED)) { + return this.elements.getSource().toString(); + } StringBuilder result = new StringBuilder(); - for (CharSequence element : elements) { - boolean indexed = isIndexed(element); + for (int i = 0; i < getNumberOfElements(); i++) { + boolean indexed = isIndexed(i); if (result.length() > 0 && !indexed) { result.append('.'); } if (indexed) { - result.append(element); + result.append("["); + result.append(getElement(i, Form.ORIGINAL)); + result.append("]"); } else { - for (int i = 0; i < element.length(); i++) { - char ch = Character.toLowerCase(element.charAt(i)); - if (ch != '_') { - result.append(ch); - } - } + result.append(getElement(i, Form.DASHED)); } } return result.toString(); } - private static boolean isIndexed(CharSequence element) { - return element.charAt(0) == '[' && element.charAt(element.length() - 1) == ']'; - } - /** * Returns if the given name is valid. If this method returns {@code true} then the * name may be used with {@link #of(CharSequence)} without throwing an exception. @@ -422,18 +398,7 @@ private static boolean isIndexed(CharSequence element) { * @return {@code true} if the name is valid */ public static boolean isValid(CharSequence name) { - if (name == null) { - return false; - } - if (name.equals(EMPTY_STRING)) { - return true; - } - if (name.charAt(0) == '.' || name.charAt(name.length() - 1) == '.') { - return false; - } - ElementValidator validator = new ElementValidator(); - process(name, '.', validator); - return validator.isValid(); + return of(name, true) != null; } /** @@ -443,26 +408,54 @@ public static boolean isValid(CharSequence name) { * @throws InvalidConfigurationPropertyNameException if the name is not valid */ public static ConfigurationPropertyName of(CharSequence name) { - Assert.notNull(name, "Name must not be null"); - if (name.length() >= 1 - && (name.charAt(0) == '.' || name.charAt(name.length() - 1) == '.')) { - throw new InvalidConfigurationPropertyNameException(name, - Collections.singletonList('.')); + return of(name, false); + } + + /** + * Return a {@link ConfigurationPropertyName} for the specified string. + * @param name the source name + * @param returnNullIfInvalid if null should be returned if the name is not valid + * @return a {@link ConfigurationPropertyName} instance + * @throws InvalidConfigurationPropertyNameException if the name is not valid and + * {@code returnNullIfInvalid} is {@code false} + */ + static ConfigurationPropertyName of(CharSequence name, boolean returnNullIfInvalid) { + if (name == null) { + Assert.isTrue(returnNullIfInvalid, "Name must not be null"); + return null; } if (name.length() == 0) { return EMPTY; } - List elements = new ArrayList<>(10); - process(name, '.', (elementValue, start, end, indexed) -> { - if (elementValue.length() > 0) { - if (!indexed) { - InvalidConfigurationPropertyNameException.throwIfHasInvalidChars(name, - ElementValidator.getInvalidChars(elementValue)); + if (name.charAt(0) == '.' || name.charAt(name.length() - 1) == '.') { + if (returnNullIfInvalid) { + return null; + } + throw new InvalidConfigurationPropertyNameException(name, + Collections.singletonList('.')); + } + Elements elements = new ElementsParser(name, '.').parse(); + for (int i = 0; i < elements.getSize(); i++) { + if (elements.getType(i) == ElementType.NON_UNIFORM) { + if (returnNullIfInvalid) { + return null; } - elements.add(elementValue); + throw new InvalidConfigurationPropertyNameException(name, + getInvalidChars(elements, i)); } - }); - return new ConfigurationPropertyName(elements.toArray(new CharSequence[0])); + } + return new ConfigurationPropertyName(elements); + } + + private static List getInvalidChars(Elements elements, int index) { + List invalidChars = new ArrayList<>(); + for (int charIndex = 0; charIndex < elements.getLength(index); charIndex++) { + char ch = elements.charAt(index, charIndex); + if (!ElementsParser.isValidChar(ch, charIndex)) { + invalidChars.add(ch); + } + } + return invalidChars; } /** @@ -473,7 +466,7 @@ public static ConfigurationPropertyName of(CharSequence name) { * @return a {@link ConfigurationPropertyName} */ static ConfigurationPropertyName adapt(CharSequence name, char separator) { - return adapt(name, separator, Function.identity()); + return adapt(name, separator, null); } /** @@ -492,84 +485,15 @@ static ConfigurationPropertyName adapt(CharSequence name, char separator) { static ConfigurationPropertyName adapt(CharSequence name, char separator, Function elementValueProcessor) { Assert.notNull(name, "Name must not be null"); - Assert.notNull(elementValueProcessor, "ElementValueProcessor must not be null"); if (name.length() == 0) { return EMPTY; } - List elements = new ArrayList<>(); - process(name, separator, (elementValue, start, end, indexed) -> { - elementValue = elementValueProcessor.apply(elementValue); - if (!isIndexed(elementValue)) { - elementValue = cleanupCharSequence(elementValue, - (ch, index) -> ch != '_' && !ElementValidator - .isValidChar(Character.toLowerCase(ch), index), - CharProcessor.NONE); - } - if (elementValue.length() > 0) { - elements.add(elementValue); - } - }); - return new ConfigurationPropertyName(elements.toArray(new CharSequence[0])); - } - - private static void process(CharSequence name, char separator, - ElementProcessor processor) { - int start = 0; - boolean indexed = false; - int length = name.length(); - int openBracketCount = 0; - for (int i = 0; i < length; i++) { - char ch = name.charAt(i); - if (ch == ']') { - openBracketCount--; - if (openBracketCount == 0) { - processElement(processor, name, start, i + 1, indexed); - start = i + 1; - indexed = false; - } - } - else if (ch == '[') { - openBracketCount++; - if (!indexed) { - processElement(processor, name, start, i, indexed); - start = i; - indexed = true; - } - } - else if (!indexed && ch == separator) { - processElement(processor, name, start, i, indexed); - start = i + 1; - } - } - processElement(processor, name, start, length, false); - } - - private static void processElement(ElementProcessor processor, CharSequence name, - int start, int end, boolean indexed) { - if ((end - start) >= 1) { - processor.process(name.subSequence(start, end), start, end, indexed); - } - } - - private static CharSequence cleanupCharSequence(CharSequence name, CharFilter filter, - CharProcessor processor) { - for (int i = 0; i < name.length(); i++) { - char ch = name.charAt(i); - char processed = processor.process(ch, i); - if (filter.isExcluded(processed, i) || processed != ch) { - // We save memory by only creating the new result if necessary - StringBuilder result = new StringBuilder(name.length()); - result.append(name.subSequence(0, i)); - for (int j = i; j < name.length(); j++) { - processed = processor.process(name.charAt(j), j); - if (!filter.isExcluded(processed, j)) { - result.append(processed); - } - } - return result; - } + Elements elements = new ElementsParser(name, separator) + .parse(elementValueProcessor); + if (elements.getSize() == 0) { + return EMPTY; } - return name; + return new ConfigurationPropertyName(elements); } /** @@ -578,7 +502,7 @@ private static CharSequence cleanupCharSequence(CharSequence name, CharFilter fi public enum Form { /** - * The original form as specified when the name was created or parsed. For + * The original form as specified when the name was created or adapted. For * example: *

      *
    • "{@code foo-bar}" = "{@code foo-bar}"
    • @@ -589,6 +513,18 @@ public enum Form { */ ORIGINAL, + /** + * The dashed configuration form (used for toString; lower-case with only + * alphanumeric characters and dashes). + *
        + *
      • "{@code foo-bar}" = "{@code foo-bar}"
      • + *
      • "{@code fooBar}" = "{@code foobar}"
      • + *
      • "{@code foo_bar}" = "{@code foobar}"
      • + *
      • "{@code [Foo.bar]}" = "{@code Foo.bar}"
      • + *
      + */ + DASHED, + /** * The uniform configuration form (used for equals/hashCode; lower-case with only * alphanumeric characters). @@ -604,81 +540,308 @@ public enum Form { } /** - * Internal functional interface used when processing names. + * Allows access to the individual elements that make up the name. We store the + * indexes in arrays rather than a list of object in order to conserve memory. */ - @FunctionalInterface - private interface ElementProcessor { + private static class Elements { - void process(CharSequence elementValue, int start, int end, boolean indexed); + private static final int[] NO_POSITION = {}; - } + private static final ElementType[] NO_TYPE = {}; - /** - * Internal filter used to strip out characters. - */ - private interface CharFilter { + public static final Elements EMPTY = new Elements("", 0, NO_POSITION, NO_POSITION, + NO_TYPE, null); - boolean isExcluded(char ch, int index); + private final CharSequence source; - } + private final int size; - /** - * Internal processor used to change characters. - */ - private interface CharProcessor { + private final int[] start; - CharProcessor NONE = (c, i) -> c; + private final int[] end; - CharProcessor LOWERCASE = (c, i) -> Character.toLowerCase(c); + private final ElementType[] type; - char process(char c, int index); + /** + * Contains any resolved elements or can be {@code null} if there aren't any. + * Resolved elements allow us to modify the element values in some way (or example + * when adapting with a mapping function, or when append has been called). Note + * that this array is not used as a cache, in fact, when it's not null then + * {@link #canShortcutWithSource} will always return false which may hurt + * performance. + */ + private final CharSequence[] resolved; + + Elements(CharSequence source, int size, int[] start, int[] end, + ElementType[] type, CharSequence[] resolved) { + super(); + this.source = source; + this.size = size; + this.start = start; + this.end = end; + this.type = type; + this.resolved = resolved; + } + + public Elements append(Elements additional) { + Assert.isTrue(additional.getSize() == 1, () -> "Element value '" + + additional.getSource() + "' must be a single item"); + ElementType[] type = new ElementType[this.size + 1]; + System.arraycopy(this.type, 0, type, 0, this.size); + type[this.size] = additional.type[0]; + CharSequence[] resolved = newResolved(this.size + 1); + resolved[this.size] = additional.get(0); + return new Elements(this.source, this.size + 1, this.start, this.end, type, + resolved); + } + + public Elements chop(int size) { + CharSequence[] resolved = newResolved(size); + return new Elements(this.source, size, this.start, this.end, this.type, + resolved); + } + + private CharSequence[] newResolved(int size) { + CharSequence[] resolved = new CharSequence[size]; + if (this.resolved != null) { + System.arraycopy(this.resolved, 0, resolved, 0, + Math.min(size, this.size)); + } + return resolved; + } - } + public int getSize() { + return this.size; + } - /** - * {@link ElementProcessor} that checks if a name is valid. - */ - private static class ElementValidator implements ElementProcessor { + public CharSequence get(int index) { + if (this.resolved != null && this.resolved[index] != null) { + return this.resolved[index]; + } + int start = this.start[index]; + int end = this.end[index]; + return this.source.subSequence(start, end); + } - private boolean valid = true; + public int getLength(int index) { + if (this.resolved != null && this.resolved[index] != null) { + return this.resolved[index].length(); + } + int start = this.start[index]; + int end = this.end[index]; + return end - start; + } - @Override - public void process(CharSequence elementValue, int start, int end, - boolean indexed) { - if (this.valid && !indexed) { - this.valid = isValidElement(elementValue); + public char charAt(int index, int charIndex) { + if (this.resolved != null && this.resolved[index] != null) { + return this.resolved[index].charAt(charIndex); } + int start = this.start[index]; + return this.source.charAt(start + charIndex); + } + + public ElementType getType(int index) { + return this.type[index]; } - public boolean isValid() { - return this.valid; + public CharSequence getSource() { + return this.source; } - public static boolean isValidElement(CharSequence elementValue) { - for (int i = 0; i < elementValue.length(); i++) { - char ch = elementValue.charAt(i); - if (!isValidChar(ch, i)) { + /** + * Returns if the element source can be used as a shortcut for an operation such + * as {@code equals} or {@code toString}. + * @param requiredType the required type + * @return {@code true} if all elements match at least one of the types + */ + public boolean canShortcutWithSource(ElementType requiredType) { + return canShortcutWithSource(requiredType, requiredType); + } + + /** + * Returns if the element source can be used as a shortcut for an operation such + * as {@code equals} or {@code toString}. + * @param requiredType the required type + * @param alternativeType and alternative required type + * @return {@code true} if all elements match at least one of the types + */ + public boolean canShortcutWithSource(ElementType requiredType, + ElementType alternativeType) { + if (this.resolved != null) { + return false; + } + for (int i = 0; i < this.size; i++) { + ElementType type = this.type[i]; + if (type != requiredType && type != alternativeType) { + return false; + } + if (i > 0 && this.end[i - 1] + 1 != this.start[i]) { return false; } } return true; } - public static List getInvalidChars(CharSequence elementValue) { - List chars = new ArrayList<>(); - for (int i = 0; i < elementValue.length(); i++) { - char ch = elementValue.charAt(i); - if (!isValidChar(ch, i)) { - chars.add(ch); + } + + /** + * Main parsing logic used to convert a {@link CharSequence} to {@link Elements}. + */ + private static class ElementsParser { + + private static final int DEFAULT_CAPACITY = 6; + + private final CharSequence source; + + private final char separator; + + private int size; + + private int[] start; + + private int[] end; + + private ElementType[] type; + + private CharSequence[] resolved; + + ElementsParser(CharSequence source, char separator) { + this(source, separator, DEFAULT_CAPACITY); + } + + ElementsParser(CharSequence source, char separator, int capacity) { + this.source = source; + this.separator = separator; + this.start = new int[capacity]; + this.end = new int[capacity]; + this.type = new ElementType[capacity]; + } + + public Elements parse() { + return parse(null); + } + + public Elements parse(Function valueProcessor) { + int length = this.source.length(); + int openBracketCount = 0; + int start = 0; + ElementType type = ElementType.EMPTY; + for (int i = 0; i < length; i++) { + char ch = this.source.charAt(i); + if (ch == '[') { + if (openBracketCount == 0) { + add(start, i, type, valueProcessor); + start = i + 1; + type = ElementType.NUMERICALLY_INDEXED; + } + openBracketCount++; + } + else if (ch == ']') { + openBracketCount--; + if (openBracketCount == 0) { + add(start, i, type, valueProcessor); + start = i + 1; + type = ElementType.EMPTY; + } + } + else if (!type.isIndexed() && ch == this.separator) { + add(start, i, type, valueProcessor); + start = i + 1; + type = ElementType.EMPTY; } + else { + type = updateType(type, ch, i - start); + } + } + if (openBracketCount != 0) { + type = ElementType.NON_UNIFORM; } - return chars; + add(start, length, type, valueProcessor); + return new Elements(this.source, this.size, this.start, this.end, this.type, + this.resolved); + } + + private ElementType updateType(ElementType existingType, char ch, int index) { + if (existingType.isIndexed()) { + if (existingType == ElementType.NUMERICALLY_INDEXED && !isNumeric(ch)) { + return ElementType.INDEXED; + } + return existingType; + } + if (existingType == ElementType.EMPTY && isValidChar(ch, index)) { + return (index == 0) ? ElementType.UNIFORM : ElementType.NON_UNIFORM; + } + if (existingType == ElementType.UNIFORM && ch == '-') { + return ElementType.DASHED; + } + if (!isValidChar(ch, index)) { + if (existingType == ElementType.EMPTY + && !isValidChar(Character.toLowerCase(ch), index)) { + return ElementType.EMPTY; + } + return ElementType.NON_UNIFORM; + } + return existingType; + } + + private void add(int start, int end, ElementType type, + Function valueProcessor) { + if ((end - start) < 1 || type == ElementType.EMPTY) { + return; + } + if (this.start.length <= end) { + this.start = expand(this.start); + this.end = expand(this.end); + this.type = expand(this.type); + this.resolved = expand(this.resolved); + } + if (valueProcessor != null) { + if (this.resolved == null) { + this.resolved = new CharSequence[this.start.length]; + } + CharSequence resolved = valueProcessor + .apply(this.source.subSequence(start, end)); + Elements resolvedElements = new ElementsParser(resolved, '.').parse(); + Assert.state(resolvedElements.getSize() == 1, + "Resolved element must not contain multiple elements"); + this.resolved[this.size] = resolvedElements.get(0); + type = resolvedElements.getType(0); + } + this.start[this.size] = start; + this.end[this.size] = end; + this.type[this.size] = type; + this.size++; + } + + private int[] expand(int[] src) { + int[] dest = new int[src.length + DEFAULT_CAPACITY]; + System.arraycopy(src, 0, dest, 0, src.length); + return dest; + } + + private ElementType[] expand(ElementType[] src) { + ElementType[] dest = new ElementType[src.length + DEFAULT_CAPACITY]; + System.arraycopy(src, 0, dest, 0, src.length); + return dest; + } + + private CharSequence[] expand(CharSequence[] src) { + if (src == null) { + return null; + } + CharSequence[] dest = new CharSequence[src.length + DEFAULT_CAPACITY]; + System.arraycopy(src, 0, dest, 0, src.length); + return dest; } public static boolean isValidChar(char ch, int index) { return isAlpha(ch) || isNumeric(ch) || (index != 0 && ch == '-'); } + public static boolean isAlphaNumeric(char ch) { + return isAlpha(ch) || isNumeric(ch); + } + private static boolean isAlpha(char ch) { return ch >= 'a' && ch <= 'z'; } @@ -689,4 +852,61 @@ private static boolean isNumeric(char ch) { } + /** + * The various types of element that we can detect. + */ + private enum ElementType { + + /** + * The element is logically empty (contains no valid chars). + */ + EMPTY(false), + + /** + * The element is a uniform name (a-z, 0-9, no dashes, lowercase). + */ + UNIFORM(false), + + /** + * The element is almost uniform, but it contains (but does not start with) at + * least one dash. + */ + DASHED(false), + + /** + * The element contains non uniform characters and will need to be converted. + */ + NON_UNIFORM(false), + + /** + * The element is non-numerically indexed. + */ + INDEXED(true), + + /** + * The element is numerically indexed. + */ + NUMERICALLY_INDEXED(true); + + private final boolean indexed; + + ElementType(boolean indexed) { + this.indexed = indexed; + } + + public boolean isIndexed() { + return this.indexed; + } + + } + + /** + * Predicate used to filter element chars. + */ + private interface ElementCharPredicate { + + boolean test(char ch, int index); + + } + } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java index e2212a8bddf1..9b7a23d7cf9b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java @@ -52,13 +52,11 @@ public Origin getOrigin(String name) { private ConfigurationProperty findConfigurationProperty(String name) { try { - if (ConfigurationPropertyName.isValid(name)) { - return findConfigurationProperty(ConfigurationPropertyName.of(name)); - } + return findConfigurationProperty(ConfigurationPropertyName.of(name, true)); } catch (Exception ex) { + return null; } - return null; } private ConfigurationProperty findConfigurationProperty( diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java index 17a858a8cebc..576acc4904eb 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java @@ -234,10 +234,10 @@ public void adaptWhenNameIsNullShouldThrowException() { } @Test - public void adaptWhenElementValueProcessorIsNullShouldThrowException() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("ElementValueProcessor must not be null"); - ConfigurationPropertyName.adapt("foo", '.', null); + public void adaptWhenElementValueProcessorIsNullShouldAdapt() { + ConfigurationPropertyName name = ConfigurationPropertyName.adapt("foo", '.', + null); + assertThat(name.toString()).isEqualTo("foo"); } @Test @@ -304,6 +304,12 @@ public void adaptShouldSupportIndexedElements() { assertThat(name.getNumberOfElements()).isEqualTo(3); } + @Test + public void adaptUnderscoreShouldReturnEmpty() { + assertThat(ConfigurationPropertyName.adapt("_", '_').isEmpty()).isTrue(); + assertThat(ConfigurationPropertyName.adapt("_", '.').isEmpty()).isTrue(); + } + @Test public void isEmptyWhenEmptyShouldReturnTrue() { assertThat(ConfigurationPropertyName.of("").isEmpty()).isTrue(); @@ -538,6 +544,15 @@ public void compareShouldSortNames() { "foo.bar", "foo.bard", "foo.baz"); } + @Test + public void compareDifferentLengthsShouldSortNames() { + ConfigurationPropertyName name = ConfigurationPropertyName + .of("spring.resources.chain.strategy.content"); + ConfigurationPropertyName other = ConfigurationPropertyName + .of("spring.resources.chain.strategy.content.enabled"); + assertThat(name.compareTo(other)).isLessThan(0); + } + @Test public void toStringShouldBeLowerCaseDashed() { ConfigurationPropertyName name = ConfigurationPropertyName.adapt("fOO.b_-a-r", @@ -545,6 +560,12 @@ public void toStringShouldBeLowerCaseDashed() { assertThat(name.toString()).isEqualTo("foo.b-a-r"); } + @Test + public void toStringFromOfShouldBeLowerCaseDashed() { + ConfigurationPropertyName name = ConfigurationPropertyName.of("foo.bar-baz"); + assertThat(name.toString()).isEqualTo("foo.bar-baz"); + } + @Test public void equalsAndHashCode() { ConfigurationPropertyName n01 = ConfigurationPropertyName.of("foo[bar]"); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java index bb550c056094..b1586b537a26 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java @@ -104,6 +104,19 @@ public void shouldNotAdaptSystemEnvironmentPropertyOverrideSource() { assertThat(iterator.hasNext()).isFalse(); } + @Test + public void shouldAdaptSystemEnvironmentPropertySourceWithUnderscoreValue() { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new SystemEnvironmentPropertySource( + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, + Collections.singletonMap("_", "1234"))); + Iterator iterator = new SpringConfigurationPropertySources( + sources).iterator(); + ConfigurationPropertyName name = ConfigurationPropertyName.of("bar"); + assertThat(iterator.next().getConfigurationProperty(name)).isNull(); + assertThat(iterator.hasNext()).isFalse(); + } + @Test public void shouldAdaptMultiplePropertySources() { MutablePropertySources sources = new MutablePropertySources(); From 11b1318cad455cb6ce58a0c1e7b98d5a03b369fb Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 20 Sep 2018 21:26:02 -0700 Subject: [PATCH 657/701] Reduce GC pressure in JAR handler Update the JAR `Hander` so that URL `startsWith` checks produce less garbage. Comparisons are now performed first on the `path` rather than the full `toString`. URL `toString` operations produce quite a lot of garbage since a `StringBuilder` is always used. In addition, we now also cache the JarFile URL toString to save repeated calculation. Closes gh-14561 --- .../org/springframework/boot/loader/jar/Handler.java | 10 ++++++++-- .../org/springframework/boot/loader/jar/JarFile.java | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java index 5e9c8075cd6f..5b23b677bf68 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java @@ -92,8 +92,7 @@ public Handler(JarFile jarFile) { @Override protected URLConnection openConnection(URL url) throws IOException { - if (this.jarFile != null - && url.toString().startsWith(this.jarFile.getUrl().toString())) { + if (this.jarFile != null && isUrlInJarFile(url, this.jarFile)) { return JarURLConnection.get(url, this.jarFile); } try { @@ -104,6 +103,13 @@ protected URLConnection openConnection(URL url) throws IOException { } } + private boolean isUrlInJarFile(URL url, JarFile jarFile) + throws MalformedURLException { + // Try the path first to save building a new url string each time + return url.getPath().startsWith(jarFile.getUrl().getPath()) + && url.toString().startsWith(jarFile.getUrlString()); + } + private URLConnection openFallbackConnection(URL url, Exception reason) throws IOException { try { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 9c16b0b74d02..dafcd4a2b1d8 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -69,6 +69,8 @@ public class JarFile extends java.util.jar.JarFile { private URL url; + private String urlString; + private JarFileEntries entries; private Supplier manifestSupplier; @@ -301,6 +303,13 @@ public void close() throws IOException { } } + String getUrlString() throws MalformedURLException { + if (this.urlString == null) { + this.urlString = getUrl().toString(); + } + return this.urlString; + } + /** * Return a URL that can be used to access this JAR file. NOTE: the specified URL * cannot be serialized and or cloned. From f3c637f5c2f2ab1b7628fb8f3697e27adaf9f2d3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 21 Sep 2018 10:57:48 +0200 Subject: [PATCH 658/701] Upgrade to Spring Framwork 5.1.0.RELEASE Closes gh-14481 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 8220723f3f11..d2dc93bebdc9 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -157,7 +157,7 @@ 1.23 7.4.0 - 5.1.0.BUILD-SNAPSHOT + 5.1.0.RELEASE 2.1.0.M3 4.1.0.M3 2.0.3.RELEASE From 42abf733bedc7d3427a8411c96689f54e88320f9 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 11:56:00 +0100 Subject: [PATCH 659/701] Start building against snapshots for Micrometer 1.1.0 M1 See gh-14567 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d2dc93bebdc9..d291edfe5259 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -127,7 +127,7 @@ 1.2.3 1.18.2 2.3.0 - 1.0.6 + 1.1.0-SNAPSHOT 2.22.0 1.9.2 3.8.2 From fe75f966ff7cb6c95efd6267747842819d592022 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 13:11:33 +0100 Subject: [PATCH 660/701] Auto-configure Micrometer's Dynatrace meter registry Closes gh-14522 --- .../pom.xml | 5 + ...natraceMetricsExportAutoConfiguration.java | 66 +++++++ .../export/dynatrace/DynatraceProperties.java | 85 +++++++++ .../DynatracePropertiesConfigAdapter.java | 58 ++++++ .../export/dynatrace/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 1 + ...ceMetricsExportAutoConfigurationTests.java | 169 ++++++++++++++++++ ...DynatracePropertiesConfigAdapterTests.java | 62 +++++++ .../dynatrace/DynatracePropertiesTests.java | 40 +++++ .../spring-boot-dependencies/pom.xml | 5 + .../appendix-application-properties.adoc | 10 ++ .../asciidoc/production-ready-features.adoc | 23 +++ 12 files changed, 544 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index 5aea66cbc2fb..b4eb5f61a30d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -102,6 +102,11 @@ micrometer-registry-datadog true + + io.micrometer + micrometer-registry-dynatrace + true + io.micrometer micrometer-registry-ganglia diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfiguration.java new file mode 100644 index 000000000000..e9d28ae3f06c --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.dynatrace.DynatraceConfig; +import io.micrometer.dynatrace.DynatraceMeterRegistry; + +import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Dynatrace. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnBean(Clock.class) +@ConditionalOnClass(DynatraceMeterRegistry.class) +@ConditionalOnProperty(prefix = "management.metrics.export.dynatrace", name = "enabled", havingValue = "true", matchIfMissing = true) +@EnableConfigurationProperties(DynatraceProperties.class) +public class DynatraceMetricsExportAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public DynatraceConfig dynatraceConfig(DynatraceProperties dynatraceProperties) { + return new DynatracePropertiesConfigAdapter(dynatraceProperties); + } + + @Bean + @ConditionalOnMissingBean + public DynatraceMeterRegistry dynatraceMeterRegistry(DynatraceConfig dynatraceConfig, + Clock clock) { + return new DynatraceMeterRegistry(dynatraceConfig, clock); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java new file mode 100644 index 000000000000..2be57720f005 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties} for configuring Dynatrace metrics export. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@ConfigurationProperties(prefix = "management.metrics.export.dynatrace") +public class DynatraceProperties extends StepRegistryProperties { + + /** + * Dynatrace authentication token. + */ + private String apiToken; + + /** + * ID of the custom device that is exporting metrics to Dynatrace. + */ + private String deviceId; + + /** + * Technology type for exported metrics. Used to group metrics under a logical + * technology name in the Dynatrace UI. + */ + private String technologyType = "java"; + + /** + * URI to ship metrics to. If you need to publish metrics to an internal proxy + * en-route to Dynatrace, you can define the location of the proxy with this. + */ + private String uri; + + public String getApiToken() { + return this.apiToken; + } + + public void setApiToken(String apiToken) { + this.apiToken = apiToken; + } + + public String getDeviceId() { + return this.deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getTechnologyType() { + return this.technologyType; + } + + public void setTechnologyType(String technologyType) { + this.technologyType = technologyType; + } + + public String getUri() { + return this.uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java new file mode 100644 index 000000000000..099877457f00 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import io.micrometer.datadog.DatadogConfig; +import io.micrometer.dynatrace.DynatraceConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; + +/** + * Adapter to convert {@link DynatraceProperties} to a {@link DatadogConfig}. + * + * @author Andy Wilkinson * + */ +class DynatracePropertiesConfigAdapter + extends StepRegistryPropertiesConfigAdapter + implements DynatraceConfig { + + DynatracePropertiesConfigAdapter(DynatraceProperties properties) { + super(properties); + } + + @Override + public String apiToken() { + return get(DynatraceProperties::getApiToken, DynatraceConfig.super::apiToken); + } + + @Override + public String deviceId() { + return get(DynatraceProperties::getDeviceId, DynatraceConfig.super::deviceId); + } + + @Override + public String technologyType() { + return get(DynatraceProperties::getTechnologyType, + DynatraceConfig.super::technologyType); + } + + @Override + public String uri() { + return get(DynatraceProperties::getUri, DynatraceConfig.super::uri); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/package-info.java new file mode 100644 index 000000000000..36e019707bc2 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Support for exporting actuator metrics to Dynatrace. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 0109c40f12fb..dbbf9472723d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -43,6 +43,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoCon org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogMetricsExportAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace.DynatraceMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetricsExportAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java new file mode 100644 index 000000000000..7d307594bec5 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java @@ -0,0 +1,169 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import java.util.Map; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.dynatrace.DynatraceConfig; +import io.micrometer.dynatrace.DynatraceMeterRegistry; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link DynatraceMetricsExportAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class DynatraceMetricsExportAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(DynatraceMetricsExportAutoConfiguration.class)); + + @Test + public void backsOffWithoutAClock() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(DynatraceMeterRegistry.class)); + } + + @Test + public void failsWithoutAUri() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .run((context) -> assertThat(context).hasFailed()); + } + + @Test + public void autoConfiguresConfigAndMeterRegistry() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues( + "management.metrics.export.dynatrace.uri=https://dynatrace.example.com") + .run((context) -> assertThat(context) + .hasSingleBean(DynatraceMeterRegistry.class) + .hasSingleBean(DynatraceConfig.class)); + } + + @Test + public void autoConfigurationCanBeDisabled() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.metrics.export.dynatrace.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(DynatraceMeterRegistry.class) + .doesNotHaveBean(DynatraceConfig.class)); + } + + @Test + public void allowsCustomConfigToBeUsed() { + this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(DynatraceMeterRegistry.class) + .hasSingleBean(DynatraceConfig.class).hasBean("customConfig")); + } + + @Test + public void allowsCustomRegistryToBeUsed() { + this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class) + .withPropertyValues( + "management.metrics.export.dynatrace.uri=https://dynatrace.example.com") + .run((context) -> assertThat(context) + .hasSingleBean(DynatraceMeterRegistry.class) + .hasBean("customRegistry").hasSingleBean(DynatraceConfig.class)); + } + + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.metrics.export.dynatrace.api-token=abcde", + "management.metrics.export.dynatrace.uri=https://dynatrace.example.com", + "management.metrics.export.dynatrace.deviceId=test") + .run((context) -> { + DynatraceMeterRegistry registry = spyOnDisposableBean( + DynatraceMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + + @Configuration + static class BaseConfiguration { + + @Bean + public Clock clock() { + return Clock.SYSTEM; + } + + } + + @Configuration + @Import(BaseConfiguration.class) + static class CustomConfigConfiguration { + + @Bean + public DynatraceConfig customConfig() { + return new DynatraceConfig() { + + @Override + public String get(String k) { + if ("dynatrace.uri".equals(k)) { + return "https://dynatrace.example.com"; + } + return null; + } + + }; + } + + } + + @Configuration + @Import(BaseConfiguration.class) + static class CustomRegistryConfiguration { + + @Bean + public DynatraceMeterRegistry customRegistry(DynatraceConfig config, + Clock clock) { + return new DynatraceMeterRegistry(config, clock); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java new file mode 100644 index 000000000000..b8e6e6e9c13d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DynatracePropertiesConfigAdapter}. + * + * @author Andy Wilkiknson + */ +public class DynatracePropertiesConfigAdapterTests { + + @Test + public void whenPropertiesUriIsSetAdapterUriReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setUri("https://dynatrace.example.com"); + assertThat(new DynatracePropertiesConfigAdapter(properties).uri()) + .isEqualTo("https://dynatrace.example.com"); + } + + @Test + public void whenPropertiesApiTokenIsSetAdapterApiTokenReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setApiToken("123ABC"); + assertThat(new DynatracePropertiesConfigAdapter(properties).apiToken()) + .isEqualTo("123ABC"); + } + + @Test + public void whenPropertiesDeviceIdIsSetAdapterDeviceIdReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setDeviceId("dev-1"); + assertThat(new DynatracePropertiesConfigAdapter(properties).deviceId()) + .isEqualTo("dev-1"); + } + + @Test + public void whenPropertiesTechnologyTypeIsSetAdapterTechnologyTypeReturnsIt() { + DynatraceProperties properties = new DynatraceProperties(); + properties.setTechnologyType("tech-1"); + assertThat(new DynatracePropertiesConfigAdapter(properties).technologyType()) + .isEqualTo("tech-1"); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesTests.java new file mode 100644 index 000000000000..b360f258e1d2 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.dynatrace; + +import io.micrometer.dynatrace.DynatraceConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesTests; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DynatraceProperties}. + * + * @author Andy Wilkinson + */ +public class DynatracePropertiesTests extends StepRegistryPropertiesTests { + + @Override + public void defaultValuesAreConsistent() { + DynatraceProperties properties = new DynatraceProperties(); + DynatraceConfig config = DynatraceConfig.DEFAULT; + assertStepRegistryDefaultValues(properties, config); + assertThat(properties.getTechnologyType()).isEqualTo(config.technologyType()); + } + +} diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index d291edfe5259..716ff1fdf21f 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -899,6 +899,11 @@ micrometer-registry-datadog ${micrometer.version} + + io.micrometer + micrometer-registry-dynatrace + ${micrometer.version} + io.micrometer micrometer-registry-influx diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 1fc1d2feb023..4780209a0e93 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1400,6 +1400,16 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.datadog.read-timeout=10s # Read timeout for requests to this backend. management.metrics.export.datadog.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.datadog.uri=https://app.datadoghq.com # URI to ship metrics to. If you need to publish metrics to an internal proxy en-route to Datadog, you can define the location of the proxy with this. + management.metrics.export.dynatrace.api-token= # Dynatrace API token. + management.metrics.export.dynatrace.batch-size=10000 # Number of measurements per request to use for this backend. If more measurements are found, then multiple requests will be made. + management.metrics.export.dynatrace.connect-timeout=1s # Connection timeout for requests to this backend. + management.metrics.export.dynatrace.deviceId= # ID of the custom device that is exporting metrics to Dynatrace. + management.metrics.export.dynatrace.enabled=true # Whether exporting of metrics to this backend is enabled. + management.metrics.export.dynatrace.num-threads=2 # Number of threads to use with the metrics publishing scheduler. + management.metrics.export.dynatrace.read-timeout=10s # Read timeout for requests to this backend. + management.metrics.export.dynatrace.step=1m # Step size (i.e. reporting frequency) to use. + management.metrics.export.dynatrace.technology-type=java # Technology type for exported metrics. Used to group metrics under a logical technology name in the Dynatrace UI. + management.metrics.export.dynatrace.uri= # URI to ship metrics to. If you need to publish metrics to an internal proxy en-route to Dynatrace, you can define the location of the proxy with this. management.metrics.export.ganglia.addressing-mode=multicast # UDP addressing mode, either unicast or multicast. management.metrics.export.ganglia.duration-units=milliseconds # Base time unit used to report durations. management.metrics.export.ganglia.enabled=true # Whether exporting of metrics to Ganglia is enabled. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 3671d5e8eafd..eea3521e145c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1336,6 +1336,7 @@ monitoring systems, including: - <> - <> +- <> - <> - <> - <> @@ -1452,6 +1453,28 @@ You can also change the interval at which metrics are sent to Datadog: +[[production-ready-metrics-export-dynatrace]] +==== Datadog +Dynatrace registry pushes metrics to the configured UIR periodically. To export metrics to +{micrometer-registry-documentation}/dynatrace[Dynatrace], your API token, device ID, and +URI must be provided: + +[source,properties,indent=0] +---- + management.metrics.export.dynatrace.api-token=YOUR_TOKEN + management.metrics.export.dynatrace.device-id=YOUR_DEVICE_ID + management.metrics.export.dynatrace.uri=YOUR_URI +---- + +You can also change the interval at which metrics are sent to Dynatrace: + +[source,properties,indent=0] +---- + management.metrics.export.dynatrace.step=30s +---- + + + [[production-ready-metrics-export-ganglia]] ==== Ganglia By default, metrics are exported to {micrometer-registry-documentation}/ganglia[Ganglia] From 4b00dc8a5ccb1e3981ac88649ac56bf3c9e80689 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 20 Sep 2018 12:16:22 +0100 Subject: [PATCH 661/701] Add support for Spring Data JDBC (auto-config, starter, and test slice) Closes gh-14489 --- .../spring-boot-autoconfigure/pom.xml | 5 + .../JdbcRepositoriesAutoConfiguration.java | 65 +++++++++ ...dbcRepositoriesAutoConfigureRegistrar.java | 56 +++++++ .../autoconfigure/data/jdbc/package-info.java | 20 +++ ...itional-spring-configuration-metadata.json | 6 + .../main/resources/META-INF/spring.factories | 1 + ...dbcRepositoriesAutoConfigurationTests.java | 138 ++++++++++++++++++ .../autoconfigure/data/jdbc/city/City.java | 63 ++++++++ .../data/jdbc/city/CityRepository.java | 28 ++++ .../src/test/resources/data-jdbc-schema.sql | 7 + .../spring-boot-dependencies/pom.xml | 5 + .../appendix-application-properties.adoc | 3 + .../main/asciidoc/spring-boot-features.adoc | 47 +++++- .../spring-boot-starters/pom.xml | 1 + .../spring-boot-starter-data-jdbc/pom.xml | 26 ++++ .../spring-boot-test-autoconfigure/pom.xml | 5 + .../data/jdbc/AutoConfigureDataJdbc.java | 44 ++++++ .../autoconfigure/data/jdbc/DataJdbcTest.java | 103 +++++++++++++ .../jdbc/DataJdbcTestContextBootstrapper.java | 37 +++++ .../data/jdbc/DataJdbcTypeExcludeFilter.java | 73 +++++++++ .../autoconfigure/data/jdbc/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 10 ++ .../jdbc/DataJdbcTestIntegrationTests.java | 97 ++++++++++++ ...ataJdbcTestPropertiesIntegrationTests.java | 46 ++++++ .../data/jdbc/ExampleComponent.java | 29 ++++ .../data/jdbc/ExampleDataJdbcApplication.java | 41 ++++++ .../data/jdbc/ExampleEntity.java | 48 ++++++ .../data/jdbc/ExampleRepository.java | 28 ++++ .../test/autoconfigure/data/jdbc/schema.sql | 1 + spring-boot-samples/README.adoc | 3 + spring-boot-samples/pom.xml | 1 + .../spring-boot-sample-data-jdbc/pom.xml | 48 ++++++ .../main/java/sample/data/jdbc/Customer.java | 56 +++++++ .../sample/data/jdbc/CustomerRepository.java | 30 ++++ .../sample/data/jdbc/SampleController.java | 43 ++++++ .../data/jdbc/SampleDataJdbcApplication.java | 29 ++++ .../src/main/resources/data.sql | 2 + .../src/main/resources/schema.sql | 5 + .../CustomerRepositoryIntegrationTests.java | 56 +++++++ .../jdbc/SampleDataJdbcApplicationTests.java | 60 ++++++++ 40 files changed, 1383 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigureRegistrar.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/City.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/CityRepository.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/resources/data-jdbc-schema.sql create mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-jdbc/pom.xml create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/AutoConfigureDataJdbc.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTest.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestContextBootstrapper.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTypeExcludeFilter.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/package-info.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestPropertiesIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleComponent.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleDataJdbcApplication.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleEntity.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleRepository.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/resources/org/springframework/boot/test/autoconfigure/data/jdbc/schema.sql create mode 100755 spring-boot-samples/spring-boot-sample-data-jdbc/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/Customer.java create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/CustomerRepository.java create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleController.java create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleDataJdbcApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/data.sql create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/schema.sql create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/CustomerRepositoryIntegrationTests.java create mode 100644 spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/SampleDataJdbcApplicationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index bd627da715f6..87981c1ef666 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -469,6 +469,11 @@ spring-data-cassandra true + + org.springframework.data + spring-data-jdbc + true + org.springframework.data spring-data-ldap diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration.java new file mode 100644 index 000000000000..a8cc1d64675b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfiguration.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.jdbc; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.data.jdbc.repository.config.JdbcConfiguration; +import org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's JDBC Repositories. + *

      + * Once in effect, the auto-configuration is the equivalent of enabling JDBC repositories + * using the + * {@link org.springframework.data.jdbc.repository.config.EnableJdbcRepositories} + * annotation and providing a {@link JdbcConfiguration} subclass. + * + * @author Andy Wilkinson + * @since 2.1.0 + * @see EnableJdbcRepositories + */ +@Configuration +@ConditionalOnBean(NamedParameterJdbcOperations.class) +@ConditionalOnClass({ NamedParameterJdbcOperations.class, JdbcConfiguration.class }) +@ConditionalOnProperty(prefix = "spring.data.jdbc.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@AutoConfigureAfter(JdbcTemplateAutoConfiguration.class) +public class JdbcRepositoriesAutoConfiguration { + + @Configuration + @ConditionalOnMissingBean(JdbcRepositoryConfigExtension.class) + @Import(JdbcRepositoriesAutoConfigureRegistrar.class) + static class JdbcRepositoriesConfiguration { + + } + + @Configuration + @ConditionalOnMissingBean(JdbcConfiguration.class) + static class SpringBootJdbcConfiguration extends JdbcConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigureRegistrar.java new file mode 100644 index 000000000000..a3e49b0ee20a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigureRegistrar.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.jdbc; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data JDBC + * Repositories. + * + * @author Andy Wilkinson + */ +class JdbcRepositoriesAutoConfigureRegistrar + extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableJdbcRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableJdbcRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new JdbcRepositoryConfigExtension(); + } + + @EnableJdbcRepositories + private static class EnableJdbcRepositoriesConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/package-info.java new file mode 100644 index 000000000000..8f5290109489 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jdbc/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Spring Data JDBC. + */ +package org.springframework.boot.autoconfigure.data.jdbc; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c370ba38c3aa..193f9567d45d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -156,6 +156,12 @@ "description": "Whether to enable Elasticsearch repositories.", "defaultValue": true }, + { + "name": "spring.data.jdbc.repositories.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable JDBC repositories.", + "defaultValue": true + }, { "name": "spring.data.jpa.repositories.bootstrap-mode", "type": "org.springframework.data.repository.config.BootstrapMode", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 946adfbdc204..5a80d1196aa7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -44,6 +44,7 @@ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoC org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigurationTests.java new file mode 100644 index 000000000000..2c897eb3626e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/JdbcRepositoriesAutoConfigurationTests.java @@ -0,0 +1,138 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.jdbc; + +import javax.sql.DataSource; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; +import org.springframework.boot.autoconfigure.data.jdbc.city.City; +import org.springframework.boot.autoconfigure.data.jdbc.city.CityRepository; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.data.jdbc.repository.config.JdbcConfiguration; +import org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension; +import org.springframework.data.repository.Repository; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link JdbcRepositoriesAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class JdbcRepositoriesAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(JdbcRepositoriesAutoConfiguration.class)); + + @Test + public void backsOffWithNoDataSource() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .run((context) -> { + assertThat(context) + .doesNotHaveBean(JdbcRepositoryConfigExtension.class); + }); + } + + @Test + public void backsOffWithNoJdbcOperations() { + this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, + TestConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(DataSource.class); + assertThat(context) + .doesNotHaveBean(JdbcRepositoryConfigExtension.class); + }); + } + + @Test + public void basicAutoConfiguration() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(JdbcTemplateAutoConfiguration.class, + DataSourceAutoConfiguration.class)) + .withUserConfiguration(TestConfiguration.class, + EmbeddedDataSourceConfiguration.class) + .withPropertyValues( + "spring.datasource.schema=classpath:data-jdbc-schema.sql", + "spring.datasource.data=classpath:city.sql") + .run((context) -> { + assertThat(context).hasSingleBean(JdbcConfiguration.class); + assertThat(context).hasSingleBean(CityRepository.class); + assertThat(context.getBean(CityRepository.class).findById(2000L)) + .isPresent(); + }); + } + + @Test + public void autoConfigurationWithNoRepositories() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(JdbcTemplateAutoConfiguration.class)) + .withUserConfiguration(EmbeddedDataSourceConfiguration.class, + EmptyConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(JdbcConfiguration.class); + assertThat(context).doesNotHaveBean(Repository.class); + }); + } + + @Test + public void honoursUsersEnableJdbcRepositoriesConfiguration() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(JdbcTemplateAutoConfiguration.class, + DataSourceAutoConfiguration.class)) + .withUserConfiguration(EnableRepositoriesConfiguration.class, + EmbeddedDataSourceConfiguration.class) + .withPropertyValues( + "spring.datasource.schema=classpath:data-jdbc-schema.sql", + "spring.datasource.data=classpath:city.sql") + .run((context) -> { + assertThat(context).hasSingleBean(JdbcConfiguration.class); + assertThat(context).hasSingleBean(CityRepository.class); + assertThat(context.getBean(CityRepository.class).findById(2000L)) + .isPresent(); + }); + } + + @TestAutoConfigurationPackage(City.class) + private static class TestConfiguration { + + } + + @Configuration + @TestAutoConfigurationPackage(EmptyDataPackage.class) + protected static class EmptyConfiguration { + + } + + @TestAutoConfigurationPackage(EmptyDataPackage.class) + @EnableJdbcRepositories(basePackageClasses = City.class) + private static class EnableRepositoriesConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/City.java new file mode 100644 index 000000000000..bdec56653857 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/City.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.jdbc.city; + +import org.springframework.data.annotation.Id; + +public class City { + + @Id + private Long id; + + private String name; + + private String state; + + private String country; + + private String map; + + protected City() { + } + + public City(String name, String country) { + this.name = name; + this.country = country; + } + + public String getName() { + return this.name; + } + + public String getState() { + return this.state; + } + + public String getCountry() { + return this.country; + } + + public String getMap() { + return this.map; + } + + @Override + public String toString() { + return getName() + "," + getState() + "," + getCountry(); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/CityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/CityRepository.java new file mode 100644 index 000000000000..22f0595388f9 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jdbc/city/CityRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2018 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.autoconfigure.data.jdbc.city; + +import org.springframework.data.repository.CrudRepository; + +/** + * Data JDBC repository for working with {@link City Cities}. + * + * @author Andy Wilkinson + */ +public interface CityRepository extends CrudRepository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/data-jdbc-schema.sql b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/data-jdbc-schema.sql new file mode 100644 index 000000000000..7e3a3462e00d --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/data-jdbc-schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE CITY ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(30), + state VARCHAR(30), + country VARCHAR(30), + map VARCHAR(30) +); diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 716ff1fdf21f..540566f1cc7c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -355,6 +355,11 @@ spring-boot-starter-data-elasticsearch ${revision} + + org.springframework.boot + spring-boot-starter-data-jdbc + ${revision} + org.springframework.boot spring-boot-starter-data-jpa diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 4780209a0e93..e14a368bf3dd 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -659,6 +659,9 @@ content into your application. Rather, pick only the properties that you need. spring.data.elasticsearch.properties.*= # Additional properties used to configure the client. spring.data.elasticsearch.repositories.enabled=true # Whether to enable Elasticsearch repositories. + # DATA JDBC + spring.data.jdbc.repositories.enabled=true # Whether to enable JDBC repositories. + # DATA LDAP spring.data.ldap.repositories.enabled=true # Whether to enable LDAP repositories. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5789e685ef6d..1c02abc2c526 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3671,7 +3671,7 @@ scenes. If more than one `JdbcTemplate` is defined and no primary candidate exis [[boot-features-jpa-and-spring-data]] -=== JPA and "`Spring Data`" +=== JPA and Spring Data JPA The Java Persistence API is a standard technology that lets you "`map`" objects to relational databases. The `spring-boot-starter-data-jpa` POM provides a quick way to get started. It provides the following key dependencies: @@ -3838,6 +3838,23 @@ views. If you do not want this behavior, you should set `spring.jpa.open-in-view +[[boot-features-data-jdbc]] +=== Spring Data JDBC +Spring Data includes repository support for JDBC and will automatically generate SQL for +the methods on `CrudRepository`. For more advanced queries, a `@Query` annotation is +provided. + +Spring Boot will auto-configure Spring Data's JDBC repositories when the necessary +dependencies are on the classpath. They can be added to your project with a single +dependency on `spring-boot-starter-data-jdbc`. If necessary, you can take control of +Spring Data JDBC's configuration by adding the `@EnableJdbcRepositories` annotation or a +`JdbcConfiguration` subclass to your application. + +TIP: For complete details of Spring Data JDBC, please refer to the +https://projects.spring.io/spring-data-jdbc/[reference documentation]. + + + [[boot-features-sql-h2-console]] === Using H2's Web Console The http://www.h2database.com[H2 database] provides a @@ -7106,8 +7123,9 @@ following example: [[boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test]] ==== Auto-configured JDBC Tests `@JdbcTest` is similar to `@DataJpaTest` but is for tests that only require a -`DataSource`. By default, it configures an in-memory embedded database and a -`JdbcTemplate`. Regular `@Component` beans are not loaded into the `ApplicationContext`. +`DataSource` and do not use Spring Data JDBC. By default, it configures an in-memory +embedded database and a `JdbcTemplate`. Regular `@Component` beans are not loaded into +the `ApplicationContext`. TIP: A list of the auto-configurations that are enabled by `@JdbcTest` can be <>. @@ -7141,6 +7159,29 @@ If you prefer your test to run against a real database, you can use the +[[boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test]] +==== Auto-configured Data JDBC Tests +`@DataJdbcTest` is similar to `@JdbcTest` but is for tests that use Spring Data JDBC +repositories. By default, it configures an in-memory embedded database, a `JdbcTemplate`, +and Spring Data JDBD repositories. Regular `@Component` beans are not loaded into +the `ApplicationContext`. + +TIP: A list of the auto-configurations that are enabled by `@DataJdbcTest` can be +<>. + +By default, Data JDBC tests are transactional and roll back at the end of each test. See +the {spring-reference}testing.html#testcontext-tx-enabling-transactions[relevant section] +in the Spring Framework Reference Documentation for more details. If that is not what you +want, you can disable transaction management for a test or for the whole test class as +<>. + +If you prefer your test to run against a real database, you can use the +`@AutoConfigureTestDatabase` annotation in the same way as for `DataJpaTest`. (See +"<>".) + + + [[boot-features-testing-spring-boot-applications-testing-autoconfigured-jooq-test]] ==== Auto-configured jOOQ Tests You can use `@JooqTest` in a similar fashion as `@JdbcTest` but for jOOQ-related tests. diff --git a/spring-boot-project/spring-boot-starters/pom.xml b/spring-boot-project/spring-boot-starters/pom.xml index 76a7ca4dfebb..610daeec870d 100644 --- a/spring-boot-project/spring-boot-starters/pom.xml +++ b/spring-boot-project/spring-boot-starters/pom.xml @@ -30,6 +30,7 @@ spring-boot-starter-data-couchbase spring-boot-starter-data-couchbase-reactive spring-boot-starter-data-elasticsearch + spring-boot-starter-data-jdbc spring-boot-starter-data-jpa spring-boot-starter-data-ldap spring-boot-starter-data-mongodb diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jdbc/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jdbc/pom.xml new file mode 100644 index 000000000000..26a8e354d5a7 --- /dev/null +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-jdbc/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starters + ${revision} + + spring-boot-starter-data-jdbc + Spring Boot Data JDBC Starter + Starter for using Spring Data JDBC + + ${basedir}/../../.. + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.data + spring-data-jdbc + + + diff --git a/spring-boot-project/spring-boot-test-autoconfigure/pom.xml b/spring-boot-project/spring-boot-test-autoconfigure/pom.xml index 3c8550b30aa6..b219fe39992c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-test-autoconfigure/pom.xml @@ -116,6 +116,11 @@ spring-webflux true + + org.springframework.data + spring-data-jdbc + true + org.springframework.data spring-data-jpa diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/AutoConfigureDataJdbc.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/AutoConfigureDataJdbc.java new file mode 100644 index 000000000000..12324b2f50e6 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/AutoConfigureDataJdbc.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; + +/** + * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data JDBC tests. + * Most tests should consider using {@link DataJdbcTest @DataJdbcTest} rather than using + * this annotation directly. + * + * @author Andy Wilkinson + * @since 2.1.0 + * @see DataJdbcTest + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@ImportAutoConfiguration +public @interface AutoConfigureDataJdbc { + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTest.java new file mode 100644 index 000000000000..161e6a2f2335 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration; +import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache; +import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.core.annotation.AliasFor; +import org.springframework.core.env.Environment; +import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +/** + * Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)} + * for a typical Data JDBC test. Can be used when a test focuses only on + * Data JDBC components. + *

      + * Using this annotation will disable full auto-configuration and instead apply only + * configuration relevant to Data JDBC tests. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@BootstrapWith(DataJdbcTestContextBootstrapper.class) +@ExtendWith(SpringExtension.class) +@OverrideAutoConfiguration(enabled = false) +@TypeExcludeFilters(DataJdbcTypeExcludeFilter.class) +@AutoConfigureCache +@AutoConfigureDataJdbc +@AutoConfigureTestDatabase +@ImportAutoConfiguration +public @interface DataJdbcTest { + + /** + * Properties in form {@literal key=value} that should be added to the Spring + * {@link Environment} before the test runs. + * @return the properties to add + */ + String[] properties() default {}; + + /** + * Determines if default filtering should be used with + * {@link SpringBootApplication @SpringBootApplication}. By default no beans are + * included. + * @see #includeFilters() + * @see #excludeFilters() + * @return if default filters should be used + */ + boolean useDefaultFilters() default true; + + /** + * A set of include filters which can be used to add otherwise filtered beans to the + * application context. + * @return include filters to apply + */ + Filter[] includeFilters() default {}; + + /** + * A set of exclude filters which can be used to filter beans that would otherwise be + * added to the application context. + * @return exclude filters to apply + */ + Filter[] excludeFilters() default {}; + + /** + * Auto-configuration exclusions that should be applied for this test. + * @return auto-configuration exclusions to apply + */ + @AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude") + Class[] excludeAutoConfiguration() default {}; + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestContextBootstrapper.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestContextBootstrapper.java new file mode 100644 index 000000000000..77c969293308 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestContextBootstrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.test.context.TestContextBootstrapper; + +/** + * {@link TestContextBootstrapper} for {@link DataJdbcTest @DataJdbcTest} support. + * + * @author Andy Wilkinson + */ +class DataJdbcTestContextBootstrapper extends SpringBootTestContextBootstrapper { + + @Override + protected String[] getProperties(Class testClass) { + DataJdbcTest annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataJdbcTest.class); + return (annotation != null) ? annotation.properties() : null; + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTypeExcludeFilter.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTypeExcludeFilter.java new file mode 100644 index 000000000000..5d3e340c7ebf --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTypeExcludeFilter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.boot.context.TypeExcludeFilter; +import org.springframework.boot.test.autoconfigure.filter.AnnotationCustomizableTypeExcludeFilter; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.core.annotation.AnnotatedElementUtils; + +/** + * {@link TypeExcludeFilter} for {@link DataJdbcTest @DataJdbcTest}. + * + * @author Andy Wilkinson + */ +class DataJdbcTypeExcludeFilter extends AnnotationCustomizableTypeExcludeFilter { + + private final DataJdbcTest annotation; + + DataJdbcTypeExcludeFilter(Class testClass) { + this.annotation = AnnotatedElementUtils.getMergedAnnotation(testClass, + DataJdbcTest.class); + } + + @Override + protected boolean hasAnnotation() { + return this.annotation != null; + } + + @Override + protected Filter[] getFilters(FilterType type) { + switch (type) { + case INCLUDE: + return this.annotation.includeFilters(); + case EXCLUDE: + return this.annotation.excludeFilters(); + default: + throw new IllegalStateException("Unsupported type " + type); + } + } + + @Override + protected boolean isUseDefaultFilters() { + return this.annotation.useDefaultFilters(); + } + + @Override + protected Set> getDefaultIncludes() { + return Collections.emptySet(); + } + + @Override + protected Set> getComponentIncludes() { + return Collections.emptySet(); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/package-info.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/package-info.java new file mode 100644 index 000000000000..73c617f89513 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/jdbc/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Auto-configuration for Data JDBC tests. + */ +package org.springframework.boot.test.autoconfigure.data.jdbc; diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index cbc25286c25b..adf105572e7f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -2,6 +2,16 @@ org.springframework.boot.test.autoconfigure.core.AutoConfigureCache=\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration +# AutoConfigureDataJdbc auto-configuration imports +org.springframework.boot.test.autoconfigure.data.jdbc.AutoConfigureDataJdbc=\ +org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\ +org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ +org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ +org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\ +org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\ +org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration + # AutoConfigureDataJpa auto-configuration imports org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa=\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestIntegrationTests.java new file mode 100644 index 000000000000..6ecdbff031c9 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestIntegrationTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import javax.sql.DataSource; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration; + +/** + * Integration tests for {@link DataJdbcTest}. + * + * @author Andy Wilkinson + */ +@RunWith(SpringRunner.class) +@DataJdbcTest +@TestPropertySource(properties = "spring.datasource.schema=classpath:org/springframework/boot/test/autoconfigure/data/jdbc/schema.sql") +public class DataJdbcTestIntegrationTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Autowired + private ExampleRepository repository; + + @Autowired + private DataSource dataSource; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Test + public void testRepository() { + this.jdbcTemplate.update( + "INSERT INTO EXAMPLE_ENTITY (id, name, reference) VALUES (1, 'a', 'alpha')"); + this.jdbcTemplate.update( + "INSERT INTO EXAMPLE_ENTITY (id, name, reference) VALUES (2, 'b', 'bravo')"); + assertThat(this.repository.findAll()).hasSize(2); + } + + @Test + public void replacesDefinedDataSourceWithEmbeddedDefault() throws Exception { + String product = this.dataSource.getConnection().getMetaData() + .getDatabaseProductName(); + assertThat(product).isEqualTo("H2"); + } + + @Test + public void didNotInjectExampleComponent() { + this.thrown.expect(NoSuchBeanDefinitionException.class); + this.applicationContext.getBean(ExampleComponent.class); + } + + @Test + public void flywayAutoConfigurationWasImported() { + assertThat(this.applicationContext) + .has(importedAutoConfiguration(FlywayAutoConfiguration.class)); + } + + @Test + public void liquibaseAutoConfigurationWasImported() { + assertThat(this.applicationContext) + .has(importedAutoConfiguration(LiquibaseAutoConfiguration.class)); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestPropertiesIntegrationTests.java new file mode 100644 index 000000000000..b10cf67b54bc --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTestPropertiesIntegrationTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the {@link DataJdbcTest#properties properties} attribute of + * {@link DataJdbcTest @DataJdbcTest}. + * + * @author Andy Wilkinson + */ +@RunWith(SpringRunner.class) +@DataJdbcTest(properties = "spring.profiles.active=test") +public class DataJdbcTestPropertiesIntegrationTests { + + @Autowired + private Environment environment; + + @Test + public void environmentWithNewProfile() { + assertThat(this.environment.getActiveProfiles()).containsExactly("test"); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleComponent.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleComponent.java new file mode 100644 index 000000000000..477b1a8549de --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleComponent.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import org.springframework.stereotype.Component; + +/** + * Example component used with {@link DataJdbcTest} tests. + * + * @author Andy Wilkinson + */ +@Component +public class ExampleComponent { + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleDataJdbcApplication.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleDataJdbcApplication.java new file mode 100644 index 000000000000..cb3b0524eb36 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleDataJdbcApplication.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import javax.sql.DataSource; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; + +/** + * Example {@link SpringBootApplication} used with {@link DataJdbcTest} tests. + * + * @author Andy Wilkinson + */ +@SpringBootApplication +public class ExampleDataJdbcApplication { + + @Bean + public DataSource dataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() + .generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL); + return builder.build(); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleEntity.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleEntity.java new file mode 100644 index 000000000000..6b97a3a6f787 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleEntity.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import org.springframework.data.annotation.Id; + +/** + * Example entity used with {@link DataJdbcTest} tests. + * + * @author Andy Wilkinson + */ +public class ExampleEntity { + + @Id + private Long id; + + private String name; + + private String reference; + + public ExampleEntity(String name, String reference) { + this.name = name; + this.reference = reference; + } + + public String getName() { + return this.name; + } + + public String getReference() { + return this.reference; + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleRepository.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleRepository.java new file mode 100644 index 000000000000..3674b883ff3d --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/jdbc/ExampleRepository.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2018 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.test.autoconfigure.data.jdbc; + +import org.springframework.data.repository.CrudRepository; + +/** + * Example repository used with {@link DataJdbcTest} tests. + * + * @author Andy Wilkinson + */ +public interface ExampleRepository extends CrudRepository { + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/resources/org/springframework/boot/test/autoconfigure/data/jdbc/schema.sql b/spring-boot-project/spring-boot-test-autoconfigure/src/test/resources/org/springframework/boot/test/autoconfigure/data/jdbc/schema.sql new file mode 100644 index 000000000000..6d144184bef1 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/resources/org/springframework/boot/test/autoconfigure/data/jdbc/schema.sql @@ -0,0 +1 @@ +create table example_entity (id int, name varchar, reference varchar); diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc index d46e5bee0b70..a4d77923dcaf 100644 --- a/spring-boot-samples/README.adoc +++ b/spring-boot-samples/README.adoc @@ -50,6 +50,9 @@ The following sample applications are provided: | link:spring-boot-sample-data-elasticsearch[spring-boot-sample-data-elasticsearch] | Stores data using Spring Data Elasticsearch +| link:spring-boot-sample-data-jdbc[spring-boot-sample-data-jdbc] +| Stores data using Spring Data JDBC + | link:spring-boot-sample-data-jpa[spring-boot-sample-data-jpa] | Stores data using Spring Data JPA with Hibernate diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 1ce53cdc5871..c3c9d36904ee 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -35,6 +35,7 @@ spring-boot-sample-data-cassandra spring-boot-sample-data-couchbase spring-boot-sample-data-elasticsearch + spring-boot-sample-data-jdbc spring-boot-sample-data-jpa spring-boot-sample-data-ldap spring-boot-sample-data-mongodb diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/pom.xml b/spring-boot-samples/spring-boot-sample-data-jdbc/pom.xml new file mode 100755 index 000000000000..d1074c312ac4 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + ${revision} + + spring-boot-sample-data-jdbc + Spring Boot Data JDBC Sample + Spring Boot Data JDBC Sample + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-data-jdbc + + + org.springframework.boot + spring-boot-starter-web + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/Customer.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/Customer.java new file mode 100644 index 000000000000..709fe2f1293c --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/Customer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import java.time.LocalDate; + +import org.springframework.data.annotation.Id; + +class Customer { + + @Id + private Long id; + + private String firstName; + + private LocalDate dateOfBirth; + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFirstName() { + return this.firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public LocalDate getDateOfBirth() { + return this.dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/CustomerRepository.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/CustomerRepository.java new file mode 100644 index 000000000000..d3d3f522c617 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/CustomerRepository.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import java.util.List; + +import org.springframework.data.jdbc.repository.query.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +interface CustomerRepository extends CrudRepository { + + @Query("select id, first_name, date_of_birth from customer where upper(first_name) like '%' || upper(:name) || '%' ") + List findByName(@Param("name") String name); + +} diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleController.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleController.java new file mode 100644 index 000000000000..8425f7f31c2d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleController.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import java.util.List; + +import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class SampleController { + + private final CustomerRepository customerRepository; + + public SampleController(CustomerRepository customerRepository) { + this.customerRepository = customerRepository; + } + + @GetMapping("/") + @ResponseBody + @Transactional(readOnly = true) + public List customers(@RequestParam String name) { + return this.customerRepository.findByName(name); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleDataJdbcApplication.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleDataJdbcApplication.java new file mode 100644 index 000000000000..e9ed792a577a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/java/sample/data/jdbc/SampleDataJdbcApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleDataJdbcApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleDataJdbcApplication.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/data.sql b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/data.sql new file mode 100644 index 000000000000..4ad90b6b4956 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/data.sql @@ -0,0 +1,2 @@ +INSERT INTO CUSTOMER (ID, FIRST_NAME, DATE_OF_BIRTH) values (1, 'Meredith', '1998-07-13'); +INSERT INTO CUSTOMER (ID, FIRST_NAME, DATE_OF_BIRTH) values (2, 'Joan', '1982-10-29'); diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/schema.sql b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/schema.sql new file mode 100644 index 000000000000..1b999f2e8015 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/main/resources/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE CUSTOMER ( + ID INTEGER IDENTITY PRIMARY KEY, + FIRST_NAME VARCHAR(30), + DATE_OF_BIRTH DATE +); diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/CustomerRepositoryIntegrationTests.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/CustomerRepositoryIntegrationTests.java new file mode 100644 index 000000000000..296ef5199bbd --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/CustomerRepositoryIntegrationTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link CustomerRepository}. + * + * @author Andy Wilkinson + */ +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureTestDatabase +public class CustomerRepositoryIntegrationTests { + + @Autowired + private CustomerRepository repository; + + @Test + public void findAllCustomers() { + assertThat(this.repository.findAll()).hasSize(2); + } + + @Test + public void findByNameWithMatch() { + assertThat(this.repository.findByName("joan")).hasSize(1); + } + + @Test + public void findByNameWithNoMatch() { + assertThat(this.repository.findByName("hugh")).isEmpty(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/SampleDataJdbcApplicationTests.java b/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/SampleDataJdbcApplicationTests.java new file mode 100644 index 000000000000..fea4709ab002 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-jdbc/src/test/java/sample/data/jdbc/SampleDataJdbcApplicationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2018 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 sample.data.jdbc; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Integration tests for {@link SampleDataJdbcApplication}. + * + * @author Andy Wilkinson + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class SampleDataJdbcApplicationTests { + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + @Test + public void testCustomers() throws Exception { + this.mvc.perform(get("/").param("name", "merEDith")).andExpect(status().isOk()) + .andExpect(content().string(containsString("Meredith"))); + } + +} From 0f7897a0cae0804f10aa36d32b3c6918063f3993 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 14:22:11 +0100 Subject: [PATCH 662/701] Upgrade to Spring Data Lovelace-RELEASE Closes gh-14510 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 540566f1cc7c..62192dd57746 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -161,7 +161,7 @@ 2.1.0.M3 4.1.0.M3 2.0.3.RELEASE - Lovelace-BUILD-SNAPSHOT + Lovelace-RELEASE ${spring.version} 0.25.0.RELEASE 5.1.0.M2 From 258c4838b12c7915e02eb2051bc8267d6d1eafcc Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 14:45:20 +0100 Subject: [PATCH 663/701] Auto-configure Micrometer's Log4j2 metrics Closes gh-14524 --- .../pom.xml | 5 ++ .../Log4J2MetricsAutoConfiguration.java | 48 ++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + .../Log4J2MetricsAutoConfigurationTests.java | 64 +++++++++++++++++++ .../asciidoc/production-ready-features.adoc | 1 + 5 files changed, 119 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index b4eb5f61a30d..b54069cad654 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -198,6 +198,11 @@ commons-dbcp2 true + + org.apache.logging.log4j + log4j-core + true + org.apache.tomcat.embed tomcat-embed-core diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfiguration.java new file mode 100644 index 000000000000..5ffdbc8345e4 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.logging.Log4j2Metrics; +import org.apache.logging.log4j.core.LoggerContext; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Auto-configuration for Log4J2 metrics. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Configuration +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnClass({ Log4j2Metrics.class, LoggerContext.class }) +@ConditionalOnBean(MeterRegistry.class) +public class Log4J2MetricsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public Log4j2Metrics log4j2Metrics() { + return new Log4j2Metrics(); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index dbbf9472723d..0ab29f380037 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -35,6 +35,7 @@ org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAut org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.JvmMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.Log4J2MetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.LogbackMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.MetricsEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..e177454c10e0 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/Log4J2MetricsAutoConfigurationTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.logging.Log4j2Metrics; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link Log4J2MetricsAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class Log4J2MetricsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()).withConfiguration( + AutoConfigurations.of(Log4J2MetricsAutoConfiguration.class)); + + @Test + public void autoConfiguresLog4J2Metrics() { + this.contextRunner + .run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class)); + } + + @Test + public void allowsCustomLog4J2MetricsToBeUsed() { + this.contextRunner.withUserConfiguration(CustomLog4J2MetricsConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class) + .hasBean("customLog4J2Metrics")); + } + + @Configuration + static class CustomLog4J2MetricsConfiguration { + + @Bean + public Log4j2Metrics customLog4J2Metrics() { + return new Log4j2Metrics(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index eea3521e145c..bd62675ae44c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1707,6 +1707,7 @@ Spring Boot registers the following core metrics when applicable: ** Number of classes loaded/unloaded * CPU metrics * File descriptor metrics +* Log4j2 metrics: record the number of events logged to Log4j2 at each level * Logback metrics: record the number of events logged to Logback at each level * Uptime metrics: report a gauge for uptime and a fixed gauge representing the application's absolute start time From def02deaf08828cf40ea3c4c576632901773fd72 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 14:46:43 +0100 Subject: [PATCH 664/701] Make micrometer-registry-dynatrace available to javadoc generation See gh-14522 --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 87f37123be4d..30775bf71593 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -211,6 +211,11 @@ micrometer-registry-datadog true + + io.micrometer + micrometer-registry-dynatrace + true + io.micrometer micrometer-registry-ganglia From eb9f635004798cae9ac71166ac3bb04dff93c322 Mon Sep 17 00:00:00 2001 From: qct Date: Thu, 20 Sep 2018 12:01:16 +0000 Subject: [PATCH 665/701] Migrate size properties to DataSize See gh-14549 --- .../autoconfigure/web/ServerProperties.java | 42 +++++++++---------- .../JettyWebServerFactoryCustomizer.java | 3 +- .../TomcatWebServerFactoryCustomizer.java | 9 ++-- .../UndertowWebServerFactoryCustomizer.java | 6 ++- .../web/ServerPropertiesTests.java | 6 +-- .../appendix-application-properties.adoc | 4 +- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 953f0328e717..82844cd27209 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -325,14 +325,14 @@ public static class Tomcat { private int minSpareThreads = 10; /** - * Maximum size, in bytes, of the HTTP post content. + * Maximum size of the HTTP post content. */ - private int maxHttpPostSize = 2097152; + private DataSize maxHttpPostSize = DataSize.ofMegabytes(2); /** * Maximum size, in bytes, of the HTTP message header. */ - private int maxHttpHeaderSize = 0; + private DataSize maxHttpHeaderSize = DataSize.ofBytes(0); /** * Maximum amount of request body to swallow. @@ -397,11 +397,11 @@ public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; } - public int getMaxHttpPostSize() { + public DataSize getMaxHttpPostSize() { return this.maxHttpPostSize; } - public void setMaxHttpPostSize(int maxHttpPostSize) { + public void setMaxHttpPostSize(DataSize maxHttpPostSize) { this.maxHttpPostSize = maxHttpPostSize; } @@ -499,12 +499,12 @@ public void setMaxConnections(int maxConnections) { @Deprecated @DeprecatedConfigurationProperty(replacement = "server.max-http-header-size") - public int getMaxHttpHeaderSize() { + public DataSize getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } @Deprecated - public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { + public void setMaxHttpHeaderSize(DataSize maxHttpHeaderSize) { this.maxHttpHeaderSize = maxHttpHeaderSize; } @@ -722,9 +722,9 @@ public static class Jetty { private final Accesslog accesslog = new Accesslog(); /** - * Maximum size, in bytes, of the HTTP post or put content. + * Maximum size of the HTTP post or put content. */ - private int maxHttpPostSize = 200000; // bytes + private DataSize maxHttpPostSize = DataSize.ofBytes(200000); /** * Number of acceptor threads to use. When the value is -1, the default, the @@ -742,11 +742,11 @@ public Accesslog getAccesslog() { return this.accesslog; } - public int getMaxHttpPostSize() { + public DataSize getMaxHttpPostSize() { return this.maxHttpPostSize; } - public void setMaxHttpPostSize(int maxHttpPostSize) { + public void setMaxHttpPostSize(DataSize maxHttpPostSize) { this.maxHttpPostSize = maxHttpPostSize; } @@ -937,16 +937,16 @@ public void setLogLatency(boolean logLatency) { public static class Undertow { /** - * Maximum size, in bytes, of the HTTP post content. When the value is -1, the - * default, the size is unlimited. + * Maximum size of the HTTP post content. When the value is -1, the default, the + * size is unlimited. */ - private long maxHttpPostSize = -1; // bytes + private DataSize maxHttpPostSize = DataSize.ofBytes(-1); /** - * Size of each buffer, in bytes. The default is derived from the maximum amount - * of memory that is available to the JVM. + * Size of each buffer. The default is derived from the maximum amount of memory + * that is available to the JVM. */ - private Integer bufferSize; + private DataSize bufferSize = DataSize.ofBytes(0); /** * Number of I/O threads to create for the worker. The default is derived from the @@ -972,19 +972,19 @@ public static class Undertow { private final Accesslog accesslog = new Accesslog(); - public long getMaxHttpPostSize() { + public DataSize getMaxHttpPostSize() { return this.maxHttpPostSize; } - public void setMaxHttpPostSize(long maxHttpPostSize) { + public void setMaxHttpPostSize(DataSize maxHttpPostSize) { this.maxHttpPostSize = maxHttpPostSize; } - public Integer getBufferSize() { + public DataSize getBufferSize() { return this.bufferSize; } - public void setBufferSize(Integer bufferSize) { + public void setBufferSize(DataSize bufferSize) { this.bufferSize = bufferSize; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java index 5dab73bd8363..b6b8129a88a5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java @@ -78,7 +78,8 @@ public void customize(ConfigurableJettyWebServerFactory factory) { .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); - propertyMapper.from(jettyProperties::getMaxHttpPostSize).when(this::isPositive) + propertyMapper.from(jettyProperties::getMaxHttpPostSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(properties::getConnectionTimeout).whenNonNull() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 3bf75348d208..cd8e8d6e8484 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -92,8 +92,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull() .asInt(DataSize::toBytes) .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); - propertyMapper.from(tomcatProperties::getMaxHttpPostSize) - .when((maxHttpPostSize) -> maxHttpPostSize != 0) + propertyMapper.from(tomcatProperties::getMaxHttpPostSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(tomcatProperties::getAccesslog) @@ -118,9 +118,8 @@ private boolean isPositive(int value) { @SuppressWarnings("deprecation") private DataSize determineMaxHttpHeaderSize() { - return isPositive(this.serverProperties.getTomcat().getMaxHttpHeaderSize()) - ? DataSize - .ofBytes(this.serverProperties.getTomcat().getMaxHttpHeaderSize()) + return (this.serverProperties.getTomcat().getMaxHttpHeaderSize().toBytes() > 0) + ? this.serverProperties.getTomcat().getMaxHttpHeaderSize() : this.serverProperties.getMaxHttpHeaderSize(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java index c08ef547db40..2ba3e644abdb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java @@ -64,7 +64,8 @@ public void customize(ConfigurableUndertowWebServerFactory factory) { ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties .getAccesslog(); PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull(); - propertyMapper.from(undertowProperties::getBufferSize).to(factory::setBufferSize); + propertyMapper.from(undertowProperties::getBufferSize).whenNonNull() + .asInt(DataSize::toBytes).to(factory::setBufferSize); propertyMapper.from(undertowProperties::getIoThreads).to(factory::setIoThreads); propertyMapper.from(undertowProperties::getWorkerThreads) .to(factory::setWorkerThreads); @@ -88,7 +89,8 @@ public void customize(ConfigurableUndertowWebServerFactory factory) { .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); - propertyMapper.from(undertowProperties::getMaxHttpPostSize).when(this::isPositive) + propertyMapper.from(undertowProperties::getMaxHttpPostSize).whenNonNull() + .asInt(DataSize::toBytes) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(properties::getConnectionTimeout) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index b909677ea38e..6a9a849838f0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -226,7 +226,7 @@ public void tomcatMinSpareThreadsMatchesProtocolDefault() throws Exception { @Test public void tomcatMaxHttpPostSizeMatchesConnectorDefault() throws Exception { - assertThat(this.properties.getTomcat().getMaxHttpPostSize()) + assertThat(this.properties.getTomcat().getMaxHttpPostSize().toBytes()) .isEqualTo(getDefaultConnector().getMaxPostSize()); } @@ -333,7 +333,7 @@ public void handleError(ClientHttpResponse response) throws IOException { String message = failure.get().getCause().getMessage(); int defaultMaxPostSize = Integer .valueOf(message.substring(message.lastIndexOf(' ')).trim()); - assertThat(this.properties.getJetty().getMaxHttpPostSize()) + assertThat(this.properties.getJetty().getMaxHttpPostSize().toBytes()) .isEqualTo(defaultMaxPostSize); } finally { @@ -343,7 +343,7 @@ public void handleError(ClientHttpResponse response) throws IOException { @Test public void undertowMaxHttpPostSizeMatchesDefault() { - assertThat(this.properties.getUndertow().getMaxHttpPostSize()) + assertThat(this.properties.getUndertow().getMaxHttpPostSize().toBytes()) .isEqualTo(UndertowOptions.DEFAULT_MAX_ENTITY_SIZE); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e14a368bf3dd..06c2a19b28a0 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -263,7 +263,7 @@ content into your application. Rather, pick only the properties that you need. 172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3} # Regular expression matching trusted IP addresses. server.tomcat.max-connections=10000 # Maximum number of connections that the server will accept and process at any given time. - server.tomcat.max-http-post-size=2097152 # Maximum size in bytes of the HTTP post content. + server.tomcat.max-http-post-size=2MB # Maximum size of the HTTP post content. server.tomcat.max-swallow-size=2MB # Maximum amount of request body to swallow. server.tomcat.max-threads=200 # Maximum amount of worker threads. server.tomcat.min-spare-threads=10 # Minimum amount of worker threads. @@ -282,7 +282,7 @@ content into your application. Rather, pick only the properties that you need. server.undertow.accesslog.prefix=access_log. # Log file name prefix. server.undertow.accesslog.rotate=true # Whether to enable access log rotation. server.undertow.accesslog.suffix=log # Log file name suffix. - server.undertow.buffer-size= # Size of each buffer, in bytes. + server.undertow.buffer-size=0 # Size of each buffer, in bytes. server.undertow.direct-buffers= # Allocate buffers outside the Java heap. The default is derived from the maximum amount of memory that is available to the JVM. server.undertow.eager-filter-init=true # Whether servlet filters should be initialized on startup. server.undertow.io-threads= # Number of I/O threads to create for the worker. The default is derived from the number of available processors. From cbae22f0c9137feacf00c9df9c9e379a24e4a786 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 21 Sep 2018 14:43:10 +0200 Subject: [PATCH 666/701] Polish "Migrate size properties to DataSize" Closes gh-14549 --- .../DiskSpaceHealthIndicatorProperties.java | 16 +++-- ...HealthIndicatorAutoConfigurationTests.java | 27 +++++++- .../system/DiskSpaceHealthIndicator.java | 26 ++++++-- .../system/DiskSpaceHealthIndicatorTests.java | 33 +++++----- .../autoconfigure/kafka/KafkaProperties.java | 62 ++++++++++++------- .../EmbeddedMongoAutoConfiguration.java | 3 +- .../embedded/EmbeddedMongoProperties.java | 14 +++-- .../thymeleaf/ThymeleafAutoConfiguration.java | 5 +- .../thymeleaf/ThymeleafProperties.java | 13 ++-- .../autoconfigure/web/ServerProperties.java | 2 +- .../JettyWebServerFactoryCustomizer.java | 4 +- .../TomcatWebServerFactoryCustomizer.java | 4 +- .../UndertowWebServerFactoryCustomizer.java | 4 +- ...itional-spring-configuration-metadata.json | 6 ++ .../kafka/KafkaAutoConfigurationTests.java | 32 +++++++--- .../EmbeddedMongoAutoConfigurationTests.java | 9 ++- ...ymeleafReactiveAutoConfigurationTests.java | 4 +- .../appendix-application-properties.adoc | 24 +++---- .../embedded/jetty/JettyHandlerWrappers.java | 2 +- .../embedded/netty/CompressionCustomizer.java | 5 +- .../CompressionConnectorCustomizer.java | 2 +- .../UndertowCompressionConfigurer.java | 3 +- .../boot/web/server/Compression.java | 8 ++- ...AbstractReactiveWebServerFactoryTests.java | 3 +- 24 files changed, 205 insertions(+), 106 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorProperties.java index 5b954e18d79b..32cc54b2fc20 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorProperties.java @@ -21,29 +21,27 @@ import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; +import org.springframework.util.unit.DataSize; /** * External configuration properties for {@link DiskSpaceHealthIndicator}. * * @author Andy Wilkinson + * @author Stephane Nicoll * @since 1.2.0 */ @ConfigurationProperties(prefix = "management.health.diskspace") public class DiskSpaceHealthIndicatorProperties { - private static final int MEGABYTES = 1024 * 1024; - - private static final int DEFAULT_THRESHOLD = 10 * MEGABYTES; - /** * Path used to compute the available disk space. */ private File path = new File("."); /** - * Minimum disk space, in bytes, that should be available. + * Minimum disk space that should be available. */ - private long threshold = DEFAULT_THRESHOLD; + private DataSize threshold = DataSize.ofMegabytes(10); public File getPath() { return this.path; @@ -55,12 +53,12 @@ public void setPath(File path) { this.path = path; } - public long getThreshold() { + public DataSize getThreshold() { return this.threshold; } - public void setThreshold(long threshold) { - Assert.isTrue(threshold >= 0, "threshold must be greater than 0"); + public void setThreshold(DataSize threshold) { + Assert.isTrue(!threshold.isNegative(), "threshold must be greater than 0"); this.threshold = threshold; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorAutoConfigurationTests.java index fd5407102e29..2c3d9a867bf6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/system/DiskSpaceHealthIndicatorAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -18,11 +18,13 @@ import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.util.unit.DataSize; import static org.assertj.core.api.Assertions.assertThat; @@ -30,6 +32,7 @@ * Tests for {@link DiskSpaceHealthIndicatorAutoConfiguration}. * * @author Phillip Webb + * @author Stephane Nicoll */ public class DiskSpaceHealthIndicatorAutoConfigurationTests { @@ -45,6 +48,28 @@ public void runShouldCreateIndicator() { .doesNotHaveBean(ApplicationHealthIndicator.class)); } + @Test + public void thresholdMustBePositive() { + this.contextRunner + .withPropertyValues("management.health.diskspace.threshold=-10MB") + .run((context) -> assertThat(context).hasFailed().getFailure() + .hasMessageContaining( + "Failed to bind properties under 'management.health.diskspace'")); + } + + @Test + public void thresholdCanBeCustomized() { + this.contextRunner + .withPropertyValues("management.health.diskspace.threshold=20MB") + .run((context) -> { + assertThat(context).hasSingleBean(DiskSpaceHealthIndicator.class); + DirectFieldAccessor dfa = new DirectFieldAccessor( + context.getBean(DiskSpaceHealthIndicator.class)); + assertThat(dfa.getPropertyValue("threshold")) + .isEqualTo(DataSize.ofMegabytes(20)); + }); + } + @Test public void runWhenDisabledShouldNotCreateIndicator() { this.contextRunner.withPropertyValues("management.health.diskspace.enabled:false") diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java index 9576c67658b7..8d478c7381c3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java @@ -25,6 +25,7 @@ import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.Status; +import org.springframework.util.unit.DataSize; /** * A {@link HealthIndicator} that checks available disk space and reports a status of @@ -32,6 +33,7 @@ * * @author Mattias Severson * @author Andy Wilkinson + * @author Stephane Nicoll * @since 2.0.0 */ public class DiskSpaceHealthIndicator extends AbstractHealthIndicator { @@ -40,35 +42,47 @@ public class DiskSpaceHealthIndicator extends AbstractHealthIndicator { private final File path; - private final long threshold; + private final DataSize threshold; /** * Create a new {@code DiskSpaceHealthIndicator} instance. * @param path the Path used to compute the available disk space - * @param threshold the minimum disk space that should be available (in bytes) + * @param threshold the minimum disk space that should be available */ - public DiskSpaceHealthIndicator(File path, long threshold) { + public DiskSpaceHealthIndicator(File path, DataSize threshold) { super("DiskSpace health check failed"); this.path = path; this.threshold = threshold; } + /** + * Create a new {@code DiskSpaceHealthIndicator} instance. + * @param path the Path used to compute the available disk space + * @param threshold the minimum disk space that should be available (in bytes) + * @deprecated since 2.1.0 in favour of + * {@link #DiskSpaceHealthIndicator(File, DataSize)} + */ + @Deprecated + public DiskSpaceHealthIndicator(File path, long threshold) { + this(path, DataSize.ofBytes(threshold)); + } + @Override protected void doHealthCheck(Health.Builder builder) throws Exception { long diskFreeInBytes = this.path.getUsableSpace(); - if (diskFreeInBytes >= this.threshold) { + if (diskFreeInBytes >= this.threshold.toBytes()) { builder.up(); } else { logger.warn(String.format( "Free disk space below threshold. " - + "Available: %d bytes (threshold: %d bytes)", + + "Available: %d bytes (threshold: %s)", diskFreeInBytes, this.threshold)); builder.down(); } builder.withDetail("total", this.path.getTotalSpace()) .withDetail("free", diskFreeInBytes) - .withDetail("threshold", this.threshold); + .withDetail("threshold", this.threshold.toBytes()); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicatorTests.java index ae0f5ef9c859..1bc8cc6db23d 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -28,6 +28,7 @@ import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.Status; +import org.springframework.util.unit.DataSize; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -36,10 +37,13 @@ * Tests for {@link DiskSpaceHealthIndicator}. * * @author Mattias Severson + * @author Stephane Nicoll */ public class DiskSpaceHealthIndicatorTests { - static final long THRESHOLD_BYTES = 1024; + private static final DataSize THRESHOLD = DataSize.ofKilobytes(1); + + private static final DataSize TOTAL_SPACE = DataSize.ofKilobytes(10); @Rule public ExpectedException exception = ExpectedException.none(); @@ -54,30 +58,31 @@ public void setUp() { MockitoAnnotations.initMocks(this); given(this.fileMock.exists()).willReturn(true); given(this.fileMock.canRead()).willReturn(true); - this.healthIndicator = new DiskSpaceHealthIndicator(this.fileMock, - THRESHOLD_BYTES); + this.healthIndicator = new DiskSpaceHealthIndicator(this.fileMock, THRESHOLD); } @Test public void diskSpaceIsUp() { - given(this.fileMock.getUsableSpace()).willReturn(THRESHOLD_BYTES + 10); - given(this.fileMock.getTotalSpace()).willReturn(THRESHOLD_BYTES * 10); + long freeSpace = THRESHOLD.toBytes() + 10; + given(this.fileMock.getUsableSpace()).willReturn(freeSpace); + given(this.fileMock.getTotalSpace()).willReturn(TOTAL_SPACE.toBytes()); Health health = this.healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.UP); - assertThat(health.getDetails().get("threshold")).isEqualTo(THRESHOLD_BYTES); - assertThat(health.getDetails().get("free")).isEqualTo(THRESHOLD_BYTES + 10); - assertThat(health.getDetails().get("total")).isEqualTo(THRESHOLD_BYTES * 10); + assertThat(health.getDetails().get("threshold")).isEqualTo(THRESHOLD.toBytes()); + assertThat(health.getDetails().get("free")).isEqualTo(freeSpace); + assertThat(health.getDetails().get("total")).isEqualTo(TOTAL_SPACE.toBytes()); } @Test public void diskSpaceIsDown() { - given(this.fileMock.getUsableSpace()).willReturn(THRESHOLD_BYTES - 10); - given(this.fileMock.getTotalSpace()).willReturn(THRESHOLD_BYTES * 10); + long freeSpace = THRESHOLD.toBytes() - 10; + given(this.fileMock.getUsableSpace()).willReturn(freeSpace); + given(this.fileMock.getTotalSpace()).willReturn(TOTAL_SPACE.toBytes()); Health health = this.healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.DOWN); - assertThat(health.getDetails().get("threshold")).isEqualTo(THRESHOLD_BYTES); - assertThat(health.getDetails().get("free")).isEqualTo(THRESHOLD_BYTES - 10); - assertThat(health.getDetails().get("total")).isEqualTo(THRESHOLD_BYTES * 10); + assertThat(health.getDetails().get("threshold")).isEqualTo(THRESHOLD.toBytes()); + assertThat(health.getDetails().get("free")).isEqualTo(freeSpace); + assertThat(health.getDetails().get("total")).isEqualTo(TOTAL_SPACE.toBytes()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java index 763054dd48a6..1f42906894ef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java @@ -33,12 +33,14 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.convert.DurationUnit; import org.springframework.core.io.Resource; import org.springframework.kafka.listener.ContainerProperties.AckMode; import org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer; import org.springframework.util.CollectionUtils; +import org.springframework.util.unit.DataSize; /** * Configuration properties for Spring for Apache Kafka. @@ -247,14 +249,14 @@ public static class Consumer { /** * Maximum amount of time the server blocks before answering the fetch request if * there isn't sufficient data to immediately satisfy the requirement given by - * "fetch.min.bytes". + * "fetch-min-size". */ private Duration fetchMaxWait; /** - * Minimum amount of data, in bytes, the server should return for a fetch request. + * Minimum amount of data the server should return for a fetch request. */ - private Integer fetchMinSize; + private DataSize fetchMinSize; /** * Unique string that identifies the consumer group to which this consumer @@ -339,11 +341,11 @@ public void setFetchMaxWait(Duration fetchMaxWait) { this.fetchMaxWait = fetchMaxWait; } - public Integer getFetchMinSize() { + public DataSize getFetchMinSize() { return this.fetchMinSize; } - public void setFetchMinSize(Integer fetchMinSize) { + public void setFetchMinSize(DataSize fetchMinSize) { this.fetchMinSize = fetchMinSize; } @@ -406,7 +408,7 @@ public Map buildProperties() { .to(properties.in(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG)); map.from(this::getFetchMaxWait).asInt(Duration::toMillis) .to(properties.in(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG)); - map.from(this::getFetchMinSize) + map.from(this::getFetchMinSize).asInt(DataSize::toBytes) .to(properties.in(ConsumerConfig.FETCH_MIN_BYTES_CONFIG)); map.from(this::getGroupId).to(properties.in(ConsumerConfig.GROUP_ID_CONFIG)); map.from(this::getHeartbeatInterval).asInt(Duration::toMillis) @@ -433,10 +435,10 @@ public static class Producer { private String acks; /** - * Default batch size in bytes. A small batch size will make batching less common - * and may reduce throughput (a batch size of zero disables batching entirely). + * Default batch size. A small batch size will make batching less common and may + * reduce throughput (a batch size of zero disables batching entirely). */ - private Integer batchSize; + private DataSize batchSize; /** * Comma-delimited list of host:port pairs to use for establishing the initial @@ -445,10 +447,10 @@ public static class Producer { private List bootstrapServers; /** - * Total bytes of memory the producer can use to buffer records waiting to be sent - * to the server. + * Total memory size the producer can use to buffer records waiting to be sent to + * the server. */ - private Long bufferMemory; + private DataSize bufferMemory; /** * ID to pass to the server when making requests. Used for server-side logging. @@ -497,11 +499,11 @@ public void setAcks(String acks) { this.acks = acks; } - public Integer getBatchSize() { + public DataSize getBatchSize() { return this.batchSize; } - public void setBatchSize(Integer batchSize) { + public void setBatchSize(DataSize batchSize) { this.batchSize = batchSize; } @@ -513,11 +515,11 @@ public void setBootstrapServers(List bootstrapServers) { this.bootstrapServers = bootstrapServers; } - public Long getBufferMemory() { + public DataSize getBufferMemory() { return this.bufferMemory; } - public void setBufferMemory(Long bufferMemory) { + public void setBufferMemory(DataSize bufferMemory) { this.bufferMemory = bufferMemory; } @@ -577,11 +579,11 @@ public Map buildProperties() { Properties properties = new Properties(); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this::getAcks).to(properties.in(ProducerConfig.ACKS_CONFIG)); - map.from(this::getBatchSize) + map.from(this::getBatchSize).asInt(DataSize::toBytes) .to(properties.in(ProducerConfig.BATCH_SIZE_CONFIG)); map.from(this::getBootstrapServers) .to(properties.in(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)); - map.from(this::getBufferMemory) + map.from(this::getBufferMemory).as(DataSize::toBytes) .to(properties.in(ProducerConfig.BUFFER_MEMORY_CONFIG)); map.from(this::getClientId) .to(properties.in(ProducerConfig.CLIENT_ID_CONFIG)); @@ -674,9 +676,9 @@ public static class Streams { private List bootstrapServers; /** - * Maximum number of memory bytes to be used for buffering across all threads. + * Maximum memory size to be used for buffering across all threads. */ - private Integer cacheMaxBytesBuffering; + private DataSize cacheMaxSizeBuffering; /** * ID to pass to the server when making requests. Used for server-side logging. @@ -727,12 +729,26 @@ public void setBootstrapServers(List bootstrapServers) { this.bootstrapServers = bootstrapServers; } + @DeprecatedConfigurationProperty(replacement = "spring.kafka.streams.cache-max-size-buffering") + @Deprecated public Integer getCacheMaxBytesBuffering() { - return this.cacheMaxBytesBuffering; + return (this.cacheMaxSizeBuffering != null) + ? (int) this.cacheMaxSizeBuffering.toBytes() : null; } + @Deprecated public void setCacheMaxBytesBuffering(Integer cacheMaxBytesBuffering) { - this.cacheMaxBytesBuffering = cacheMaxBytesBuffering; + DataSize cacheMaxSizeBuffering = (cacheMaxBytesBuffering != null) + ? DataSize.ofBytes(cacheMaxBytesBuffering) : null; + setCacheMaxSizeBuffering(cacheMaxSizeBuffering); + } + + public DataSize getCacheMaxSizeBuffering() { + return this.cacheMaxSizeBuffering; + } + + public void setCacheMaxSizeBuffering(DataSize cacheMaxSizeBuffering) { + this.cacheMaxSizeBuffering = cacheMaxSizeBuffering; } public String getClientId() { @@ -769,7 +785,7 @@ public Map buildProperties() { map.from(this::getApplicationId).to(properties.in("application.id")); map.from(this::getBootstrapServers) .to(properties.in(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG)); - map.from(this::getCacheMaxBytesBuffering) + map.from(this::getCacheMaxSizeBuffering).asInt(DataSize::toBytes) .to(properties.in("cache.max.bytes.buffering")); map.from(this::getClientId) .to(properties.in(CommonClientConfigs.CLIENT_ID_CONFIG)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 2fbd777fefd5..5be48fdc6c61 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -134,7 +134,8 @@ public IMongodConfig embeddedMongoConfiguration() throws IOException { if (storage != null) { String databaseDir = storage.getDatabaseDir(); String replSetName = storage.getReplSetName(); - int oplogSize = (storage.getOplogSize() != null) ? storage.getOplogSize() : 0; + int oplogSize = (storage.getOplogSize() != null) + ? (int) storage.getOplogSize().toMegabytes() : 0; builder.replication(new Storage(databaseDir, replSetName, oplogSize)); } Integer configuredPort = this.properties.getPort(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java index 9814ba06f345..96a450db305e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,6 +23,9 @@ import de.flapdoodle.embed.mongo.distribution.Feature; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.convert.DataSizeUnit; +import org.springframework.util.unit.DataSize; +import org.springframework.util.unit.DataUnit; /** * Configuration properties for Embedded Mongo. @@ -70,9 +73,10 @@ public Storage getStorage() { public static class Storage { /** - * Maximum size of the oplog, in megabytes. + * Maximum size of the oplog. */ - private Integer oplogSize; + @DataSizeUnit(DataUnit.MEGABYTES) + private DataSize oplogSize; /** * Name of the replica set. @@ -84,11 +88,11 @@ public static class Storage { */ private String databaseDir; - public Integer getOplogSize() { + public DataSize getOplogSize() { return this.oplogSize; } - public void setOplogSize(Integer oplogSize) { + public void setOplogSize(DataSize oplogSize) { this.oplogSize = oplogSize; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 1490a2a94d48..8ef9e53c352b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -57,6 +57,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.util.MimeType; +import org.springframework.util.unit.DataSize; import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; /** @@ -283,8 +284,8 @@ private void mapReactiveProperties(Reactive properties, PropertyMapper map = PropertyMapper.get(); map.from(properties::getMediaTypes).whenNonNull() .to(resolver::setSupportedMediaTypes); - map.from(properties::getMaxChunkSize).when((size) -> size > 0) - .to(resolver::setResponseMaxChunkSizeBytes); + map.from(properties::getMaxChunkSize).asInt(DataSize::toBytes) + .when((size) -> size > 0).to(resolver::setResponseMaxChunkSizeBytes); map.from(properties::getFullModeViewNames).to(resolver::setFullModeViewNames); map.from(properties::getChunkedModeViewNames) .to(resolver::setChunkedModeViewNames); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafProperties.java index aa2f2d18ff93..84245030a318 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,6 +23,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.MediaType; import org.springframework.util.MimeType; +import org.springframework.util.unit.DataSize; /** * Properties for Thymeleaf. @@ -233,10 +234,10 @@ public void setContentType(MimeType contentType) { public static class Reactive { /** - * Maximum size of data buffers used for writing to the response, in bytes. - * Templates will execute in CHUNKED mode by default if this is set. + * Maximum size of data buffers used for writing to the response. Templates will + * execute in CHUNKED mode by default if this is set. */ - private int maxChunkSize; + private DataSize maxChunkSize = DataSize.ofBytes(0); /** * Media types supported by the view technology. @@ -263,11 +264,11 @@ public void setMediaTypes(List mediaTypes) { this.mediaTypes = mediaTypes; } - public int getMaxChunkSize() { + public DataSize getMaxChunkSize() { return this.maxChunkSize; } - public void setMaxChunkSize(int maxChunkSize) { + public void setMaxChunkSize(DataSize maxChunkSize) { this.maxChunkSize = maxChunkSize; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 82844cd27209..1c50ecaa8229 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -946,7 +946,7 @@ public static class Undertow { * Size of each buffer. The default is derived from the maximum amount of memory * that is available to the JVM. */ - private DataSize bufferSize = DataSize.ofBytes(0); + private DataSize bufferSize; /** * Number of I/O threads to create for the worker. The default is derived from the diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java index b6b8129a88a5..85a649ecb4e6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java @@ -78,8 +78,8 @@ public void customize(ConfigurableJettyWebServerFactory factory) { .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); - propertyMapper.from(jettyProperties::getMaxHttpPostSize).whenNonNull() - .asInt(DataSize::toBytes) + propertyMapper.from(jettyProperties::getMaxHttpPostSize).asInt(DataSize::toBytes) + .when(this::isPositive) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(properties::getConnectionTimeout).whenNonNull() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index cd8e8d6e8484..18b756f6df56 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -92,8 +92,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull() .asInt(DataSize::toBytes) .to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize)); - propertyMapper.from(tomcatProperties::getMaxHttpPostSize).whenNonNull() - .asInt(DataSize::toBytes) + propertyMapper.from(tomcatProperties::getMaxHttpPostSize).asInt(DataSize::toBytes) + .when((maxHttpPostSize) -> maxHttpPostSize != 0) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(tomcatProperties::getAccesslog) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java index 2ba3e644abdb..2151cae4f6c2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java @@ -89,8 +89,8 @@ public void customize(ConfigurableUndertowWebServerFactory factory) { .asInt(DataSize::toBytes) .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); - propertyMapper.from(undertowProperties::getMaxHttpPostSize).whenNonNull() - .asInt(DataSize::toBytes) + propertyMapper.from(undertowProperties::getMaxHttpPostSize) + .asInt(DataSize::toBytes).when(this::isPositive) .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(properties::getConnectionTimeout) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 193f9567d45d..27770b77b566 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -29,6 +29,12 @@ "level": "error" } }, + { + "name": "server.compression.min-response-size", + "description": "Minimum \"Content-Length\" value that is required for compression to be performed.", + "type": "org.springframework.util.unit.DataSize", + "defaultValue": "2KB" + }, { "name": "server.error.include-stacktrace", "defaultValue": "never" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java index f5262c3a3169..9ae1dfa3563e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/kafka/KafkaAutoConfigurationTests.java @@ -100,7 +100,7 @@ public void consumerProperties() { "spring.kafka.consumer.enable-auto-commit=false", "spring.kafka.consumer.fetch-max-wait=456", "spring.kafka.consumer.properties.fiz.buz=fix.fox", - "spring.kafka.consumer.fetch-min-size=789", + "spring.kafka.consumer.fetch-min-size=1KB", "spring.kafka.consumer.group-id=bar", "spring.kafka.consumer.heartbeat-interval=234", "spring.kafka.consumer.key-deserializer = org.apache.kafka.common.serialization.LongDeserializer", @@ -143,7 +143,7 @@ public void consumerProperties() { assertThat(configs.get(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG)) .isEqualTo(456); assertThat(configs.get(ConsumerConfig.FETCH_MIN_BYTES_CONFIG)) - .isEqualTo(789); + .isEqualTo(1024); assertThat(configs.get(ConsumerConfig.GROUP_ID_CONFIG)) .isEqualTo("bar"); assertThat(configs.get(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG)) @@ -166,10 +166,10 @@ public void consumerProperties() { public void producerProperties() { this.contextRunner.withPropertyValues("spring.kafka.clientId=cid", "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", - "spring.kafka.producer.acks=all", "spring.kafka.producer.batch-size=20", + "spring.kafka.producer.acks=all", "spring.kafka.producer.batch-size=2KB", "spring.kafka.producer.bootstrap-servers=bar:1234", // test // override - "spring.kafka.producer.buffer-memory=12345", + "spring.kafka.producer.buffer-memory=4KB", "spring.kafka.producer.compression-type=gzip", "spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.LongSerializer", "spring.kafka.producer.retries=2", @@ -194,11 +194,11 @@ public void producerProperties() { // producer assertThat(configs.get(ProducerConfig.ACKS_CONFIG)).isEqualTo("all"); assertThat(configs.get(ProducerConfig.BATCH_SIZE_CONFIG)) - .isEqualTo(20); + .isEqualTo(2048); assertThat(configs.get(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)) .isEqualTo(Collections.singletonList("bar:1234")); // override assertThat(configs.get(ProducerConfig.BUFFER_MEMORY_CONFIG)) - .isEqualTo(12345L); + .isEqualTo(4096L); assertThat(configs.get(ProducerConfig.COMPRESSION_TYPE_CONFIG)) .isEqualTo("gzip"); assertThat(configs.get(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG)) @@ -290,7 +290,7 @@ public void streamsProperties() { "spring.application.name=appName", "spring.kafka.properties.foo.bar.baz=qux.fiz.buz", "spring.kafka.streams.auto-startup=false", - "spring.kafka.streams.cache-max-bytes-buffering=42", + "spring.kafka.streams.cache-max-size-buffering=1KB", "spring.kafka.streams.client-id=override", "spring.kafka.streams.properties.fiz.buz=fix.fox", "spring.kafka.streams.replication-factor=2", @@ -311,7 +311,7 @@ public void streamsProperties() { .isEqualTo("localhost:9092, localhost:9093"); assertThat( configs.get(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG)) - .isEqualTo("42"); + .isEqualTo("1024"); assertThat(configs.get(StreamsConfig.CLIENT_ID_CONFIG)) .isEqualTo("override"); assertThat(configs.get(StreamsConfig.REPLICATION_FACTOR_CONFIG)) @@ -347,6 +347,22 @@ public void streamsProperties() { }); } + @Test + @Deprecated + public void streamPropertiesWithCustomCacheMaxBytesBuffering() { + this.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class) + .withPropertyValues("spring.application.name=appName", + "spring.kafka.streams.cache-max-bytes-buffering=42") + .run((context) -> { + Properties configs = context.getBean( + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME, + KafkaStreamsConfiguration.class).asProperties(); + assertThat( + configs.get(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG)) + .isEqualTo("42"); + }); + } + @Test public void streamsApplicationIdUsesMainApplicationNameByDefault() { this.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index 554e47f4b89a..99248a4022ad 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -139,6 +139,13 @@ public void mongoWritesToCustomDatabaseDir() { @Test public void customOpLogSizeIsAppliedToConfiguration() { + load("spring.mongodb.embedded.storage.oplogSize=1024KB"); + assertThat(this.context.getBean(IMongodConfig.class).replication().getOplogSize()) + .isEqualTo(1); + } + + @Test + public void customOpLogSizeUsesMegabytesPerDefault() { load("spring.mongodb.embedded.storage.oplogSize=10"); assertThat(this.context.getBean(IMongodConfig.class).replication().getOplogSize()) .isEqualTo(10); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafReactiveAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafReactiveAutoConfigurationTests.java index 934a7860ae72..f93b05589000 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafReactiveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafReactiveAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -116,7 +116,7 @@ public void overrideViewNames() { @Test public void overrideMaxChunkSize() { - load(BaseConfiguration.class, "spring.thymeleaf.reactive.maxChunkSize:8192"); + load(BaseConfiguration.class, "spring.thymeleaf.reactive.maxChunkSize:8KB"); ThymeleafReactiveViewResolver views = this.context .getBean(ThymeleafReactiveViewResolver.class); assertThat(views.getResponseMaxChunkSizeBytes()).isEqualTo(Integer.valueOf(8192)); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 06c2a19b28a0..1aae35ae98b0 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -183,7 +183,7 @@ content into your application. Rather, pick only the properties that you need. server.compression.enabled=false # Whether response compression is enabled. server.compression.excluded-user-agents= # List of user-agents to exclude from compression. server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml # Comma-separated list of MIME types that should be compressed. - server.compression.min-response-size=2048 # Minimum "Content-Length" value that is required for compression to be performed. + server.compression.min-response-size=2KB # Minimum "Content-Length" value that is required for compression to be performed. server.connection-timeout= # Time that connectors wait for another HTTP request before closing the connection. When not set, the connector's container-specific default is used. Use a value of -1 to indicate no (that is, an infinite) timeout. server.error.include-exception=false # Include the "exception" attribute. server.error.include-stacktrace=never # When to include a "stacktrace" attribute. @@ -203,7 +203,7 @@ content into your application. Rather, pick only the properties that you need. server.jetty.accesslog.log-server=false # Enable logging of the request hostname. server.jetty.accesslog.retention-period=31 # Number of days before rotated log files are deleted. server.jetty.accesslog.time-zone=GMT # Timezone of the request log. - server.jetty.max-http-post-size=200000 # Maximum size, in bytes, of the HTTP post or put content. + server.jetty.max-http-post-size=200000B # Maximum size of the HTTP post or put content. server.jetty.selectors=-1 # Number of selector threads to use. When the value is -1, the default, the number of selectors is derived from the operating environment. server.max-http-header-size=8KB # Maximum size of the HTTP message header. server.port=8080 # Server HTTP port. @@ -282,11 +282,11 @@ content into your application. Rather, pick only the properties that you need. server.undertow.accesslog.prefix=access_log. # Log file name prefix. server.undertow.accesslog.rotate=true # Whether to enable access log rotation. server.undertow.accesslog.suffix=log # Log file name suffix. - server.undertow.buffer-size=0 # Size of each buffer, in bytes. + server.undertow.buffer-size= # Size of each buffer. server.undertow.direct-buffers= # Allocate buffers outside the Java heap. The default is derived from the maximum amount of memory that is available to the JVM. server.undertow.eager-filter-init=true # Whether servlet filters should be initialized on startup. server.undertow.io-threads= # Number of I/O threads to create for the worker. The default is derived from the number of available processors. - server.undertow.max-http-post-size=-1 # Maximum size in bytes of the HTTP post content. When the value is -1, the default, the size is unlimited. + server.undertow.max-http-post-size=-1B # Maximum size of the HTTP post content. When the value is -1, the default, the size is unlimited. server.undertow.worker-threads= # Number of worker threads. The default is 8 times the number of I/O threads. # FREEMARKER ({sc-spring-boot-autoconfigure}/freemarker/FreeMarkerProperties.{sc-ext}[FreeMarkerProperties]) @@ -501,7 +501,7 @@ content into your application. Rather, pick only the properties that you need. spring.thymeleaf.prefix=classpath:/templates/ # Prefix that gets prepended to view names when building a URL. spring.thymeleaf.reactive.chunked-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be the only ones executed in CHUNKED mode when a max chunk size is set. spring.thymeleaf.reactive.full-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be executed in FULL mode even if a max chunk size is set. - spring.thymeleaf.reactive.max-chunk-size=0 # Maximum size of data buffers used for writing to the response, in bytes. + spring.thymeleaf.reactive.max-chunk-size=0B # Maximum size of data buffers used for writing to the response. spring.thymeleaf.reactive.media-types= # Media types supported by the view technology. spring.thymeleaf.servlet.content-type=text/html # Content-Type value written to HTTP responses. spring.thymeleaf.suffix=.html # Suffix that gets appended to view names when building a URL. @@ -920,7 +920,7 @@ content into your application. Rather, pick only the properties that you need. # EMBEDDED MONGODB ({sc-spring-boot-autoconfigure}/mongo/embedded/EmbeddedMongoProperties.{sc-ext}[EmbeddedMongoProperties]) spring.mongodb.embedded.features=sync_delay # Comma-separated list of features to enable. spring.mongodb.embedded.storage.database-dir= # Directory used for data storage. - spring.mongodb.embedded.storage.oplog-size= # Maximum size of the oplog, in megabytes. + spring.mongodb.embedded.storage.oplog-size= # Maximum size of the oplog. spring.mongodb.embedded.storage.repl-set-name= # Name of the replica set. spring.mongodb.embedded.version=3.2.2 # Version of Mongo to use. @@ -1046,8 +1046,8 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.consumer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connections to the Kafka cluster. Overrides the global property, for consumers. spring.kafka.consumer.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.consumer.enable-auto-commit= # Whether the consumer's offset is periodically committed in the background. - spring.kafka.consumer.fetch-max-wait= # Maximum amount of time the server blocks before answering the fetch request if there isn't sufficient data to immediately satisfy the requirement given by "fetch.min.bytes". - spring.kafka.consumer.fetch-min-size= # Minimum amount of data, in bytes, the server should return for a fetch request. + spring.kafka.consumer.fetch-max-wait= # Maximum amount of time the server blocks before answering the fetch request if there isn't sufficient data to immediately satisfy the requirement given by "fetch-min-size". + spring.kafka.consumer.fetch-min-size= # Minimum amount of data the server should return for a fetch request. spring.kafka.consumer.group-id= # Unique string that identifies the consumer group to which this consumer belongs. spring.kafka.consumer.heartbeat-interval= # Expected time between heartbeats to the consumer coordinator. spring.kafka.consumer.key-deserializer= # Deserializer class for keys. @@ -1078,9 +1078,9 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.listener.poll-timeout= # Timeout to use when polling the consumer. spring.kafka.listener.type=single # Listener type. spring.kafka.producer.acks= # Number of acknowledgments the producer requires the leader to have received before considering a request complete. - spring.kafka.producer.batch-size= # Default batch size in bytes. + spring.kafka.producer.batch-size= # Default batch size. spring.kafka.producer.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connections to the Kafka cluster. Overrides the global property, for producers. - spring.kafka.producer.buffer-memory= # Total bytes of memory the producer can use to buffer records waiting to be sent to the server. + spring.kafka.producer.buffer-memory= # Total memory size the producer can use to buffer records waiting to be sent to the server. spring.kafka.producer.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.producer.compression-type= # Compression type for all data generated by the producer. spring.kafka.producer.key-serializer= # Serializer class for keys. @@ -1108,7 +1108,7 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.streams.application-id= # Kafka streams application.id property; default spring.application.name. spring.kafka.streams.auto-startup=true # Whether or not to auto-start the streams factory bean. spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connections to the Kafka cluster. Overrides the global property, for streams. - spring.kafka.streams.cache-max-bytes-buffering= # Maximum number of memory bytes to be used for buffering across all threads. + spring.kafka.streams.cache-max-size-buffering= # Maximum number of memory size to be used for buffering across all threads. spring.kafka.streams.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.streams.properties.*= # Additional Kafka properties used to configure the streams. spring.kafka.streams.replication-factor= # The replication factor for change log topics and repartition topics created by the stream processing application. @@ -1347,7 +1347,7 @@ content into your application. Rather, pick only the properties that you need. management.health.defaults.enabled=true # Whether to enable default health indicators. management.health.diskspace.enabled=true # Whether to enable disk space health check. management.health.diskspace.path= # Path used to compute the available disk space. - management.health.diskspace.threshold=0 # Minimum disk space, in bytes, that should be available. + management.health.diskspace.threshold=10MB # Minimum disk space that should be available. management.health.elasticsearch.enabled=true # Whether to enable Elasticsearch health check. management.health.elasticsearch.indices= # Comma-separated index names. management.health.elasticsearch.response-timeout=100ms # Time to wait for a response from the cluster. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyHandlerWrappers.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyHandlerWrappers.java index d0cab9866f81..30253bd8fa57 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyHandlerWrappers.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyHandlerWrappers.java @@ -41,7 +41,7 @@ private JettyHandlerWrappers() { static HandlerWrapper createGzipHandlerWrapper(Compression compression) { GzipHandler handler = new GzipHandler(); - handler.setMinGzipSize(compression.getMinResponseSize()); + handler.setMinGzipSize((int) compression.getMinResponseSize().toBytes()); handler.setIncludedMimeTypes(compression.getMimeTypes()); for (HttpMethod httpMethod : HttpMethod.values()) { handler.addIncludedMethods(httpMethod.name()); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java index 396120a499d1..30a759c7e41a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java @@ -51,8 +51,9 @@ final class CompressionCustomizer implements NettyServerCustomizer { @Override public HttpServer apply(HttpServer server) { - if (this.compression.getMinResponseSize() >= 0) { - server = server.compress(this.compression.getMinResponseSize()); + if (!this.compression.getMinResponseSize().isNegative()) { + server = server + .compress((int) this.compression.getMinResponseSize().toBytes()); } CompressionPredicate mimeTypes = getMimeTypesPredicate( this.compression.getMimeTypes()); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/CompressionConnectorCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/CompressionConnectorCustomizer.java index e9d1d64d74bb..61feb7aa5eb5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/CompressionConnectorCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/CompressionConnectorCustomizer.java @@ -50,7 +50,7 @@ public void customize(Connector connector) { private void customize(AbstractHttp11Protocol protocol) { Compression compression = this.compression; protocol.setCompression("on"); - protocol.setCompressionMinSize(compression.getMinResponseSize()); + protocol.setCompressionMinSize((int) compression.getMinResponseSize().toBytes()); protocol.setCompressibleMimeType( StringUtils.arrayToCommaDelimitedString(compression.getMimeTypes())); if (this.compression.getExcludedUserAgents() != null) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowCompressionConfigurer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowCompressionConfigurer.java index 682d95a013dc..51be7d91934b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowCompressionConfigurer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowCompressionConfigurer.java @@ -65,7 +65,8 @@ public static HttpHandler configureCompression(Compression compression, private static Predicate[] getCompressionPredicates(Compression compression) { List predicates = new ArrayList<>(); - predicates.add(new MaxSizePredicate(compression.getMinResponseSize())); + predicates.add( + new MaxSizePredicate((int) compression.getMinResponseSize().toBytes())); predicates.add(new CompressibleMimeTypePredicate(compression.getMimeTypes())); if (compression.getExcludedUserAgents() != null) { for (String agent : compression.getExcludedUserAgents()) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/Compression.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/Compression.java index 36d48d1f75bb..e41432aa8956 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/Compression.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/Compression.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.server; +import org.springframework.util.unit.DataSize; + /** * Simple server-independent abstraction for compression configuration. * @@ -45,7 +47,7 @@ public class Compression { /** * Minimum "Content-Length" value that is required for compression to be performed. */ - private int minResponseSize = 2048; + private DataSize minResponseSize = DataSize.ofKilobytes(2); public boolean getEnabled() { return this.enabled; @@ -63,11 +65,11 @@ public void setMimeTypes(String[] mimeTypes) { this.mimeTypes = mimeTypes; } - public int getMinResponseSize() { + public DataSize getMinResponseSize() { return this.minResponseSize; } - public void setMinResponseSize(int minSize) { + public void setMinResponseSize(DataSize minSize) { this.minResponseSize = minSize; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index bc1d9ca24548..fbce32c475a6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -58,6 +58,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.SocketUtils; +import org.springframework.util.unit.DataSize; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.client.WebClient; @@ -265,7 +266,7 @@ public void compressionOfResponseToPostRequest() { public void noCompressionForSmallResponse() { Compression compression = new Compression(); compression.setEnabled(true); - compression.setMinResponseSize(3001); + compression.setMinResponseSize(DataSize.ofBytes(3001)); WebClient client = prepareCompressionTest(compression); ResponseEntity response = client.get().exchange() .flatMap((res) -> res.toEntity(Void.class)).block(); From ade79f7ded965d469f9ec2241917876467b00a92 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 16:07:06 +0100 Subject: [PATCH 667/701] Fix duplicate section ID in the docs --- .../main/asciidoc/spring-boot-features.adoc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 1c02abc2c526..f94a7a6480f6 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4296,19 +4296,19 @@ You can take full control over the session creation by adding a ==== Using the Embedded Mode If you add `org.neo4j:neo4j-ogm-embedded-driver` to the dependencies of your application, Spring Boot automatically configures an in-process embedded instance of Neo4j that does -not persist any data when your application shuts down. +not persist any data when your application shuts down. [NOTE] ==== -As the embedded Neo4j OGM driver does not provide the Neo4j kernel itself, you have -to declare `org.neo4j:neo4j` as dependency yourself. Refer to +As the embedded Neo4j OGM driver does not provide the Neo4j kernel itself, you have +to declare `org.neo4j:neo4j` as dependency yourself. Refer to https://neo4j.com/docs/ogm-manual/current/reference/#reference:getting-started[the Neo4j OGM documentation] for a list of compatible versions. ==== The embedded driver takes precedence over the other drivers when there are multiple -drivers on the classpath. You can explicitly disable the embedded mode by setting -`spring.data.neo4j.embedded.enabled=false`. +drivers on the classpath. You can explicitly disable the embedded mode by setting +`spring.data.neo4j.embedded.enabled=false`. <> automatically make use of an embedded Neo4j instance if the embedded driver and Neo4j @@ -4316,7 +4316,7 @@ kernel are on the classpath as described above. [NOTE] ==== -You can enable persistence for the embedded mode by providing a path to a database file +You can enable persistence for the embedded mode by providing a path to a database file in your configuration, e.g. `spring.data.neo4j.uri=file://var/tmp/graph.db`. ==== @@ -4360,9 +4360,9 @@ abstraction works in the same way, as shown in the following example: } ---- -The `spring-boot-starter-data-neo4j` "`Starter`" enables the repository support as well +The `spring-boot-starter-data-neo4j` "`Starter`" enables the repository support as well as transaction management. You can customize the locations to look for repositories and -entities by using `@EnableNeo4jRepositories` and `@EntityScan` respectively on a +entities by using `@EnableNeo4jRepositories` and `@EntityScan` respectively on a `@Configuration`-bean. TIP: For complete details of Spring Data Neo4j, including its object mapping @@ -7159,7 +7159,7 @@ If you prefer your test to run against a real database, you can use the -[[boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test]] +[[boot-features-testing-spring-boot-applications-testing-autoconfigured-data-jdbc-test]] ==== Auto-configured Data JDBC Tests `@DataJdbcTest` is similar to `@JdbcTest` but is for tests that use Spring Data JDBC repositories. By default, it configures an in-memory embedded database, a `JdbcTemplate`, From cce693f708a58358485f2432c17fab9a81a15cef Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 16:40:29 +0100 Subject: [PATCH 668/701] Upgrade to Spring Security 5.1.0.RELEASE Closes gh-14571 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 62192dd57746..29dc3d35a3d4 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -170,7 +170,7 @@ 1.2.0.RELEASE 2.0.2.RELEASE 1.2.2.RELEASE - 5.1.0.RC2 + 5.1.0.RELEASE Bean-M3 3.0.4.RELEASE 3.23.1 From ce75a585b1941ded6c303dd20d9077b8ce8c3603 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 19:14:22 +0100 Subject: [PATCH 669/701] Make spring-data-jdbc available to javadoc generation See gh-14489 --- spring-boot-project/spring-boot-docs/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 30775bf71593..9fc2a7e41ced 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -787,6 +787,11 @@ spring-data-elasticsearch true + + org.springframework.data + spring-data-jdbc + true + org.springframework.data spring-data-jpa From 5d0a1ee0da24aa8dbc0c614384006b94bdc22f27 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 19:16:08 +0100 Subject: [PATCH 670/701] Upgrade to Spring AMQP 2.1.0.RC1 Closes gh-14574 --- .../amqp/AbstractRabbitListenerContainerFactoryConfigurer.java | 2 +- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java index d271bc0fea4f..2a092caf2752 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java @@ -119,7 +119,7 @@ protected void configure(T factory, ConnectionFactory connectionFactory, factory.setMissingQueuesFatal(configuration.isMissingQueuesFatal()); ListenerRetry retryConfig = configuration.getRetry(); if (retryConfig.isEnabled()) { - RetryInterceptorBuilder builder = (retryConfig.isStateless()) + RetryInterceptorBuilder builder = (retryConfig.isStateless()) ? RetryInterceptorBuilder.stateless() : RetryInterceptorBuilder.stateful(); RetryTemplate retryTemplate = new RetryTemplateFactory( diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 29dc3d35a3d4..3a51c3411e41 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -158,7 +158,7 @@ 7.4.0 5.1.0.RELEASE - 2.1.0.M3 + 2.1.0.RC1 4.1.0.M3 2.0.3.RELEASE Lovelace-RELEASE From 06d05684e575dbc54292430496e8e190b71ee5de Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 19:16:58 +0100 Subject: [PATCH 671/701] Upgrade to Spring Kafka 2.2.0.RC1 Closes gh-14491 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 3a51c3411e41..e636422bddc4 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -165,7 +165,7 @@ ${spring.version} 0.25.0.RELEASE 5.1.0.M2 - 2.2.0.BUILD-SNAPSHOT + 2.2.0.RC1 2.3.2.RELEASE 1.2.0.RELEASE 2.0.2.RELEASE From 5196e138fa6641fc5828f5ec5a2a5968e5ab109e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 19:17:28 +0100 Subject: [PATCH 672/701] Upgrade to Spring Integration 5.1.0.RC1 Closes gh-14572 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index e636422bddc4..19436d0f564b 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -164,7 +164,7 @@ Lovelace-RELEASE ${spring.version} 0.25.0.RELEASE - 5.1.0.M2 + 5.1.0.RC1 2.2.0.RC1 2.3.2.RELEASE 1.2.0.RELEASE From 977f8b447924ddfcd937cb7a35dcb384f25ed3ba Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Sep 2018 19:55:10 +0100 Subject: [PATCH 673/701] Auto-configure Micrometer's Kafka consumer metrics Closes gh-14525 --- .../pom.xml | 5 ++ .../KafkaMetricsAutoConfiguration.java | 54 +++++++++++++ .../main/resources/META-INF/spring.factories | 1 + .../KafkaMetricsAutoConfigurationTests.java | 76 +++++++++++++++++++ .../asciidoc/production-ready-features.adoc | 1 + 5 files changed, 137 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index b54069cad654..f5ffd7cb56d6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -198,6 +198,11 @@ commons-dbcp2 true + + org.apache.kafka + kafka-clients + true + org.apache.logging.log4j log4j-core diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfiguration.java new file mode 100644 index 000000000000..0478021dbf5d --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfiguration.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import java.util.Collections; + +import javax.management.MBeanServer; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.kafka.KafkaConsumerMetrics; +import org.apache.kafka.clients.consumer.KafkaConsumer; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +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.jmx.JmxAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Auto-configuration for Kafka metrics. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Configuration +@AutoConfigureAfter({ MetricsAutoConfiguration.class, JmxAutoConfiguration.class }) +@ConditionalOnClass({ KafkaConsumerMetrics.class, KafkaConsumer.class }) +@ConditionalOnBean(MeterRegistry.class) +public class KafkaMetricsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean(MBeanServer.class) + public KafkaConsumerMetrics kafkaConsumerMetrics(MBeanServer mbeanServer) { + return new KafkaConsumerMetrics(mbeanServer, Collections.emptyList()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 0ab29f380037..594ce0c289ac 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -35,6 +35,7 @@ org.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAut org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.JvmMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.KafkaMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.Log4J2MetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.LogbackMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfigurationTests.java new file mode 100644 index 000000000000..227eb3cb1aa9 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/KafkaMetricsAutoConfigurationTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.kafka.KafkaConsumerMetrics; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link KafkaMetricsAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class KafkaMetricsAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()).withConfiguration( + AutoConfigurations.of(KafkaMetricsAutoConfiguration.class)); + + @Test + public void whenThereIsNoMBeanServerAutoConfigurationBacksOff() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(KafkaConsumerMetrics.class)); + } + + @Test + public void whenThereIsAnMBeanServerKafkaConsumerMetricsIsConfigured() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class)) + .run((context) -> assertThat(context) + .hasSingleBean(KafkaConsumerMetrics.class)); + } + + @Test + public void allowsCustomKafkaConsumerMetricsToBeUsed() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class)) + .withUserConfiguration(CustomKafkaConsumerMetricsConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(KafkaConsumerMetrics.class) + .hasBean("customKafkaConsumerMetrics")); + } + + @Configuration + static class CustomKafkaConsumerMetricsConfiguration { + + @Bean + public KafkaConsumerMetrics customKafkaConsumerMetrics() { + return new KafkaConsumerMetrics(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index bd62675ae44c..7ff09963df72 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1707,6 +1707,7 @@ Spring Boot registers the following core metrics when applicable: ** Number of classes loaded/unloaded * CPU metrics * File descriptor metrics +* Kafka consumer metrics * Log4j2 metrics: record the number of events logged to Log4j2 at each level * Logback metrics: record the number of events logged to Logback at each level * Uptime metrics: report a gauge for uptime and a fixed gauge representing the From d4942a11a80b0df913d3015b0ba0c7a1a0b0b856 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 22 Sep 2018 08:23:48 +0100 Subject: [PATCH 674/701] Upgrade to Spring Session Bean-RC1 Closes gh-14573 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 19436d0f564b..96b92c388214 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -171,7 +171,7 @@ 2.0.2.RELEASE 1.2.2.RELEASE 5.1.0.RELEASE - Bean-M3 + Bean-RC1 3.0.4.RELEASE 3.23.1 3.1.0 From 86c2b4a335ffa1f4fe1e31e484b23d00e8f8c429 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 22 Sep 2018 08:24:17 +0100 Subject: [PATCH 675/701] Upgrade to Spring Batch 4.1.0.RC1 Closes gh-14577 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 96b92c388214..f66e448f99e3 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -159,7 +159,7 @@ 5.1.0.RELEASE 2.1.0.RC1 - 4.1.0.M3 + 4.1.0.RC1 2.0.3.RELEASE Lovelace-RELEASE ${spring.version} From 8e9a93e5f3ed9cc3f8bc533b8b2055232bd9682e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 22 Sep 2018 14:57:43 +0100 Subject: [PATCH 676/701] Align SessionAutoConfigurationRedisTests with changes in Bean-RC1 See gh-14573 --- .../session/SessionAutoConfigurationRedisTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java index 1c98d1a7baa5..42257667f0fb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java @@ -57,7 +57,7 @@ public void defaultConfig() { .withPropertyValues("spring.session.store-type=redis", "spring.redis.port=" + redis.getMappedPort()) .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) - .run(validateSpringSessionUsesRedis("spring:session:event:created:", + .run(validateSpringSessionUsesRedis("spring:session:event:0:created:", RedisFlushMode.ON_SAVE, "0 * * * * *")); } @@ -69,7 +69,7 @@ public void defaultConfigWithUniqueStoreImplementation() { MongoOperationsSessionRepository.class)) .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)) .withPropertyValues("spring.redis.port=" + redis.getMappedPort()) - .run(validateSpringSessionUsesRedis("spring:session:event:created:", + .run(validateSpringSessionUsesRedis("spring:session:event:0:created:", RedisFlushMode.ON_SAVE, "0 * * * * *")); } @@ -82,7 +82,7 @@ public void redisSessionStoreWithCustomizations() { "spring.session.redis.flush-mode=immediate", "spring.session.redis.cleanup-cron=0 0 12 * * *", "spring.redis.port=" + redis.getMappedPort()) - .run(validateSpringSessionUsesRedis("foo:event:created:", + .run(validateSpringSessionUsesRedis("foo:event:0:created:", RedisFlushMode.IMMEDIATE, "0 0 12 * * *")); } From f1552029ea5adaeffc14972daeb0c90fbacdf813 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sat, 22 Sep 2018 23:25:29 +0900 Subject: [PATCH 677/701] Add @since in ApplicationContextInitializedEvent Closes gh-14579 --- .../boot/context/event/ApplicationContextInitializedEvent.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java index dd88bbfb055e..d44a8c3673fb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java @@ -26,6 +26,7 @@ * called but before any bean definitions are loaded. * * @author Artsiom Yudovin + * @since 2.1.0 */ @SuppressWarnings("serial") public class ApplicationContextInitializedEvent extends SpringApplicationEvent { From 3dc78d19bfc2b46dc995907ef3a1db389f5b1604 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 21 Sep 2018 17:14:48 +0900 Subject: [PATCH 678/701] Add log messages to lines only when the destination isn't set Closes gh-14565 --- .../boot/logging/DeferredLog.java | 4 +++- .../boot/logging/DeferredLogTests.java | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java index 2d86075b7128..5ac65e0f1daf 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java @@ -142,7 +142,9 @@ private void log(LogLevel level, Object message, Throwable t) { if (this.destination != null) { logTo(this.destination, level, message, t); } - this.lines.add(new Line(level, message, t)); + else { + this.lines.add(new Line(level, message, t)); + } } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java index 9b5adfbef444..c807c3ba7248 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java @@ -16,9 +16,13 @@ package org.springframework.boot.logging; +import java.util.List; + import org.apache.commons.logging.Log; import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -169,9 +173,21 @@ public void clearsOnReplayTo() { @Test public void switchTo() { + DirectFieldAccessor deferredLogFieldAccessor = new DirectFieldAccessor( + this.deferredLog); + List lines = (List) deferredLogFieldAccessor + .getPropertyValue("lines"); + assertThat(lines).isEmpty(); + this.deferredLog.error(this.message, this.throwable); + assertThat(lines).hasSize(1); + this.deferredLog.switchTo(this.log); + assertThat(lines).isEmpty(); + this.deferredLog.info("Message2"); + assertThat(lines).isEmpty(); + verify(this.log).error(this.message, this.throwable); verify(this.log).info("Message2", null); } From 47f937930560e77ff570c547e0db62576e385b2d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sat, 22 Sep 2018 20:02:28 +0200 Subject: [PATCH 679/701] Adapt to changes in latest Micrometer snapshot See gh-14522 --- .../export/dynatrace/DynatraceProperties.java | 4 +- ...ceMetricsExportAutoConfigurationTests.java | 39 +++++++++++-------- .../appendix-application-properties.adoc | 2 +- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java index 2be57720f005..9df349db1007 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceProperties.java @@ -45,8 +45,8 @@ public class DynatraceProperties extends StepRegistryProperties { private String technologyType = "java"; /** - * URI to ship metrics to. If you need to publish metrics to an internal proxy - * en-route to Dynatrace, you can define the location of the proxy with this. + * URI to ship metrics to. Should be used for SaaS, self managed instances or to + * en-route through an internal proxy. */ private String uri; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java index 7d307594bec5..6f9a31a45ada 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; import java.util.Map; +import java.util.function.Function; import io.micrometer.core.instrument.Clock; import io.micrometer.dynatrace.DynatraceConfig; @@ -39,6 +40,7 @@ * Tests for {@link DynatraceMetricsExportAutoConfiguration}. * * @author Andy Wilkinson + * @author Stephane Nicoll */ public class DynatraceMetricsExportAutoConfigurationTests { @@ -61,8 +63,7 @@ public void failsWithoutAUri() { @Test public void autoConfiguresConfigAndMeterRegistry() { this.contextRunner.withUserConfiguration(BaseConfiguration.class) - .withPropertyValues( - "management.metrics.export.dynatrace.uri=https://dynatrace.example.com") + .with(mandatoryProperties()) .run((context) -> assertThat(context) .hasSingleBean(DynatraceMeterRegistry.class) .hasSingleBean(DynatraceConfig.class)); @@ -88,8 +89,7 @@ public void allowsCustomConfigToBeUsed() { @Test public void allowsCustomRegistryToBeUsed() { this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class) - .withPropertyValues( - "management.metrics.export.dynatrace.uri=https://dynatrace.example.com") + .with(mandatoryProperties()) .run((context) -> assertThat(context) .hasSingleBean(DynatraceMeterRegistry.class) .hasBean("customRegistry").hasSingleBean(DynatraceConfig.class)); @@ -98,10 +98,7 @@ public void allowsCustomRegistryToBeUsed() { @Test public void stopsMeterRegistryWhenContextIsClosed() { this.contextRunner.withUserConfiguration(BaseConfiguration.class) - .withPropertyValues("management.metrics.export.dynatrace.api-token=abcde", - "management.metrics.export.dynatrace.uri=https://dynatrace.example.com", - "management.metrics.export.dynatrace.deviceId=test") - .run((context) -> { + .with(mandatoryProperties()).run((context) -> { DynatraceMeterRegistry registry = spyOnDisposableBean( DynatraceMeterRegistry.class, context); context.close(); @@ -109,6 +106,13 @@ public void stopsMeterRegistryWhenContextIsClosed() { }); } + private Function mandatoryProperties() { + return (runner) -> runner.withPropertyValues( + "management.metrics.export.dynatrace.uri=https://dynatrace.example.com", + "management.metrics.export.dynatrace.api-token=abcde", + "management.metrics.export.dynatrace.device-id=test"); + } + @SuppressWarnings("unchecked") private T spyOnDisposableBean(Class type, AssertableApplicationContext context) { @@ -139,16 +143,17 @@ static class CustomConfigConfiguration { @Bean public DynatraceConfig customConfig() { - return new DynatraceConfig() { - - @Override - public String get(String k) { - if ("dynatrace.uri".equals(k)) { - return "https://dynatrace.example.com"; - } - return null; + return (k) -> { + if ("dynatrace.uri".equals(k)) { + return "https://dynatrace.example.com"; } - + if ("dynatrace.apiToken".equals(k)) { + return "abcde"; + } + if ("dynatrace.deviceId".equals(k)) { + return "test"; + } + return null; }; } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index ccea76ed24a4..5c5790cd4fb0 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1412,7 +1412,7 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.dynatrace.read-timeout=10s # Read timeout for requests to this backend. management.metrics.export.dynatrace.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.dynatrace.technology-type=java # Technology type for exported metrics. Used to group metrics under a logical technology name in the Dynatrace UI. - management.metrics.export.dynatrace.uri= # URI to ship metrics to. If you need to publish metrics to an internal proxy en-route to Dynatrace, you can define the location of the proxy with this. + management.metrics.export.dynatrace.uri= # URI to ship metrics to. Should be used for SaaS, self managed instances or to en-route through an internal proxy. management.metrics.export.ganglia.addressing-mode=multicast # UDP addressing mode, either unicast or multicast. management.metrics.export.ganglia.duration-units=milliseconds # Base time unit used to report durations. management.metrics.export.ganglia.enabled=true # Whether exporting of metrics to Ganglia is enabled. From da59d5c6d9631f0ed2559a7f72cbbcc72fddbbe9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 23 Sep 2018 10:11:19 +0200 Subject: [PATCH 680/701] Polish --- .../main/asciidoc/appendix-application-properties.adoc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 5c5790cd4fb0..fb3e9221ed27 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -531,11 +531,12 @@ content into your application. Rather, pick only the properties that you need. # SECURITY OAUTH2 CLIENT ({sc-spring-boot-autoconfigure}/security/oauth2/client/OAuth2ClientProperties.{sc-ext}[OAuth2ClientProperties]) spring.security.oauth2.client.provider.*= # OAuth provider details. - spring.security.oauth2.client.registration.*= # OAuth client registrations. + spring.security.oauth2.client.registration.authorization-code.*= # OAuth2 authorization_code client registrations. + spring.security.oauth2.client.registration.login.*= # OpenID Connect client registrations. # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties]) spring.security.oauth2.resourceserver.jwt.jwk-set-uri= # JSON Web Key URI to use to verify the JWT token. - spring.security.oauth2.resource.jwt.issuer-uri= # URI that an OpenID Connect Provider asserts as its Issuer Identifier. + spring.security.oauth2.resourceserver.jwt.issuer-uri= # URI that an OpenID Connect Provider asserts as its Issuer Identifier. # ---------------------------------------- # DATA PROPERTIES @@ -1403,10 +1404,10 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.datadog.read-timeout=10s # Read timeout for requests to this backend. management.metrics.export.datadog.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.datadog.uri=https://app.datadoghq.com # URI to ship metrics to. If you need to publish metrics to an internal proxy en-route to Datadog, you can define the location of the proxy with this. - management.metrics.export.dynatrace.api-token= # Dynatrace API token. + management.metrics.export.dynatrace.api-token= # Dynatrace authentication token. management.metrics.export.dynatrace.batch-size=10000 # Number of measurements per request to use for this backend. If more measurements are found, then multiple requests will be made. management.metrics.export.dynatrace.connect-timeout=1s # Connection timeout for requests to this backend. - management.metrics.export.dynatrace.deviceId= # ID of the custom device that is exporting metrics to Dynatrace. + management.metrics.export.dynatrace.device-id= # ID of the custom device that is exporting metrics to Dynatrace. management.metrics.export.dynatrace.enabled=true # Whether exporting of metrics to this backend is enabled. management.metrics.export.dynatrace.num-threads=2 # Number of threads to use with the metrics publishing scheduler. management.metrics.export.dynatrace.read-timeout=10s # Read timeout for requests to this backend. From 6145b3d2789bd1cadef5ef19cd331b896cedfc2d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 23 Sep 2018 10:56:40 +0200 Subject: [PATCH 681/701] Polish --- .../main/asciidoc/appendix-application-properties.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index eb35f3ea317d..539528dd94de 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -264,7 +264,7 @@ content into your application. Rather, pick only the properties that you need. 172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}\\ 0:0:0:0:0:0:0:1\\ ::1 # Regular expression that matches proxies that are to be trusted. - server.tomcat.max-connections=10000 # Maximum number of connections that the server accepts and processes at any given time + server.tomcat.max-connections=10000 # Maximum number of connections that the server accepts and processes at any given time. server.tomcat.max-http-post-size=2MB # Maximum size of the HTTP post content. server.tomcat.max-swallow-size=2MB # Maximum amount of request body to swallow. server.tomcat.max-threads=200 # Maximum amount of worker threads. @@ -343,7 +343,7 @@ content into your application. Rather, pick only the properties that you need. # MULTIPART ({sc-spring-boot-autoconfigure}/web/servlet/MultipartProperties.{sc-ext}[MultipartProperties]) spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads. - spring.servlet.multipart.file-size-threshold=0 # Threshold after which files are written to disk. + spring.servlet.multipart.file-size-threshold=0B # Threshold after which files are written to disk. spring.servlet.multipart.location= # Intermediate location of uploaded files. spring.servlet.multipart.max-file-size=1MB # Max file size. spring.servlet.multipart.max-request-size=10MB # Max request size. @@ -1111,7 +1111,7 @@ content into your application. Rather, pick only the properties that you need. spring.kafka.streams.application-id= # Kafka streams application.id property; default spring.application.name. spring.kafka.streams.auto-startup=true # Whether or not to auto-start the streams factory bean. spring.kafka.streams.bootstrap-servers= # Comma-delimited list of host:port pairs to use for establishing the initial connections to the Kafka cluster. Overrides the global property, for streams. - spring.kafka.streams.cache-max-size-buffering= # Maximum number of memory size to be used for buffering across all threads. + spring.kafka.streams.cache-max-size-buffering= # Maximum memory size to be used for buffering across all threads. spring.kafka.streams.client-id= # ID to pass to the server when making requests. Used for server-side logging. spring.kafka.streams.properties.*= # Additional Kafka properties used to configure the streams. spring.kafka.streams.replication-factor= # The replication factor for change log topics and repartition topics created by the stream processing application. @@ -1155,7 +1155,7 @@ content into your application. Rather, pick only the properties that you need. spring.rabbitmq.listener.simple.idle-event-interval= # How often idle container events should be published. spring.rabbitmq.listener.simple.max-concurrency= # Maximum number of listener invoker threads. spring.rabbitmq.listener.simple.missing-queues-fatal=true # Whether to fail if the queues declared by the container are not available on the broker and/or whether to stop the container if one or more queues are deleted at runtime. - spring.rabbitmq.listener.simple.prefetch= # Number of messages to be handled in a single request. It should be greater than or equal to the transaction size (if used). + spring.rabbitmq.listener.simple.prefetch= # Maximum number of unacknowledged messages that can be outstanding at each consumer. spring.rabbitmq.listener.simple.retry.enabled=false # Whether publishing retries are enabled. spring.rabbitmq.listener.simple.retry.initial-interval=1000ms # Duration between the first and second attempt to deliver a message. spring.rabbitmq.listener.simple.retry.max-attempts=3 # Maximum number of attempts to deliver a message. From 95ecbc736b885fadf7987d1eead3e1e8fcf99570 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sun, 23 Sep 2018 12:05:37 +0100 Subject: [PATCH 682/701] Update example for disk space health indicator to use DataSize See gh-14549 --- .../web/documentation/HealthEndpointDocumentationTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index 2e9b8655e876..7f186bdc3dee 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -40,6 +40,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.util.unit.DataSize; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -105,7 +106,7 @@ public HealthEndpoint endpoint(Map healthIndicators) { @Bean public DiskSpaceHealthIndicator diskSpaceHealthIndicator() { - return new DiskSpaceHealthIndicator(new File("."), 1024 * 1024 * 10); + return new DiskSpaceHealthIndicator(new File("."), DataSize.ofMegabytes(10)); } @Bean From 4c3e2d10d185c285f6bf1233598ba5fd30d71ba4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sun, 23 Sep 2018 15:26:10 +0100 Subject: [PATCH 683/701] Auto-configure Micrometer's Elastic registry Closes gh-14523 --- .../pom.xml | 5 + ...ElasticMetricsExportAutoConfiguration.java | 66 ++++++++ .../export/elastic/ElasticProperties.java | 123 +++++++++++++++ .../ElasticPropertiesConfigAdapter.java | 73 +++++++++ .../metrics/export/elastic/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 1 + ...icMetricsExportAutoConfigurationTests.java | 146 ++++++++++++++++++ .../ElasticPropertiesConfigAdapterTests.java | 86 +++++++++++ .../elastic/ElasticPropertiesTests.java | 47 ++++++ .../spring-boot-dependencies/pom.xml | 5 + spring-boot-project/spring-boot-docs/pom.xml | 5 + .../appendix-application-properties.adoc | 13 ++ .../asciidoc/production-ready-features.adoc | 14 ++ 13 files changed, 604 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapter.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index f5ffd7cb56d6..a679534533ee 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -107,6 +107,11 @@ micrometer-registry-dynatrace true + + io.micrometer + micrometer-registry-elastic + true + io.micrometer micrometer-registry-ganglia diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfiguration.java new file mode 100644 index 000000000000..3d635a4643e9 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.elastic.ElasticConfig; +import io.micrometer.elastic.ElasticMeterRegistry; + +import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Elastic. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) +@AutoConfigureAfter(MetricsAutoConfiguration.class) +@ConditionalOnBean(Clock.class) +@ConditionalOnClass(ElasticMeterRegistry.class) +@ConditionalOnProperty(prefix = "management.metrics.export.elastic", name = "enabled", havingValue = "true", matchIfMissing = true) +@EnableConfigurationProperties(ElasticProperties.class) +public class ElasticMetricsExportAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public ElasticConfig elasticConfig(ElasticProperties elasticProperties) { + return new ElasticPropertiesConfigAdapter(elasticProperties); + } + + @Bean + @ConditionalOnMissingBean + public ElasticMeterRegistry elasticMeterRegistry(ElasticConfig elasticConfig, + Clock clock) { + return new ElasticMeterRegistry(elasticConfig, clock); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java new file mode 100644 index 000000000000..426405f06c97 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties} for configuring Elastic metrics export. + * + * @author Andy Wilkinson + * @since 2.1.0 + */ +@ConfigurationProperties(prefix = "management.metrics.export.elastic") +public class ElasticProperties extends StepRegistryProperties { + + /** + * Hosts to export metrics to. + */ + private String[] hosts = new String[] { "http://localhost:9200" }; + + /** + * Index to export metrics to. + */ + private String index = "metrics"; + + /** + * Index date format used for rolling indices. Appended to the index name, preceded by + * a '-'. + */ + private String indexDateFormat = "yyyy-MM"; + + /** + * Name of the timestamp field. + */ + private String timestampFieldName = "@timestamp"; + + /** + * Whether to create the index automatically if it does not exist. + */ + private boolean autoCreateIndex = true; + + /** + * Username for basic authentication. + */ + private String userName = ""; + + /** + * Password for basic authentication. + */ + private String password = ""; + + public String[] getHosts() { + return this.hosts; + } + + public void setHosts(String[] hosts) { + this.hosts = hosts; + } + + public String getIndex() { + return this.index; + } + + public void setIndex(String index) { + this.index = index; + } + + public String getIndexDateFormat() { + return this.indexDateFormat; + } + + public void setIndexDateFormat(String indexDateFormat) { + this.indexDateFormat = indexDateFormat; + } + + public String getTimestampFieldName() { + return this.timestampFieldName; + } + + public void setTimestampFieldName(String timestampFieldName) { + this.timestampFieldName = timestampFieldName; + } + + public boolean isAutoCreateIndex() { + return this.autoCreateIndex; + } + + public void setAutoCreateIndex(boolean autoCreateIndex) { + this.autoCreateIndex = autoCreateIndex; + } + + public String getUserName() { + return this.userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapter.java new file mode 100644 index 000000000000..fe6e7055a49b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import io.micrometer.elastic.ElasticConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; + +/** + * Adapter to convert {@link ElasticProperties} to an {@link ElasticConfig}. + * + * @author Andy Wilkinson + */ +class ElasticPropertiesConfigAdapter extends + StepRegistryPropertiesConfigAdapter implements ElasticConfig { + + ElasticPropertiesConfigAdapter(ElasticProperties properties) { + super(properties); + } + + @Override + public String[] hosts() { + return get(ElasticProperties::getHosts, ElasticConfig.super::hosts); + } + + @Override + public String index() { + return get(ElasticProperties::getIndex, ElasticConfig.super::index); + } + + @Override + public String indexDateFormat() { + return get(ElasticProperties::getIndexDateFormat, + ElasticConfig.super::indexDateFormat); + } + + @Override + public String timestampFieldName() { + return get(ElasticProperties::getTimestampFieldName, + ElasticConfig.super::timestampFieldName); + } + + @Override + public boolean autoCreateIndex() { + return get(ElasticProperties::isAutoCreateIndex, + ElasticConfig.super::autoCreateIndex); + } + + @Override + public String userName() { + return get(ElasticProperties::getUserName, ElasticConfig.super::userName); + } + + @Override + public String password() { + return get(ElasticProperties::getPassword, ElasticConfig.super::password); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/package-info.java new file mode 100644 index 000000000000..7ab568af0628 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + */ + +/** + * Support for exporting actuator metrics to Elastic. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.export.elastic; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 594ce0c289ac..f8a1b57b51ea 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -46,6 +46,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoCon org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace.DynatraceMetricsExportAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.export.elastic.ElasticMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetricsExportAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfigurationTests.java new file mode 100644 index 000000000000..38d5b23c534e --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticMetricsExportAutoConfigurationTests.java @@ -0,0 +1,146 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import java.util.Map; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.elastic.ElasticConfig; +import io.micrometer.elastic.ElasticMeterRegistry; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link ElasticMetricsExportAutoConfiguration}. + * + * @author Andy Wilkinson + */ +public class ElasticMetricsExportAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(ElasticMetricsExportAutoConfiguration.class)); + + @Test + public void backsOffWithoutAClock() { + this.contextRunner.run((context) -> assertThat(context) + .doesNotHaveBean(ElasticMeterRegistry.class)); + } + + @Test + public void autoConfiguresConfigAndMeterRegistry() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(ElasticMeterRegistry.class) + .hasSingleBean(ElasticConfig.class)); + } + + @Test + public void autoConfigurationCanBeDisabled() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.metrics.export.elastic.enabled=false") + .run((context) -> assertThat(context) + .doesNotHaveBean(ElasticMeterRegistry.class) + .doesNotHaveBean(ElasticConfig.class)); + } + + @Test + public void allowsCustomConfigToBeUsed() { + this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(ElasticMeterRegistry.class) + .hasSingleBean(ElasticConfig.class).hasBean("customConfig")); + } + + @Test + public void allowsCustomRegistryToBeUsed() { + this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class) + + .run((context) -> assertThat(context) + .hasSingleBean(ElasticMeterRegistry.class) + .hasBean("customRegistry").hasSingleBean(ElasticConfig.class)); + } + + @Test + public void stopsMeterRegistryWhenContextIsClosed() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .run((context) -> { + ElasticMeterRegistry registry = spyOnDisposableBean( + ElasticMeterRegistry.class, context); + context.close(); + verify(registry).stop(); + }); + } + + @SuppressWarnings("unchecked") + private T spyOnDisposableBean(Class type, + AssertableApplicationContext context) { + String[] names = context.getBeanNamesForType(type); + assertThat(names).hasSize(1); + String registryBeanName = names[0]; + Map disposableBeans = (Map) ReflectionTestUtils + .getField(context.getAutowireCapableBeanFactory(), "disposableBeans"); + Object registryAdapter = disposableBeans.get(registryBeanName); + T registry = (T) spy(ReflectionTestUtils.getField(registryAdapter, "bean")); + ReflectionTestUtils.setField(registryAdapter, "bean", registry); + return registry; + } + + @Configuration + static class BaseConfiguration { + + @Bean + public Clock clock() { + return Clock.SYSTEM; + } + + } + + @Configuration + @Import(BaseConfiguration.class) + static class CustomConfigConfiguration { + + @Bean + public ElasticConfig customConfig() { + return (k) -> null; + } + + } + + @Configuration + @Import(BaseConfiguration.class) + static class CustomRegistryConfiguration { + + @Bean + public ElasticMeterRegistry customRegistry(ElasticConfig config, Clock clock) { + return new ElasticMeterRegistry(config, clock); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java new file mode 100644 index 000000000000..427d63344e8f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ElasticPropertiesConfigAdapter}. + * + * @author Andy Wilkiknson + */ +public class ElasticPropertiesConfigAdapterTests { + + @Test + public void whenPropertiesHostsIsSetAdapterHostsReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setHosts(new String[] { "https://elastic.example.com" }); + assertThat(new ElasticPropertiesConfigAdapter(properties).hosts()) + .isEqualTo(new String[] { "https://elastic.example.com" }); + } + + @Test + public void whenPropertiesIndexIsSetAdapterIndexReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setIndex("test-metrics"); + assertThat(new ElasticPropertiesConfigAdapter(properties).index()) + .isEqualTo("test-metrics"); + } + + @Test + public void whenPropertiesIndexDateFormatIsSetAdapterIndexDateFormatReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setIndexDateFormat("yyyy"); + assertThat(new ElasticPropertiesConfigAdapter(properties).indexDateFormat()) + .isEqualTo("yyyy"); + } + + @Test + public void whenPropertiesTimestampFieldNameIsSetAdapterTimestampFieldNameReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setTimestampFieldName("@test"); + assertThat(new ElasticPropertiesConfigAdapter(properties).timestampFieldName()) + .isEqualTo("@test"); + } + + @Test + public void whenPropertiesAutoCreateIndexIsSetAdapterAutoCreateIndexReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setAutoCreateIndex(false); + assertThat(new ElasticPropertiesConfigAdapter(properties).autoCreateIndex()) + .isFalse(); + } + + @Test + public void whenPropertiesUserNameIsSetAdapterUserNameReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setUserName("alice"); + assertThat(new ElasticPropertiesConfigAdapter(properties).userName()) + .isEqualTo("alice"); + } + + @Test + public void whenPropertiesPasswordIsSetAdapterPasswordReturnsIt() { + ElasticProperties properties = new ElasticProperties(); + properties.setPassword("secret"); + assertThat(new ElasticPropertiesConfigAdapter(properties).password()) + .isEqualTo("secret"); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesTests.java new file mode 100644 index 000000000000..aaa2e874f1fc --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2018 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.autoconfigure.metrics.export.elastic; + +import io.micrometer.elastic.ElasticConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesTests; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ElasticProperties}. + * + * @author Andy Wilkinson + */ +public class ElasticPropertiesTests extends StepRegistryPropertiesTests { + + @Override + public void defaultValuesAreConsistent() { + ElasticProperties properties = new ElasticProperties(); + ElasticConfig config = ElasticConfig.DEFAULT; + assertStepRegistryDefaultValues(properties, config); + assertThat(properties.getHosts()).isEqualTo(config.hosts()); + assertThat(properties.getIndex()).isEqualTo(config.index()); + assertThat(properties.getIndexDateFormat()).isEqualTo(config.indexDateFormat()); + assertThat(properties.getPassword()).isEqualTo(config.password()); + assertThat(properties.getTimestampFieldName()) + .isEqualTo(config.timestampFieldName()); + assertThat(properties.getUserName()).isEqualTo(config.userName()); + assertThat(properties.isAutoCreateIndex()).isEqualTo(config.autoCreateIndex()); + } + +} diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index f66e448f99e3..bd395a3e785c 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -909,6 +909,11 @@ micrometer-registry-dynatrace ${micrometer.version} + + io.micrometer + micrometer-registry-elastic + ${micrometer.version} + io.micrometer micrometer-registry-influx diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml index 9fc2a7e41ced..cb605086ae5d 100644 --- a/spring-boot-project/spring-boot-docs/pom.xml +++ b/spring-boot-project/spring-boot-docs/pom.xml @@ -216,6 +216,11 @@ micrometer-registry-dynatrace true + + io.micrometer + micrometer-registry-elastic + true + io.micrometer micrometer-registry-ganglia diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 539528dd94de..abbc1d6b1f95 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1416,6 +1416,19 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.dynatrace.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.dynatrace.technology-type=java # Technology type for exported metrics. Used to group metrics under a logical technology name in the Dynatrace UI. management.metrics.export.dynatrace.uri= # URI to ship metrics to. Should be used for SaaS, self managed instances or to en-route through an internal proxy. + management.metrics.export.elastic.auto-create-index=true # Whether to create the index automatically if it does not exist. + management.metrics.export.elastic.batch-size=10000 # Number of measurements per request to use for this backend. If more measurements are found, then multiple requests will be made. + management.metrics.export.elastic.connect-timeout=1s # Connection timeout for requests to this backend. + management.metrics.export.elastic.enabled=true # Whether exporting of metrics to this backend is enabled. + management.metrics.export.elastic.hosts= # Hosts to export metrics to. + management.metrics.export.elastic.index= # Index to export metrics to. + management.metrics.export.elastic.index-date-format= # Index date format used for rolling indices. Appended to the index name, preceded by a '-'. + management.metrics.export.elastic.num-threads=2 # Number of threads to use with the metrics publishing scheduler. + management.metrics.export.elastic.password= # Password for basic authentication. + management.metrics.export.elastic.read-timeout=10s # Read timeout for requests to this backend. + management.metrics.export.elastic.step=1m # Step size (i.e. reporting frequency) to use. + management.metrics.export.elastic.timestamp-field-name=@timestamp # Name of the timestamp field. + management.metrics.export.elastic.user-name= # User name for basic authentication. management.metrics.export.ganglia.addressing-mode=multicast # UDP addressing mode, either unicast or multicast. management.metrics.export.ganglia.duration-units=milliseconds # Base time unit used to report durations. management.metrics.export.ganglia.enabled=true # Whether exporting of metrics to Ganglia is enabled. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 7ff09963df72..5d00e4b3e552 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1337,6 +1337,7 @@ monitoring systems, including: - <> - <> - <> +- <> - <> - <> - <> @@ -1475,6 +1476,19 @@ You can also change the interval at which metrics are sent to Dynatrace: +[[production-ready-metrics-export-elastic]] +==== Elastic +By default, metrics are exported to {micrometer-registry-documentation}/elastic[Elastic] +running on your local machine. The location of the Elastic server to use can be provided +using the following property: + +[source,properties,indent=0] +---- + management.metrics.export.elastic.hosts=http://elastic.example.com:8086 +---- + + + [[production-ready-metrics-export-ganglia]] ==== Ganglia By default, metrics are exported to {micrometer-registry-documentation}/ganglia[Ganglia] From 6e00d13d68e939dd5cb50ce9fc5153a7e2ce6958 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sun, 23 Sep 2018 15:44:26 +0100 Subject: [PATCH 684/701] Polish --- .../export/dynatrace/DynatracePropertiesConfigAdapter.java | 3 +-- .../src/main/resources/META-INF/spring.factories | 2 +- .../src/main/asciidoc/production-ready-features.adoc | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java index 099877457f00..11e1e8d4018e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapter.java @@ -16,13 +16,12 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.dynatrace; -import io.micrometer.datadog.DatadogConfig; import io.micrometer.dynatrace.DynatraceConfig; import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; /** - * Adapter to convert {@link DynatraceProperties} to a {@link DatadogConfig}. + * Adapter to convert {@link DynatraceProperties} to a {@link DynatraceConfig}. * * @author Andy Wilkinson * */ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index f8a1b57b51ea..7ce0481fac02 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -53,8 +53,8 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetri org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic.NewRelicMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration,\ -org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 5d00e4b3e552..32b02b62889a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1455,8 +1455,8 @@ You can also change the interval at which metrics are sent to Datadog: [[production-ready-metrics-export-dynatrace]] -==== Datadog -Dynatrace registry pushes metrics to the configured UIR periodically. To export metrics to +==== Dynatrace +Dynatrace registry pushes metrics to the configured URI periodically. To export metrics to {micrometer-registry-documentation}/dynatrace[Dynatrace], your API token, device ID, and URI must be provided: From 84e72193b3caa6ee95d03c08a8cb38da7c36bcd0 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sun, 23 Sep 2018 08:44:34 -0700 Subject: [PATCH 685/701] Remove automatic devtools web debug logging Rework `DevToolsPropertyDefaultsPostProcessor` so that web logging no longer defaults to `DEBUG`. The post processor now logs an info hint to suggest the user configure the logging themselves. Closes gh-14575 --- ...DevToolsPropertyDefaultsPostProcessor.java | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index df075273af29..3caad594814b 100755 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -31,6 +31,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; +import org.springframework.util.ClassUtils; /** * {@link EnvironmentPostProcessor} to add properties that make sense when working at @@ -49,6 +50,12 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro private static final String ENABLED = "spring.devtools.add-properties"; + private static final String WEB_LOGGING = "logging.level.web"; + + private static final String[] WEB_ENVIRONMENT_CLASSES = { + "org.springframework.web.context.ConfigurableWebEnvironment", + "org.springframework.boot.web.reactive.context.ConfigurableReactiveWebEnvironment" }; + private static final Map PROPERTIES; static { @@ -66,18 +73,24 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro properties.put("server.error.include-stacktrace", "ALWAYS"); properties.put("server.servlet.jsp.init-parameters.development", "true"); properties.put("spring.reactor.stacktrace-mode.enabled", "true"); - properties.put("logging.level.web", "debug"); PROPERTIES = Collections.unmodifiableMap(properties); } @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - if (isLocalApplication(environment) && canAddProperties(environment)) { - logger.info("Devtools property and logging defaults active! Set '" + ENABLED - + "' to 'false' to disable"); - environment.getPropertySources() - .addLast(new MapPropertySource("devtools", PROPERTIES)); + if (isLocalApplication(environment)) { + if (canAddProperties(environment)) { + logger.info("Devtools property defaults active! Set '" + ENABLED + + "' to 'false' to disable"); + environment.getPropertySources() + .addLast(new MapPropertySource("devtools", PROPERTIES)); + } + if (isWebApplication(environment) + && !environment.containsProperty(WEB_LOGGING)) { + logger.info("For additional web related logging consider " + + "setting the '" + WEB_LOGGING + "' property to 'DEBUG'"); + } } } @@ -106,4 +119,15 @@ private boolean isRemoteRestartEnabled(Environment environment) { return environment.containsProperty("spring.devtools.remote.secret"); } + private boolean isWebApplication(Environment environment) { + for (String candidate : WEB_ENVIRONMENT_CLASSES) { + Class environmentClass = ClassUtils.resolveClassName(candidate, + environment.getClass().getClassLoader()); + if (environmentClass != null && environmentClass.isInstance(environment)) { + return true; + } + } + return false; + } + } From 0f11e69ca3783ede08ec77fb795411b43292c6c7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 24 Sep 2018 07:02:10 +0200 Subject: [PATCH 686/701] Upgrade to Micrometer 1.1.0-m.1 Closes #14567 --- spring-boot-project/spring-boot-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index bd395a3e785c..15488a98a90a 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -127,7 +127,7 @@ 1.2.3 1.18.2 2.3.0 - 1.1.0-SNAPSHOT + 1.1.0-m.1 2.22.0 1.9.2 3.8.2 From 19779951a12b4a8f6139f3b3339ef8ea45a9af4c Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 24 Sep 2018 10:23:59 +0200 Subject: [PATCH 687/701] Handle class not found See gh-14575 --- .../env/DevToolsPropertyDefaultsPostProcessor.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index 3caad594814b..f7c346311075 100755 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -121,7 +121,7 @@ private boolean isRemoteRestartEnabled(Environment environment) { private boolean isWebApplication(Environment environment) { for (String candidate : WEB_ENVIRONMENT_CLASSES) { - Class environmentClass = ClassUtils.resolveClassName(candidate, + Class environmentClass = resolveClassName(candidate, environment.getClass().getClassLoader()); if (environmentClass != null && environmentClass.isInstance(environment)) { return true; @@ -130,4 +130,13 @@ private boolean isWebApplication(Environment environment) { return false; } + private Class resolveClassName(String candidate, ClassLoader classLoader) { + try { + return ClassUtils.resolveClassName(candidate, classLoader); + } + catch (IllegalArgumentException ex) { + return null; + } + } + } From 5765ed00e840324064c436f3fb0eeaac3d97c3cd Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 24 Sep 2018 10:53:22 +0200 Subject: [PATCH 688/701] Polish --- .../metrics/export/elastic/ElasticProperties.java | 4 ++-- .../main/asciidoc/appendix-application-properties.adoc | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java index 426405f06c97..7b45645056cd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticProperties.java @@ -55,12 +55,12 @@ public class ElasticProperties extends StepRegistryProperties { private boolean autoCreateIndex = true; /** - * Username for basic authentication. + * Login user of the Elastic server. */ private String userName = ""; /** - * Password for basic authentication. + * Login password of the Elastic server. */ private String password = ""; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index abbc1d6b1f95..2b1372195ee7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1420,15 +1420,15 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.elastic.batch-size=10000 # Number of measurements per request to use for this backend. If more measurements are found, then multiple requests will be made. management.metrics.export.elastic.connect-timeout=1s # Connection timeout for requests to this backend. management.metrics.export.elastic.enabled=true # Whether exporting of metrics to this backend is enabled. - management.metrics.export.elastic.hosts= # Hosts to export metrics to. - management.metrics.export.elastic.index= # Index to export metrics to. - management.metrics.export.elastic.index-date-format= # Index date format used for rolling indices. Appended to the index name, preceded by a '-'. + management.metrics.export.elastic.hosts=http://localhost:9200 # Hosts to export metrics to. + management.metrics.export.elastic.index=metrics # Index to export metrics to. + management.metrics.export.elastic.index-date-format=yyyy-MM # Index date format used for rolling indices. Appended to the index name, preceded by a '-'. management.metrics.export.elastic.num-threads=2 # Number of threads to use with the metrics publishing scheduler. - management.metrics.export.elastic.password= # Password for basic authentication. + management.metrics.export.elastic.password= # Login password of the Elastic server. management.metrics.export.elastic.read-timeout=10s # Read timeout for requests to this backend. management.metrics.export.elastic.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.elastic.timestamp-field-name=@timestamp # Name of the timestamp field. - management.metrics.export.elastic.user-name= # User name for basic authentication. + management.metrics.export.elastic.user-name= # Login user of the Elastic server. management.metrics.export.ganglia.addressing-mode=multicast # UDP addressing mode, either unicast or multicast. management.metrics.export.ganglia.duration-units=milliseconds # Base time unit used to report durations. management.metrics.export.ganglia.enabled=true # Whether exporting of metrics to Ganglia is enabled. From e4f54a45be1a1e571721d6db8fc92a05086c4768 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Sep 2018 09:27:59 -0400 Subject: [PATCH 689/701] Add AutoConfigurationImportFilter base classes Add `FilteringSpringBootCondition` base class and refactor the existing `OnClassCondition` to use it. Also update the `match` method so that the `autoConfigurationClasses` array may include `null` elements. See gh-13328 --- .../AutoConfigurationImportFilter.java | 5 +- .../AutoConfigurationImportSelector.java | 1 + .../condition/ConditionEvaluationReport.java | 15 ++ .../FilteringSpringBootCondition.java | 147 ++++++++++++++++++ .../condition/OnClassCondition.java | 139 +++-------------- 5 files changed, 184 insertions(+), 123 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java index ee83eadf4da2..0f6d8dc34038 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -45,7 +45,8 @@ public interface AutoConfigurationImportFilter { /** * Apply the filter to the given auto-configuration class candidates. * @param autoConfigurationClasses the auto-configuration classes being considered. - * Implementations should not change the values in this array. + * This array may contain {@code null} elements. Implementations should not change the + * values in this array. * @param autoConfigurationMetadata access to the meta-data generated by the * auto-configure annotation processor * @return a boolean array indicating which of the auto-configuration classes should diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java index b65ff3017db6..4f3532c86aec 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java @@ -263,6 +263,7 @@ private List filter(List configurations, for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; + candidates[i] = null; skipped = true; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java index a5a09f2d7d8d..cb9e5ab9d31b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java @@ -29,6 +29,7 @@ import java.util.TreeMap; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; @@ -159,6 +160,20 @@ public ConditionEvaluationReport getParent() { return this.parent; } + /** + * Attempt to find the {@link ConditionEvaluationReport} for the specified bean + * factory. + * @param beanFactory the bean factory (may be {@code null}) + * @return the {@link ConditionEvaluationReport} or {@code null} + */ + public static ConditionEvaluationReport find(BeanFactory beanFactory) { + if (beanFactory != null && beanFactory instanceof ConfigurableBeanFactory) { + return ConditionEvaluationReport + .get((ConfigurableListableBeanFactory) beanFactory); + } + return null; + } + /** * Obtain a {@link ConditionEvaluationReport} for the specified bean factory. * @param beanFactory the bean factory diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java new file mode 100644 index 000000000000..9a6f8da7e4b7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java @@ -0,0 +1,147 @@ +/* + * Copyright 2012-2018 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.autoconfigure.condition; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter; +import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; + +/** + * Abstract base class for a {@link SpringBootCondition} that also implements + * {@link AutoConfigurationImportFilter}. + * + * @author Phillip Webb + */ +abstract class FilteringSpringBootCondition extends SpringBootCondition + implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware { + + private BeanFactory beanFactory; + + private ClassLoader beanClassLoader; + + @Override + public boolean[] match(String[] autoConfigurationClasses, + AutoConfigurationMetadata autoConfigurationMetadata) { + ConditionEvaluationReport report = ConditionEvaluationReport + .find(this.beanFactory); + ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, + autoConfigurationMetadata); + boolean[] match = new boolean[outcomes.length]; + for (int i = 0; i < outcomes.length; i++) { + match[i] = (outcomes[i] == null || outcomes[i].isMatch()); + if (!match[i] && outcomes[i] != null) { + logOutcome(autoConfigurationClasses[i], outcomes[i]); + if (report != null) { + report.recordConditionEvaluation(autoConfigurationClasses[i], this, + outcomes[i]); + } + } + } + return match; + } + + protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, + AutoConfigurationMetadata autoConfigurationMetadata); + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + protected final BeanFactory getBeanFactory() { + return this.beanFactory; + } + + protected final ClassLoader getBeanClassLoader() { + return this.beanClassLoader; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + protected List filter(Collection classNames, + ClassNameFilter classNameFilter, ClassLoader classLoader) { + if (CollectionUtils.isEmpty(classNames)) { + return Collections.emptyList(); + } + List matches = new ArrayList<>(classNames.size()); + for (String candidate : classNames) { + if (classNameFilter.matches(candidate, classLoader)) { + matches.add(candidate); + } + } + return matches; + } + + protected enum ClassNameFilter { + + PRESENT { + + @Override + public boolean matches(String className, ClassLoader classLoader) { + return isPresent(className, classLoader); + } + + }, + + MISSING { + + @Override + public boolean matches(String className, ClassLoader classLoader) { + return !isPresent(className, classLoader); + } + + }; + + public abstract boolean matches(String className, ClassLoader classLoader); + + public static boolean isPresent(String className, ClassLoader classLoader) { + if (classLoader == null) { + classLoader = ClassUtils.getDefaultClassLoader(); + } + try { + forName(className, classLoader); + return true; + } + catch (Throwable ex) { + return false; + } + } + + private static Class forName(String className, ClassLoader classLoader) + throws ClassNotFoundException { + if (classLoader != null) { + return classLoader.loadClass(className); + } + return Class.forName(className); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java index 4b6b535df9fa..6ba4a8bef430 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java @@ -18,17 +18,10 @@ import java.security.AccessControlException; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter; import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style; @@ -37,7 +30,6 @@ import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; /** @@ -49,43 +41,10 @@ * @see ConditionalOnMissingClass */ @Order(Ordered.HIGHEST_PRECEDENCE) -class OnClassCondition extends SpringBootCondition - implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware { - - private BeanFactory beanFactory; - - private ClassLoader beanClassLoader; +class OnClassCondition extends FilteringSpringBootCondition { @Override - public boolean[] match(String[] autoConfigurationClasses, - AutoConfigurationMetadata autoConfigurationMetadata) { - ConditionEvaluationReport report = getConditionEvaluationReport(); - ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, - autoConfigurationMetadata); - boolean[] match = new boolean[outcomes.length]; - for (int i = 0; i < outcomes.length; i++) { - match[i] = (outcomes[i] == null || outcomes[i].isMatch()); - if (!match[i] && outcomes[i] != null) { - logOutcome(autoConfigurationClasses[i], outcomes[i]); - if (report != null) { - report.recordConditionEvaluation(autoConfigurationClasses[i], this, - outcomes[i]); - } - } - } - return match; - } - - private ConditionEvaluationReport getConditionEvaluationReport() { - if (this.beanFactory != null - && this.beanFactory instanceof ConfigurableBeanFactory) { - return ConditionEvaluationReport - .get((ConfigurableListableBeanFactory) this.beanFactory); - } - return null; - } - - private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, + protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { // Split the work and perform half in a background thread. Using a single // additional thread seems to offer the best performance. More threads make @@ -95,7 +54,7 @@ private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, autoConfigurationClasses, 0, split, autoConfigurationMetadata); OutcomesResolver secondHalfResolver = new StandardOutcomesResolver( autoConfigurationClasses, split, autoConfigurationClasses.length, - autoConfigurationMetadata, this.beanClassLoader); + autoConfigurationMetadata, getBeanClassLoader()); ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes(); ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes(); ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length]; @@ -108,7 +67,7 @@ private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasse int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) { OutcomesResolver outcomesResolver = new StandardOutcomesResolver( autoConfigurationClasses, start, end, autoConfigurationMetadata, - this.beanClassLoader); + getBeanClassLoader()); try { return new ThreadedOutcomesResolver(outcomesResolver); } @@ -124,7 +83,8 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, ConditionMessage matchMessage = ConditionMessage.empty(); List onClasses = getCandidates(metadata, ConditionalOnClass.class); if (onClasses != null) { - List missing = getMatches(onClasses, MatchType.MISSING, classLoader); + List missing = filter(onClasses, ClassNameFilter.MISSING, + classLoader); if (!missing.isEmpty()) { return ConditionOutcome .noMatch(ConditionMessage.forCondition(ConditionalOnClass.class) @@ -133,12 +93,12 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, } matchMessage = matchMessage.andCondition(ConditionalOnClass.class) .found("required class", "required classes").items(Style.QUOTE, - getMatches(onClasses, MatchType.PRESENT, classLoader)); + filter(onClasses, ClassNameFilter.PRESENT, classLoader)); } List onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class); if (onMissingClasses != null) { - List present = getMatches(onMissingClasses, MatchType.PRESENT, + List present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader); if (!present.isEmpty()) { return ConditionOutcome.noMatch( @@ -147,8 +107,9 @@ public ConditionOutcome getMatchOutcome(ConditionContext context, .items(Style.QUOTE, present)); } matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class) - .didNotFind("unwanted class", "unwanted classes").items(Style.QUOTE, - getMatches(onMissingClasses, MatchType.MISSING, classLoader)); + .didNotFind("unwanted class", "unwanted classes") + .items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, + classLoader)); } return ConditionOutcome.match(matchMessage); } @@ -174,72 +135,6 @@ private void addAll(List list, List itemsToAdd) { } } - private List getMatches(Collection candidates, MatchType matchType, - ClassLoader classLoader) { - List matches = new ArrayList<>(candidates.size()); - for (String candidate : candidates) { - if (matchType.matches(candidate, classLoader)) { - matches.add(candidate); - } - } - return matches; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - private enum MatchType { - - PRESENT { - - @Override - public boolean matches(String className, ClassLoader classLoader) { - return isPresent(className, classLoader); - } - - }, - - MISSING { - - @Override - public boolean matches(String className, ClassLoader classLoader) { - return !isPresent(className, classLoader); - } - - }; - - private static boolean isPresent(String className, ClassLoader classLoader) { - if (classLoader == null) { - classLoader = ClassUtils.getDefaultClassLoader(); - } - try { - forName(className, classLoader); - return true; - } - catch (Throwable ex) { - return false; - } - } - - private static Class forName(String className, ClassLoader classLoader) - throws ClassNotFoundException { - if (classLoader != null) { - return classLoader.loadClass(className); - } - return Class.forName(className); - } - - public abstract boolean matches(String className, ClassLoader classLoader); - - } - private interface OutcomesResolver { ConditionOutcome[] resolveOutcomes(); @@ -304,10 +199,12 @@ private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, ConditionOutcome[] outcomes = new ConditionOutcome[end - start]; for (int i = start; i < end; i++) { String autoConfigurationClass = autoConfigurationClasses[i]; - Set candidates = autoConfigurationMetadata - .getSet(autoConfigurationClass, "ConditionalOnClass"); - if (candidates != null) { - outcomes[i - start] = getOutcome(candidates); + if (autoConfigurationClass != null) { + Set candidates = autoConfigurationMetadata + .getSet(autoConfigurationClass, "ConditionalOnClass"); + if (candidates != null) { + outcomes[i - start] = getOutcome(candidates); + } } } return outcomes; @@ -315,7 +212,7 @@ private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, private ConditionOutcome getOutcome(Set candidates) { try { - List missing = getMatches(candidates, MatchType.MISSING, + List missing = filter(candidates, ClassNameFilter.MISSING, this.beanClassLoader); if (!missing.isEmpty()) { return ConditionOutcome.noMatch( From 586507c49a36eec07769fdbc86ca84b30164ebd9 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 21 Sep 2018 13:55:37 -0700 Subject: [PATCH 690/701] Generate auto-configuration OnBean data Update the auto-configuration annotation processor to generate properties for `@ConditionalOnBean` and `@ConditionalOnSingleCandidate`. See gh-13328 --- .../AutoConfigureAnnotationProcessor.java | 144 +++++++++++------- .../boot/autoconfigureprocessor/Elements.java | 60 ++++++++ ...AutoConfigureAnnotationProcessorTests.java | 36 ++++- .../TestClassConfiguration.java | 4 +- ...tConditionMetadataAnnotationProcessor.java | 7 +- .../TestConditionalOnBean.java | 45 ++++++ .../TestConditionalOnSingleCandidate.java | 40 +++++ .../TestOnBeanWithNameClassConfiguration.java | 28 ++++ 8 files changed, 303 insertions(+), 61 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java index 6c6a8937258d..e6bad9588a4e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java @@ -18,14 +18,15 @@ import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Properties; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.processing.AbstractProcessor; @@ -36,10 +37,8 @@ import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeMirror; import javax.tools.FileObject; import javax.tools.StandardLocation; @@ -52,6 +51,8 @@ */ @SupportedAnnotationTypes({ "org.springframework.context.annotation.Configuration", "org.springframework.boot.autoconfigure.condition.ConditionalOnClass", + "org.springframework.boot.autoconfigure.condition.ConditionalOnBean", + "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate", "org.springframework.boot.autoconfigure.AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureAfter", "org.springframework.boot.autoconfigure.AutoConfigureOrder" }) @@ -60,7 +61,9 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { protected static final String PROPERTIES_PATH = "META-INF/" + "spring-autoconfigure-metadata.properties"; - private Map annotations; + private final Map annotations; + + private final Map valueExtractors; private final Properties properties = new Properties(); @@ -68,6 +71,9 @@ public AutoConfigureAnnotationProcessor() { Map annotations = new LinkedHashMap<>(); addAnnotations(annotations); this.annotations = Collections.unmodifiableMap(annotations); + Map valueExtractors = new LinkedHashMap<>(); + addValueExtractors(valueExtractors); + this.valueExtractors = Collections.unmodifiableMap(valueExtractors); } protected void addAnnotations(Map annotations) { @@ -75,6 +81,10 @@ protected void addAnnotations(Map annotations) { "org.springframework.context.annotation.Configuration"); annotations.put("ConditionalOnClass", "org.springframework.boot.autoconfigure.condition.ConditionalOnClass"); + annotations.put("ConditionalOnBean", + "org.springframework.boot.autoconfigure.condition.ConditionalOnBean"); + annotations.put("ConditionalOnSingleCandidate", + "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate"); annotations.put("AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureBefore"); annotations.put("AutoConfigureAfter", @@ -83,6 +93,17 @@ protected void addAnnotations(Map annotations) { "org.springframework.boot.autoconfigure.AutoConfigureOrder"); } + private void addValueExtractors(Map attributes) { + attributes.put("Configuration", ValueExtractor.allFrom("value")); + attributes.put("ConditionalOnClass", ValueExtractor.allFrom("value", "name")); + attributes.put("ConditionalOnBean", new OnBeanConditionValueExtractor()); + attributes.put("ConditionalOnSingleCandidate", + new OnBeanConditionValueExtractor()); + attributes.put("AutoConfigureBefore", ValueExtractor.allFrom("value", "name")); + attributes.put("AutoConfigureAfter", ValueExtractor.allFrom("value", "name")); + attributes.put("AutoConfigureOrder", ValueExtractor.allFrom("value")); + } + @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); @@ -123,10 +144,10 @@ private void process(RoundEnvironment roundEnv, String propertyKey, private void processElement(Element element, String propertyKey, String annotationName) { try { - String qualifiedName = getQualifiedName(element); + String qualifiedName = Elements.getQualifiedName(element); AnnotationMirror annotation = getAnnotation(element, annotationName); if (qualifiedName != null && annotation != null) { - List values = getValues(annotation); + List values = getValues(propertyKey, annotation); this.properties.put(qualifiedName + "." + propertyKey, toCommaDelimitedString(values)); this.properties.put(qualifiedName, ""); @@ -158,68 +179,89 @@ private String toCommaDelimitedString(List list) { return result.toString(); } - private List getValues(AnnotationMirror annotation) { - return annotation.getElementValues().entrySet().stream() - .filter(this::isNameOrValueAttribute).flatMap(this::getValues) - .collect(Collectors.toList()); - } - - private boolean isNameOrValueAttribute(Entry entry) { - String attributeName = entry.getKey().getSimpleName().toString(); - return "name".equals(attributeName) || "value".equals(attributeName); + private List getValues(String propertyKey, AnnotationMirror annotation) { + ValueExtractor extractor = this.valueExtractors.get(propertyKey); + if (extractor == null) { + return Collections.emptyList(); + } + return extractor.getValues(annotation); } - @SuppressWarnings("unchecked") - private Stream getValues(Entry entry) { - Object value = entry.getValue().getValue(); - if (value instanceof List) { - return ((List) value).stream() - .map((annotation) -> processValue(annotation.getValue())); + private void writeProperties() throws IOException { + if (!this.properties.isEmpty()) { + FileObject file = this.processingEnv.getFiler() + .createResource(StandardLocation.CLASS_OUTPUT, "", PROPERTIES_PATH); + try (OutputStream outputStream = file.openOutputStream()) { + this.properties.store(outputStream, null); + } } - return Stream.of(processValue(value)); } - private Object processValue(Object value) { - if (value instanceof DeclaredType) { - return getQualifiedName(((DeclaredType) value).asElement()); + @FunctionalInterface + private interface ValueExtractor { + + List getValues(AnnotationMirror annotation); + + static ValueExtractor allFrom(String... attributes) { + Set names = new HashSet<>(Arrays.asList(attributes)); + return new AbstractValueExtractor() { + + @Override + public List getValues(AnnotationMirror annotation) { + List result = new ArrayList<>(); + annotation.getElementValues().forEach((key, value) -> { + if (names.contains(key.getSimpleName().toString())) { + extractValues(value).forEach(result::add); + } + }); + return result; + } + + }; } - return value; + } - private String getQualifiedName(Element element) { - if (element != null) { - TypeElement enclosingElement = getEnclosingTypeElement(element.asType()); - if (enclosingElement != null) { - return getQualifiedName(enclosingElement) + "$" - + ((DeclaredType) element.asType()).asElement().getSimpleName() - .toString(); + private abstract static class AbstractValueExtractor implements ValueExtractor { + + @SuppressWarnings("unchecked") + protected Stream extractValues(AnnotationValue annotationValue) { + if (annotationValue == null) { + return Stream.empty(); } - if (element instanceof TypeElement) { - return ((TypeElement) element).getQualifiedName().toString(); + Object value = annotationValue.getValue(); + if (value instanceof List) { + return ((List) value).stream() + .map((annotation) -> extractValue(annotation.getValue())); } + return Stream.of(extractValue(value)); } - return null; - } - private TypeElement getEnclosingTypeElement(TypeMirror type) { - if (type instanceof DeclaredType) { - DeclaredType declaredType = (DeclaredType) type; - Element enclosingElement = declaredType.asElement().getEnclosingElement(); - if (enclosingElement != null && enclosingElement instanceof TypeElement) { - return (TypeElement) enclosingElement; + private Object extractValue(Object value) { + if (value instanceof DeclaredType) { + return Elements.getQualifiedName(((DeclaredType) value).asElement()); } + return value; } - return null; + } - private void writeProperties() throws IOException { - if (!this.properties.isEmpty()) { - FileObject file = this.processingEnv.getFiler() - .createResource(StandardLocation.CLASS_OUTPUT, "", PROPERTIES_PATH); - try (OutputStream outputStream = file.openOutputStream()) { - this.properties.store(outputStream, null); + private static class OnBeanConditionValueExtractor extends AbstractValueExtractor { + + @Override + public List getValues(AnnotationMirror annotation) { + Map attributes = new LinkedHashMap<>(); + annotation.getElementValues().forEach((key, value) -> attributes + .put(key.getSimpleName().toString(), value)); + if (attributes.containsKey("name")) { + return Collections.emptyList(); } + List result = new ArrayList<>(); + extractValues(attributes.get("value")).forEach(result::add); + extractValues(attributes.get("type")).forEach(result::add); + return result; } + } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java new file mode 100644 index 000000000000..914c9beeea03 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2018 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.autoconfigureprocessor; + +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; + +/** + * Utilities for dealing with {@link Element} classes. + * + * @author Phillip Webb + */ +final class Elements { + + private Elements() { + } + + static String getQualifiedName(Element element) { + if (element != null) { + TypeElement enclosingElement = getEnclosingTypeElement(element.asType()); + if (enclosingElement != null) { + return getQualifiedName(enclosingElement) + "$" + + ((DeclaredType) element.asType()).asElement().getSimpleName() + .toString(); + } + if (element instanceof TypeElement) { + return ((TypeElement) element).getQualifiedName().toString(); + } + } + return null; + } + + private static TypeElement getEnclosingTypeElement(TypeMirror type) { + if (type instanceof DeclaredType) { + DeclaredType declaredType = (DeclaredType) type; + Element enclosingElement = declaredType.asElement().getEnclosingElement(); + if (enclosingElement != null && enclosingElement instanceof TypeElement) { + return (TypeElement) enclosingElement; + } + } + return null; + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java index 929960d087fe..716bd8ab2f58 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -50,18 +50,38 @@ public void createCompiler() throws IOException { @Test public void annotatedClass() throws Exception { Properties properties = compile(TestClassConfiguration.class); - assertThat(properties).hasSize(3); + assertThat(properties).hasSize(5); assertThat(properties).containsEntry( "org.springframework.boot.autoconfigureprocessor." + "TestClassConfiguration.ConditionalOnClass", "java.io.InputStream,org.springframework.boot.autoconfigureprocessor." + "TestClassConfiguration$Nested"); - assertThat(properties).containsKey( - "org.springframework.boot.autoconfigureprocessor.TestClassConfiguration"); - assertThat(properties).containsKey( - "org.springframework.boot.autoconfigureprocessor.TestClassConfiguration.Configuration"); - assertThat(properties).doesNotContainKey( - "org.springframework.boot.autoconfigureprocessor.TestClassConfiguration$Nested"); + assertThat(properties) + .containsKey("org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration"); + assertThat(properties) + .containsKey("org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration.Configuration"); + assertThat(properties) + .doesNotContainKey("org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration$Nested"); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration.ConditionalOnBean", + "java.io.OutputStream"); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration.ConditionalOnSingleCandidate", + "java.io.OutputStream"); + } + + @Test + public void annoatedClassWithOnBeanThatHasName() throws Exception { + Properties properties = compile(TestOnBeanWithNameClassConfiguration.class); + assertThat(properties).hasSize(3); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestOnBeanWithNameClassConfiguration.ConditionalOnBean", + ""); } @Test diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java index 3bc346b1ecbf..6cd743360952 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -23,6 +23,8 @@ */ @TestConfiguration @TestConditionalOnClass(name = "java.io.InputStream", value = TestClassConfiguration.Nested.class) +@TestConditionalOnBean(type = "java.io.OutputStream") +@TestConditionalOnSingleCandidate(type = "java.io.OutputStream") public class TestClassConfiguration { @TestAutoConfigureOrder diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java index 56471007965f..178d8e793f6e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -32,6 +32,8 @@ @SupportedAnnotationTypes({ "org.springframework.boot.autoconfigureprocessor.TestConfiguration", "org.springframework.boot.autoconfigureprocessor.TestConditionalOnClass", + "org.springframework.boot.autoconfigure.condition.TestConditionalOnBean", + "org.springframework.boot.autoconfigure.condition.TestConditionalOnSingleCandidate", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureBefore", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureAfter", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder" }) @@ -48,6 +50,9 @@ public TestConditionMetadataAnnotationProcessor(File outputLocation) { protected void addAnnotations(Map annotations) { put(annotations, "Configuration", TestConfiguration.class); put(annotations, "ConditionalOnClass", TestConditionalOnClass.class); + put(annotations, "ConditionalOnBean", TestConditionalOnBean.class); + put(annotations, "ConditionalOnSingleCandidate", + TestConditionalOnSingleCandidate.class); put(annotations, "AutoConfigureBefore", TestAutoConfigureBefore.class); put(annotations, "AutoConfigureAfter", TestAutoConfigureAfter.class); put(annotations, "AutoConfigureOrder", TestAutoConfigureOrder.class); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java new file mode 100644 index 000000000000..7c22b99abd13 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2018 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.autoconfigureprocessor; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Alternative to Spring Boot's {@code ConditionalOnBean} for testing (removes the need + * for a dependency on the real annotation). + * + * @author Phillip Webb + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TestConditionalOnBean { + + Class[] value() default {}; + + String[] type() default {}; + + Class[] annotation() default {}; + + String[] name() default {}; + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java new file mode 100644 index 000000000000..51e103e72587 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2018 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.autoconfigureprocessor; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Alternative to Spring Boot's {@code ConditionalOnSingleCandidate} for testing (removes + * the need for a dependency on the real annotation). + * + * @author Phillip Webb + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TestConditionalOnSingleCandidate { + + Class value() default Object.class; + + String type() default ""; + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java new file mode 100644 index 000000000000..3f4f87e9bd8b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2018 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.autoconfigureprocessor; + +/** + * Test configuration with an annotated class. + * + * @author Phillip Webb + */ +@TestConfiguration +@TestConditionalOnBean(name = "test", type = "java.io.OutputStream") +public class TestOnBeanWithNameClassConfiguration { + +} From c2f8398c06a7ffb22d95c8cba50d9bdcd20de849 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Sep 2018 09:30:07 -0400 Subject: [PATCH 691/701] Allow early OnBeanCondition filtering Update `OnBeanCondition` to be an `AutoConfigurationImportFilter` and filter out classes early. See gh-13328 --- .../condition/OnBeanCondition.java | 39 ++++++++++++++++++- .../main/resources/META-INF/spring.factories | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index 5da7222d54a8..fc49d7a93b10 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Condition; @@ -58,7 +59,8 @@ * @author Andy Wilkinson */ @Order(Ordered.LOWEST_PRECEDENCE) -class OnBeanCondition extends SpringBootCondition implements ConfigurationCondition { +class OnBeanCondition extends FilteringSpringBootCondition + implements ConfigurationCondition { /** * Bean definition attribute name for factory beans to signal their product type (if @@ -66,6 +68,40 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit */ public static final String FACTORY_BEAN_OBJECT_TYPE = BeanTypeRegistry.FACTORY_BEAN_OBJECT_TYPE; + @Override + protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, + AutoConfigurationMetadata autoConfigurationMetadata) { + ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length]; + for (int i = 0; i < outcomes.length; i++) { + String autoConfigurationClass = autoConfigurationClasses[i]; + if (autoConfigurationClass != null) { + Set onBeanTypes = autoConfigurationMetadata + .getSet(autoConfigurationClass, "ConditionalOnBean"); + outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class); + if (outcomes[i] == null) { + Set onSingleCandidateTypes = autoConfigurationMetadata.getSet( + autoConfigurationClass, "ConditionalOnSingleCandidate"); + outcomes[i] = getOutcome(onSingleCandidateTypes, + ConditionalOnSingleCandidate.class); + } + } + } + return outcomes; + } + + private ConditionOutcome getOutcome(Set requiredBeanTypes, + Class annotation) { + List missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, + getBeanClassLoader()); + if (!missing.isEmpty()) { + ConditionMessage message = ConditionMessage.forCondition(annotation) + .didNotFind("required type", "required types") + .items(Style.QUOTE, missing); + return ConditionOutcome.noMatch(message); + } + return null; + } + @Override public ConfigurationPhase getConfigurationPhase() { return ConfigurationPhase.REGISTER_BEAN; @@ -337,7 +373,6 @@ private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFa .getParentBeanFactory()), beanName, considerHierarchy); } return null; - } private static class BeanSearchSpec { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 5a80d1196aa7..df2d99ab37ff 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -17,6 +17,7 @@ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoCo # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ +org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ org.springframework.boot.autoconfigure.condition.OnClassCondition # Auto Configure From 75bde003348fc29ba5399563787dbf33534ddefb Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 21 Sep 2018 17:40:33 -0700 Subject: [PATCH 692/701] Generate auto-configuration OnWebApplication data Update the auto-configuration annotation processor to generate properties for `@OnWebApplication`. See gh-13328 --- .../AutoConfigureAnnotationProcessor.java | 4 ++ ...AutoConfigureAnnotationProcessorTests.java | 8 +++- ...TestAutoConfigureAnnotationProcessor.java} | 7 ++- .../TestClassConfiguration.java | 3 ++ .../TestConditionalOnWebApplication.java | 44 +++++++++++++++++++ 5 files changed, 62 insertions(+), 4 deletions(-) rename spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/{TestConditionMetadataAnnotationProcessor.java => TestAutoConfigureAnnotationProcessor.java} (90%) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java index e6bad9588a4e..2095eb80411b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java @@ -53,6 +53,7 @@ "org.springframework.boot.autoconfigure.condition.ConditionalOnClass", "org.springframework.boot.autoconfigure.condition.ConditionalOnBean", "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate", + "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication", "org.springframework.boot.autoconfigure.AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureAfter", "org.springframework.boot.autoconfigure.AutoConfigureOrder" }) @@ -85,6 +86,8 @@ protected void addAnnotations(Map annotations) { "org.springframework.boot.autoconfigure.condition.ConditionalOnBean"); annotations.put("ConditionalOnSingleCandidate", "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate"); + annotations.put("ConditionalOnWebApplication", + "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication"); annotations.put("AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureBefore"); annotations.put("AutoConfigureAfter", @@ -99,6 +102,7 @@ private void addValueExtractors(Map attributes) { attributes.put("ConditionalOnBean", new OnBeanConditionValueExtractor()); attributes.put("ConditionalOnSingleCandidate", new OnBeanConditionValueExtractor()); + attributes.put("ConditionalOnWebApplication", ValueExtractor.allFrom("type")); attributes.put("AutoConfigureBefore", ValueExtractor.allFrom("value", "name")); attributes.put("AutoConfigureAfter", ValueExtractor.allFrom("value", "name")); attributes.put("AutoConfigureOrder", ValueExtractor.allFrom("value")); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java index 716bd8ab2f58..acf14febef4c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java @@ -50,7 +50,7 @@ public void createCompiler() throws IOException { @Test public void annotatedClass() throws Exception { Properties properties = compile(TestClassConfiguration.class); - assertThat(properties).hasSize(5); + assertThat(properties).hasSize(6); assertThat(properties).containsEntry( "org.springframework.boot.autoconfigureprocessor." + "TestClassConfiguration.ConditionalOnClass", @@ -73,6 +73,10 @@ public void annotatedClass() throws Exception { "org.springframework.boot.autoconfigureprocessor." + "TestClassConfiguration.ConditionalOnSingleCandidate", "java.io.OutputStream"); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor." + + "TestClassConfiguration.ConditionalOnWebApplication", + "SERVLET"); } @Test @@ -124,7 +128,7 @@ public void annotatedClassWithOrder() throws Exception { } private Properties compile(Class... types) throws IOException { - TestConditionMetadataAnnotationProcessor processor = new TestConditionMetadataAnnotationProcessor( + TestAutoConfigureAnnotationProcessor processor = new TestAutoConfigureAnnotationProcessor( this.compiler.getOutputLocation()); this.compiler.getTask(types).call(processor); return processor.getWrittenProperties(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java similarity index 90% rename from spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java rename to spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java index 178d8e793f6e..1e2cd1470bcc 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionMetadataAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java @@ -34,15 +34,16 @@ "org.springframework.boot.autoconfigureprocessor.TestConditionalOnClass", "org.springframework.boot.autoconfigure.condition.TestConditionalOnBean", "org.springframework.boot.autoconfigure.condition.TestConditionalOnSingleCandidate", + "org.springframework.boot.autoconfigure.condition.TestConditionalOnWebApplication", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureBefore", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureAfter", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder" }) -public class TestConditionMetadataAnnotationProcessor +public class TestAutoConfigureAnnotationProcessor extends AutoConfigureAnnotationProcessor { private final File outputLocation; - public TestConditionMetadataAnnotationProcessor(File outputLocation) { + public TestAutoConfigureAnnotationProcessor(File outputLocation) { this.outputLocation = outputLocation; } @@ -53,6 +54,8 @@ protected void addAnnotations(Map annotations) { put(annotations, "ConditionalOnBean", TestConditionalOnBean.class); put(annotations, "ConditionalOnSingleCandidate", TestConditionalOnSingleCandidate.class); + put(annotations, "ConditionalOnWebApplication", + TestConditionalOnWebApplication.class); put(annotations, "AutoConfigureBefore", TestAutoConfigureBefore.class); put(annotations, "AutoConfigureAfter", TestAutoConfigureAfter.class); put(annotations, "AutoConfigureOrder", TestAutoConfigureOrder.class); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java index 6cd743360952..5bb32cb5b698 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigureprocessor; +import org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebApplication.Type; + /** * Test configuration with an annotated class. * @@ -25,6 +27,7 @@ @TestConditionalOnClass(name = "java.io.InputStream", value = TestClassConfiguration.Nested.class) @TestConditionalOnBean(type = "java.io.OutputStream") @TestConditionalOnSingleCandidate(type = "java.io.OutputStream") +@TestConditionalOnWebApplication(type = Type.SERVLET) public class TestClassConfiguration { @TestAutoConfigureOrder diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java new file mode 100644 index 000000000000..b340da7d0dfd --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2018 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.autoconfigureprocessor; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Alternative to Spring Boot's {@code @ConditionalOnWebApplication} for testing (removes + * the need for a dependency on the real annotation). + * + * @author Phillip Webb + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TestConditionalOnWebApplication { + + Type type() default Type.ANY; + + enum Type { + + ANY, SERVLET, REACTIVE + + } + +} From ff98ba0fa569b4d025ce9ad4532dd6b65800274b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Sep 2018 09:30:18 -0400 Subject: [PATCH 693/701] Allow early OnWebApplication filtering Update `OnWebApplicationCondition` to be an `AutoConfigurationImportFilter` and filter out classes early. Closes gh-13328 --- .../condition/OnWebApplicationCondition.java | 65 +++++++++++++++++-- .../main/resources/META-INF/spring.factories | 3 +- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java index 19fdb00cf927..8dc296e4c038 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java @@ -18,6 +18,7 @@ import java.util.Map; +import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebEnvironment; import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; @@ -36,14 +37,60 @@ * {@link WebApplicationContext}. * * @author Dave Syer + * @author Phillip Webb * @see ConditionalOnWebApplication * @see ConditionalOnNotWebApplication */ @Order(Ordered.HIGHEST_PRECEDENCE + 20) -class OnWebApplicationCondition extends SpringBootCondition { +class OnWebApplicationCondition extends FilteringSpringBootCondition { - private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context." - + "support.GenericWebApplicationContext"; + private static final String SERVLET_WEB_APPLICATION_CLASS = "org.springframework.web.context.support.GenericWebApplicationContext"; + + private static final String REACTIVE_WEB_APPLICATION_CLASS = "org.springframework.web.reactive.HandlerResult"; + + @Override + protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, + AutoConfigurationMetadata autoConfigurationMetadata) { + ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length]; + for (int i = 0; i < outcomes.length; i++) { + String autoConfigurationClass = autoConfigurationClasses[i]; + if (autoConfigurationClass != null) { + outcomes[i] = getOutcome(autoConfigurationMetadata + .get(autoConfigurationClass, "ConditionalOnWebApplication")); + } + } + return outcomes; + } + + private ConditionOutcome getOutcome(String type) { + if (type == null) { + return null; + } + ConditionMessage.Builder message = ConditionMessage + .forCondition(ConditionalOnWebApplication.class); + if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) { + if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, + getBeanClassLoader())) { + return ConditionOutcome.noMatch( + message.didNotFind("servlet web application classes").atAll()); + } + } + if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) { + if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, + getBeanClassLoader())) { + return ConditionOutcome.noMatch( + message.didNotFind("reactive web application classes").atAll()); + } + } + if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, + getBeanClassLoader()) + && !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, + getBeanClassLoader())) { + return ConditionOutcome.noMatch(message + .didNotFind("reactive or servlet web application classes").atAll()); + } + return null; + } @Override public ConditionOutcome getMatchOutcome(ConditionContext context, @@ -93,9 +140,10 @@ private ConditionOutcome isAnyWebApplication(ConditionContext context, private ConditionOutcome isServletWebApplication(ConditionContext context) { ConditionMessage.Builder message = ConditionMessage.forCondition(""); - if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) { - return ConditionOutcome - .noMatch(message.didNotFind("web application classes").atAll()); + if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, + context.getClassLoader())) { + return ConditionOutcome.noMatch( + message.didNotFind("servlet web application classes").atAll()); } if (context.getBeanFactory() != null) { String[] scopes = context.getBeanFactory().getRegisteredScopeNames(); @@ -115,6 +163,11 @@ private ConditionOutcome isServletWebApplication(ConditionContext context) { private ConditionOutcome isReactiveWebApplication(ConditionContext context) { ConditionMessage.Builder message = ConditionMessage.forCondition(""); + if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, + context.getClassLoader())) { + return ConditionOutcome.noMatch( + message.didNotFind("reactive web application classes").atAll()); + } if (context.getEnvironment() instanceof ConfigurableReactiveWebEnvironment) { return ConditionOutcome .match(message.foundExactly("ConfigurableReactiveWebEnvironment")); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index df2d99ab37ff..6ede25c04129 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -18,7 +18,8 @@ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoCo # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnBeanCondition,\ -org.springframework.boot.autoconfigure.condition.OnClassCondition +org.springframework.boot.autoconfigure.condition.OnClassCondition,\ +org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ From a04e913c2258ae843d58d02a22be5adc6ce627fa Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Sep 2018 10:20:25 -0400 Subject: [PATCH 694/701] Make ResourceHandlerRegistrationCustomizer public Make `ResourceHandlerRegistrationCustomizer` a public top level class. Closes gh-14587 --- ...ResourceHandlerRegistrationCustomizer.java | 76 +++++++++++++++++++ ...ResourceHandlerRegistrationCustomizer.java | 36 +++++++++ .../reactive/WebFluxAutoConfiguration.java | 56 -------------- 3 files changed, 112 insertions(+), 56 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceChainResourceHandlerRegistrationCustomizer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceHandlerRegistrationCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceChainResourceHandlerRegistrationCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceChainResourceHandlerRegistrationCustomizer.java new file mode 100644 index 000000000000..7a93244476cc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceChainResourceHandlerRegistrationCustomizer.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ResourceProperties; +import org.springframework.web.reactive.config.ResourceChainRegistration; +import org.springframework.web.reactive.config.ResourceHandlerRegistration; +import org.springframework.web.reactive.resource.AppCacheManifestTransformer; +import org.springframework.web.reactive.resource.EncodedResourceResolver; +import org.springframework.web.reactive.resource.ResourceResolver; +import org.springframework.web.reactive.resource.VersionResourceResolver; + +/** + * {@link ResourceHandlerRegistrationCustomizer} used by auto-configuration to customize + * the resource chain. + * + * @author Brian Clozel + */ +class ResourceChainResourceHandlerRegistrationCustomizer + implements ResourceHandlerRegistrationCustomizer { + + @Autowired + private ResourceProperties resourceProperties = new ResourceProperties(); + + @Override + public void customize(ResourceHandlerRegistration registration) { + ResourceProperties.Chain properties = this.resourceProperties.getChain(); + configureResourceChain(properties, + registration.resourceChain(properties.isCache())); + } + + private void configureResourceChain(ResourceProperties.Chain properties, + ResourceChainRegistration chain) { + ResourceProperties.Strategy strategy = properties.getStrategy(); + if (properties.isCompressed()) { + chain.addResolver(new EncodedResourceResolver()); + } + if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) { + chain.addResolver(getVersionResourceResolver(strategy)); + } + if (properties.isHtmlApplicationCache()) { + chain.addTransformer(new AppCacheManifestTransformer()); + } + } + + private ResourceResolver getVersionResourceResolver( + ResourceProperties.Strategy properties) { + VersionResourceResolver resolver = new VersionResourceResolver(); + if (properties.getFixed().isEnabled()) { + String version = properties.getFixed().getVersion(); + String[] paths = properties.getFixed().getPaths(); + resolver.addFixedVersionStrategy(version, paths); + } + if (properties.getContent().isEnabled()) { + String[] paths = properties.getContent().getPaths(); + resolver.addContentVersionStrategy(paths); + } + return resolver; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceHandlerRegistrationCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceHandlerRegistrationCustomizer.java new file mode 100644 index 000000000000..983bdeaae37f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ResourceHandlerRegistrationCustomizer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import org.springframework.web.reactive.config.ResourceHandlerRegistration; + +/** + * Callback interface that can be used to customize {@link ResourceHandlerRegistration}. + * + * @author Brian Clozel + * @since 2.1.0 + */ +@FunctionalInterface +public interface ResourceHandlerRegistrationCustomizer { + + /** + * Customize the given {@link ResourceHandlerRegistration}. + * @param registration the registration to customize + */ + void customize(ResourceHandlerRegistration registration); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 69c67aabb058..8c4c06fc624a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -25,7 +25,6 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -57,16 +56,11 @@ import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration; import org.springframework.web.reactive.config.EnableWebFlux; -import org.springframework.web.reactive.config.ResourceChainRegistration; import org.springframework.web.reactive.config.ResourceHandlerRegistration; import org.springframework.web.reactive.config.ResourceHandlerRegistry; import org.springframework.web.reactive.config.ViewResolverRegistry; import org.springframework.web.reactive.config.WebFluxConfigurationSupport; import org.springframework.web.reactive.config.WebFluxConfigurer; -import org.springframework.web.reactive.resource.AppCacheManifestTransformer; -import org.springframework.web.reactive.resource.EncodedResourceResolver; -import org.springframework.web.reactive.resource.ResourceResolver; -import org.springframework.web.reactive.resource.VersionResourceResolver; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; @@ -277,54 +271,4 @@ public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistr } - interface ResourceHandlerRegistrationCustomizer { - - void customize(ResourceHandlerRegistration registration); - - } - - static class ResourceChainResourceHandlerRegistrationCustomizer - implements ResourceHandlerRegistrationCustomizer { - - @Autowired - private ResourceProperties resourceProperties = new ResourceProperties(); - - @Override - public void customize(ResourceHandlerRegistration registration) { - ResourceProperties.Chain properties = this.resourceProperties.getChain(); - configureResourceChain(properties, - registration.resourceChain(properties.isCache())); - } - - private void configureResourceChain(ResourceProperties.Chain properties, - ResourceChainRegistration chain) { - ResourceProperties.Strategy strategy = properties.getStrategy(); - if (properties.isCompressed()) { - chain.addResolver(new EncodedResourceResolver()); - } - if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) { - chain.addResolver(getVersionResourceResolver(strategy)); - } - if (properties.isHtmlApplicationCache()) { - chain.addTransformer(new AppCacheManifestTransformer()); - } - } - - private ResourceResolver getVersionResourceResolver( - ResourceProperties.Strategy properties) { - VersionResourceResolver resolver = new VersionResourceResolver(); - if (properties.getFixed().isEnabled()) { - String version = properties.getFixed().getVersion(); - String[] paths = properties.getFixed().getPaths(); - resolver.addFixedVersionStrategy(version, paths); - } - if (properties.getContent().isEnabled()) { - String[] paths = properties.getContent().getPaths(); - resolver.addContentVersionStrategy(paths); - } - return resolver; - } - - } - } From 64627fa9d6a205deea9c87bf57055b99ecbdc087 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Sep 2018 15:38:59 -0400 Subject: [PATCH 695/701] Restore Maven 3.3 compatibility Downgrade the `spring-boot-maven-plugin` maven version to 3.3. Closes gh-14464 --- .../spring-boot-docs/src/main/asciidoc/getting-started.adoc | 6 +++--- .../spring-boot-tools/spring-boot-maven-plugin/pom.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc index 2e2ad1ca7023..f6d2d4e2ac45 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/getting-started.adoc @@ -47,7 +47,7 @@ Explicit build support is provided for the following build tools: |Build Tool |Version |Maven -|3.2+ +|3.3+ |Gradle |4.4+ @@ -108,7 +108,7 @@ tool that supports dependency management (such as Maven or Gradle). [[getting-started-maven-installation]] ==== Maven Installation -Spring Boot is compatible with Apache Maven 3.2 or above. If you do not already have +Spring Boot is compatible with Apache Maven 3.3 or above. If you do not already have Maven installed, you can follow the instructions at https://maven.apache.org. TIP: On many operating systems, Maven can be installed with a package manager. If you use @@ -522,7 +522,7 @@ valid versions of Java and Maven installed: [indent=0] ---- $ mvn -v - Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T16:41:47+00:00) + Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T14:33:14-04:00) Maven home: /usr/local/Cellar/maven/3.3.9/libexec Java version: 1.8.0_102, vendor: Oracle Corporation ---- diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/pom.xml index d54b568a383d..5649df482cd2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/pom.xml +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/pom.xml @@ -13,6 +13,7 @@ Spring Boot Maven Plugin ${basedir}/../../.. + 3.3.9 From e5ed5ebf8ba8eb87443ca6acf9b54d755869ed74 Mon Sep 17 00:00:00 2001 From: Hanope Date: Tue, 25 Sep 2018 21:15:00 +0900 Subject: [PATCH 696/701] Fix "Query Parameters" section name Closes gh-14600 --- .../src/main/asciidoc/endpoints/caches.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc index 7c795aca1e75..ac31aa4fe685 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/asciidoc/endpoints/caches.adoc @@ -42,8 +42,8 @@ include::{snippets}caches/named/http-response.adoc[] -[[caches-named-request-structure]] -=== Request Structure +[[caches-named-query-parameters]] +=== Query Parameters If the requested name is specific enough to identify a single cache, no extra parameter is required. Otherwise, the `cacheManager` must be specified. The following table shows the supported query parameters: From 1a8f519922b288491cc64d5ef0a0b95f443d7a66 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 17 Sep 2018 12:29:48 +0100 Subject: [PATCH 697/701] Raise the default version of Mongo to 3.6.5 when using Embedded Mongo While MongoDB 3.6.7 has been released, 3.6.5 is the latest version that's supported by the version of Embedded Mongo that we're currently using. Closes gh-14476 --- .../EmbeddedMongoAutoConfiguration.java | 20 +++++++++++++++---- .../embedded/EmbeddedMongoProperties.java | 10 ++++------ .../EmbeddedMongoAutoConfigurationTests.java | 9 +++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 5be48fdc6c61..be84094a0ec2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -35,6 +35,7 @@ import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion; +import de.flapdoodle.embed.mongo.distribution.Version; import de.flapdoodle.embed.mongo.distribution.Versions; import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.io.ProcessOutput; @@ -125,11 +126,8 @@ private MongodStarter getMongodStarter(IRuntimeConfig runtimeConfig) { @Bean @ConditionalOnMissingBean public IMongodConfig embeddedMongoConfiguration() throws IOException { - IFeatureAwareVersion featureAwareVersion = Versions.withFeatures( - new GenericVersion(this.embeddedProperties.getVersion()), - this.embeddedProperties.getFeatures().toArray(new Feature[0])); MongodConfigBuilder builder = new MongodConfigBuilder() - .version(featureAwareVersion); + .version(determineVersion()); EmbeddedMongoProperties.Storage storage = this.embeddedProperties.getStorage(); if (storage != null) { String databaseDir = storage.getDatabaseDir(); @@ -150,6 +148,20 @@ public IMongodConfig embeddedMongoConfiguration() throws IOException { return builder.build(); } + private IFeatureAwareVersion determineVersion() { + if (this.embeddedProperties.getFeatures() == null) { + for (Version version : Version.values()) { + if (version.asInDownloadPath() + .equals(this.embeddedProperties.getVersion())) { + return version; + } + } + } + return Versions.withFeatures( + new GenericVersion(this.embeddedProperties.getVersion()), + this.embeddedProperties.getFeatures().toArray(new Feature[0])); + } + private InetAddress getHost() throws UnknownHostException { if (this.properties.getHost() == null) { return InetAddress.getByAddress(Network.localhostIsIPv6() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java index 96a450db305e..bc40d48ef9b7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.mongo.embedded; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; import de.flapdoodle.embed.mongo.distribution.Feature; @@ -40,15 +38,15 @@ public class EmbeddedMongoProperties { /** * Version of Mongo to use. */ - private String version = "3.2.2"; + private String version = "3.6.5"; private final Storage storage = new Storage(); /** - * Comma-separated list of features to enable. + * Comma-separated list of features to enable. Uses the defaults of the configured + * version by default. */ - private Set features = new HashSet<>( - Collections.singletonList(Feature.SYNC_DELAY)); + private Set features = null; public String getVersion() { return this.version; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index 99248a4022ad..36354ebd4c39 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -60,19 +60,20 @@ public void close() { @Test public void defaultVersion() { - assertVersionConfiguration(null, "3.2.2"); + assertVersionConfiguration(null, "3.6.5"); } @Test public void customVersion() { - assertVersionConfiguration("2.7.1", "2.7.1"); + assertVersionConfiguration("3.6.3", "3.6.3"); } @Test public void customFeatures() { - load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY"); + load("spring.mongodb.embedded.features=TEXT_SEARCH, SYNC_DELAY, ONLY_WITH_SSL, NO_HTTP_INTERFACE_ARG"); assertThat(this.context.getBean(EmbeddedMongoProperties.class).getFeatures()) - .contains(Feature.TEXT_SEARCH, Feature.SYNC_DELAY); + .containsExactly(Feature.TEXT_SEARCH, Feature.SYNC_DELAY, + Feature.ONLY_WITH_SSL, Feature.NO_HTTP_INTERFACE_ARG); } @Test From f88ebf75cdb56f13e4792b2536781abee51ee45d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 25 Sep 2018 16:44:38 -0400 Subject: [PATCH 698/701] Use Mongo 3.5.5 by default with Embedded mongo Closes gh-14476 --- .../autoconfigure/mongo/embedded/EmbeddedMongoProperties.java | 2 +- .../mongo/embedded/EmbeddedMongoAutoConfigurationTests.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java index bc40d48ef9b7..4582fa5ed5e0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoProperties.java @@ -38,7 +38,7 @@ public class EmbeddedMongoProperties { /** * Version of Mongo to use. */ - private String version = "3.6.5"; + private String version = "3.5.5"; private final Storage storage = new Storage(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index 36354ebd4c39..e61566c74ccb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -60,12 +60,12 @@ public void close() { @Test public void defaultVersion() { - assertVersionConfiguration(null, "3.6.5"); + assertVersionConfiguration(null, "3.5.5"); } @Test public void customVersion() { - assertVersionConfiguration("3.6.3", "3.6.3"); + assertVersionConfiguration("3.4.15", "3.4.15"); } @Test From 698bbd6a9e347bd54c5d1697609eecea392c9e95 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Tue, 25 Sep 2018 15:56:37 +0900 Subject: [PATCH 699/701] Polish Closes gh-14597 --- .../dynatrace/DynatracePropertiesConfigAdapterTests.java | 2 +- .../elastic/ElasticPropertiesConfigAdapterTests.java | 2 +- .../ReactiveOAuth2ClientAutoConfigurationTests.java | 8 ++++---- .../boot/devtools/logger/DevToolsLogFactory.java | 5 ++--- .../src/main/asciidoc/spring-boot-features.adoc | 2 +- .../AutoConfigureAnnotationProcessorTests.java | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java index b8e6e6e9c13d..4fb38888b059 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java @@ -23,7 +23,7 @@ /** * Tests for {@link DynatracePropertiesConfigAdapter}. * - * @author Andy Wilkiknson + * @author Andy Wilkinson */ public class DynatracePropertiesConfigAdapterTests { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java index 427d63344e8f..fd7ee091be8b 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java @@ -23,7 +23,7 @@ /** * Tests for {@link ElasticPropertiesConfigAdapter}. * - * @author Andy Wilkiknson + * @author Andy Wilkinson */ public class ElasticPropertiesConfigAdapterTests { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java index acc2708aedb5..a9a140a92941 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -56,11 +56,11 @@ public class ReactiveOAuth2ClientAutoConfigurationTests { @Test public void autoConfigurationShouldBackOffForServletEnvironments() { - WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + new WebApplicationContextRunner() .withConfiguration(AutoConfigurations - .of(ReactiveOAuth2ClientAutoConfiguration.class)); - contextRunner.run((context) -> assertThat(context) - .doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class)); + .of(ReactiveOAuth2ClientAutoConfiguration.class)) + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class)); } @Test diff --git a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java index 9454570ac74a..eccfae58e3b8 100644 --- a/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java +++ b/spring-boot-project/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java @@ -24,7 +24,6 @@ import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.logging.DeferredLog; import org.springframework.context.ApplicationListener; -import org.springframework.data.domain.AbstractPageRequest; /** * Devtools deferred logging support. @@ -41,8 +40,8 @@ private DevToolsLogFactory() { /** * Get a {@link Log} instance for the specified source that will be automatically - * {@link DeferredLog#switchTo(Class) switched} then the {@link AbstractPageRequest - * context is prepared}. + * {@link DeferredLog#switchTo(Class) switched} when the + * {@link ApplicationPreparedEvent context is prepared}. * @param source the source for logging * @return a {@link DeferredLog} instance */ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index f94a7a6480f6..66874e6c8fa3 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -7163,7 +7163,7 @@ If you prefer your test to run against a real database, you can use the ==== Auto-configured Data JDBC Tests `@DataJdbcTest` is similar to `@JdbcTest` but is for tests that use Spring Data JDBC repositories. By default, it configures an in-memory embedded database, a `JdbcTemplate`, -and Spring Data JDBD repositories. Regular `@Component` beans are not loaded into +and Spring Data JDBC repositories. Regular `@Component` beans are not loaded into the `ApplicationContext`. TIP: A list of the auto-configurations that are enabled by `@DataJdbcTest` can be diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java index acf14febef4c..e1ae7f4cf30f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java @@ -80,7 +80,7 @@ public void annotatedClass() throws Exception { } @Test - public void annoatedClassWithOnBeanThatHasName() throws Exception { + public void annotatedClassWithOnBeanThatHasName() throws Exception { Properties properties = compile(TestOnBeanWithNameClassConfiguration.class); assertThat(properties).hasSize(3); assertThat(properties).containsEntry( From 95ae66b3ff032bb4dba36ba524e7390b9acd9849 Mon Sep 17 00:00:00 2001 From: Gustavo Andrade Date: Thu, 27 Sep 2018 16:57:11 -0300 Subject: [PATCH 700/701] Upgrade Java 11 CI image to 11-ea-28-jdk Closes gh-14631 --- ci/images/spring-boot-jdk11-ci-image/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/images/spring-boot-jdk11-ci-image/Dockerfile b/ci/images/spring-boot-jdk11-ci-image/Dockerfile index a15a764166c8..4f4bc651fbe6 100644 --- a/ci/images/spring-boot-jdk11-ci-image/Dockerfile +++ b/ci/images/spring-boot-jdk11-ci-image/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11-ea-24-jdk +FROM openjdk:11-ea-28-jdk RUN apt-get update && \ apt-get install -y git && \ From 1e756db9661c868e75c0783e7f82e5006b38af13 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Sun, 30 Sep 2018 23:01:06 +0900 Subject: [PATCH 701/701] Use Commons Logging for OnlyOnceLoggingDenyMeterFilter Closes gh-14637 --- .../metrics/OnlyOnceLoggingDenyMeterFilter.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java index cad3250c8f4e..7de8e61ed339 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/OnlyOnceLoggingDenyMeterFilter.java @@ -23,8 +23,8 @@ import io.micrometer.core.instrument.Meter.Id; import io.micrometer.core.instrument.config.MeterFilter; import io.micrometer.core.instrument.config.MeterFilterReply; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.util.Assert; @@ -38,8 +38,8 @@ */ public final class OnlyOnceLoggingDenyMeterFilter implements MeterFilter { - private final Logger logger = LoggerFactory - .getLogger(OnlyOnceLoggingDenyMeterFilter.class); + private static final Log logger = LogFactory + .getLog(OnlyOnceLoggingDenyMeterFilter.class); private final AtomicBoolean alreadyWarned = new AtomicBoolean(false); @@ -52,9 +52,8 @@ public OnlyOnceLoggingDenyMeterFilter(Supplier message) { @Override public MeterFilterReply accept(Id id) { - if (this.logger.isWarnEnabled() - && this.alreadyWarned.compareAndSet(false, true)) { - this.logger.warn(this.message.get()); + if (logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) { + logger.warn(this.message.get()); } return MeterFilterReply.DENY; }

  • Response Codes
    StatusMeaning