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
pull/14560/head
Andy Wilkinson 6 years ago
parent cc6cf880cf
commit 426ff3ada7

@ -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 @@ import org.springframework.context.annotation.Bean;
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
public class JerseyManagementChildContextConfiguration {
private final Stream<ResourceConfigCustomizer> resourceConfigCustomizers;
private final ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers;
public JerseyManagementChildContextConfiguration(
ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {
this.resourceConfigCustomizers = resourceConfigCustomizers.orderedStream();
this.resourceConfigCustomizers = resourceConfigCustomizers;
}
@Bean
@ -63,7 +61,7 @@ public class JerseyManagementChildContextConfiguration {
@Bean
public ResourceConfig endpointResourceConfig() {
ResourceConfig resourceConfig = new ResourceConfig();
this.resourceConfigCustomizers
this.resourceConfigCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(resourceConfig));
return resourceConfig;
}

@ -20,7 +20,6 @@ import java.io.IOException;
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<JCacheManagerCustomizer> cacheManagerCustomizers;
private final ObjectProvider<JCacheManagerCustomizer> cacheManagerCustomizers;
private final Stream<JCachePropertiesCustomizer> cachePropertiesCustomizers;
private final ObjectProvider<JCachePropertiesCustomizer> 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 @@ class JCacheCacheConfiguration implements BeanClassLoaderAware {
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 @@ class JCacheCacheConfiguration implements BeanClassLoaderAware {
}
private void customize(CacheManager cacheManager) {
this.cacheManagerCustomizers
this.cacheManagerCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(cacheManager));
}

@ -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<ClusterBuilderCustomizer> builderCustomizers;
private final ObjectProvider<ClusterBuilderCustomizer> builderCustomizers;
public CassandraAutoConfiguration(CassandraProperties properties,
ObjectProvider<ClusterBuilderCustomizer> builderCustomizers) {
this.properties = properties;
this.builderCustomizers = builderCustomizers.orderedStream();
this.builderCustomizers = builderCustomizers;
}
@Bean
@ -88,7 +87,8 @@ public class CassandraAutoConfiguration {
}
private void customize(Cluster.Builder builder) {
this.builderCustomizers.forEach((customizer) -> customizer.customize(builder));
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
}
private QueryOptions getQueryOptions() {

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.data.redis;
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<JedisClientConfigurationBuilderCustomizer> builderCustomizers;
private final ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers;
JedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
@ -58,7 +57,7 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration {
ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
super(properties, sentinelConfiguration, clusterConfiguration);
this.properties = properties;
this.builderCustomizers = builderCustomizers.orderedStream();
this.builderCustomizers = builderCustomizers;
}
@Bean
@ -131,7 +130,8 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration {
private void customize(
JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
this.builderCustomizers.forEach((customizer) -> customizer.customize(builder));
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
}
}

@ -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<LettuceClientConfigurationBuilderCustomizer> builderCustomizers;
private final ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers;
LettuceConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
@ -59,7 +58,7 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers) {
super(properties, sentinelConfigurationProvider, clusterConfigurationProvider);
this.properties = properties;
this.builderCustomizers = builderCustomizers.orderedStream();
this.builderCustomizers = builderCustomizers;
}
@Bean(destroyMethod = "shutdown")
@ -137,7 +136,8 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
private void customize(
LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) {
this.builderCustomizers.forEach((customizer) -> customizer.customize(builder));
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
}
/**

@ -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<Gson> gsonProvider;
private final Stream<HttpClientConfigBuilderCustomizer> builderCustomizers;
private final ObjectProvider<HttpClientConfigBuilderCustomizer> builderCustomizers;
public JestAutoConfiguration(JestProperties properties, ObjectProvider<Gson> gson,
ObjectProvider<HttpClientConfigBuilderCustomizer> builderCustomizers) {
this.properties = properties;
this.gsonProvider = gson;
this.builderCustomizers = builderCustomizers.orderedStream();
this.builderCustomizers = builderCustomizers;
}
@Bean(destroyMethod = "shutdownClient")
@ -93,7 +92,8 @@ public class JestAutoConfiguration {
}
private void customize(HttpClientConfig.Builder builder) {
this.builderCustomizers.forEach((customizer) -> customizer.customize(builder));
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
}
}

@ -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<RestClientBuilderCustomizer> builderCustomizers;
private final ObjectProvider<RestClientBuilderCustomizer> builderCustomizers;
public RestClientAutoConfiguration(RestClientProperties properties,
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
this.properties = properties;
this.builderCustomizers = builderCustomizers.orderedStream();
this.builderCustomizers = builderCustomizers;
}
@Bean
@ -79,7 +77,8 @@ public class RestClientAutoConfiguration {
builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider));
});
this.builderCustomizers.forEach((customizer) -> customizer.customize(builder));
this.builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(builder));
return builder;
}

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.jersey;
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<ResourceConfigCustomizer> customizers;
private final ObjectProvider<ResourceConfigCustomizer> customizers;
private String path;
@ -101,7 +100,7 @@ public class JerseyAutoConfiguration implements ServletContextAware {
ObjectProvider<ResourceConfigCustomizer> customizers) {
this.jersey = jersey;
this.config = config;
this.customizers = customizers.orderedStream();
this.customizers = customizers;
}
@PostConstruct
@ -121,7 +120,8 @@ public class JerseyAutoConfiguration implements ServletContextAware {
}
private void customize() {
this.customizers.forEach((customizer) -> customizer.customize(this.config));
this.customizers.orderedStream()
.forEach((customizer) -> customizer.customize(this.config));
}
@Bean

@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.jms.artemis;
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<ArtemisConfigurationCustomizer> configurationCustomizers;
private final ObjectProvider<ArtemisConfigurationCustomizer> configurationCustomizers;
private final List<JMSQueueConfiguration> queuesConfiguration;
@ -61,7 +60,7 @@ class ArtemisEmbeddedServerConfiguration {
ObjectProvider<JMSQueueConfiguration> queuesConfiguration,
ObjectProvider<TopicConfiguration> 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 @@ class ArtemisEmbeddedServerConfiguration {
private void customize(
org.apache.activemq.artemis.core.config.Configuration configuration) {
this.configurationCustomizers
this.configurationCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(configuration));
}

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.quartz;
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<SchedulerFactoryBeanCustomizer> customizers;
private final ObjectProvider<SchedulerFactoryBeanCustomizer> customizers;
private final JobDetail[] jobDetails;
@ -77,7 +76,7 @@ public class QuartzAutoConfiguration {
ObjectProvider<Map<String, Calendar>> calendars,
ObjectProvider<Trigger[]> 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 @@ public class QuartzAutoConfiguration {
}
private void customize(SchedulerFactoryBean schedulerFactoryBean) {
this.customizers
this.customizers.orderedStream()
.forEach((customizer) -> customizer.customize(schedulerFactoryBean));
}

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.thymeleaf;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
@ -136,14 +135,14 @@ public class ThymeleafAutoConfiguration {
private final Collection<ITemplateResolver> templateResolvers;
private final Stream<IDialect> dialects;
private final ObjectProvider<IDialect> dialects;
public ThymeleafDefaultConfiguration(ThymeleafProperties properties,
Collection<ITemplateResolver> templateResolvers,
ObjectProvider<IDialect> dialectsProvider) {
this.properties = properties;
this.templateResolvers = templateResolvers;
this.dialects = dialectsProvider.orderedStream();
this.dialects = dialectsProvider;
}
@Bean
@ -152,7 +151,7 @@ public class ThymeleafAutoConfiguration {
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 @@ public class ThymeleafAutoConfiguration {
private final Collection<ITemplateResolver> templateResolvers;
private final Stream<IDialect> dialects;
private final ObjectProvider<IDialect> dialects;
ThymeleafReactiveConfiguration(ThymeleafProperties properties,
Collection<ITemplateResolver> templateResolvers,
ObjectProvider<IDialect> dialectsProvider) {
this.properties = properties;
this.templateResolvers = templateResolvers;
this.dialects = dialectsProvider.orderedStream();
this.dialects = dialectsProvider;
}
@Bean
@ -240,7 +239,7 @@ public class ThymeleafAutoConfiguration {
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;
}

@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.web.reactive;
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 class WebFluxAutoConfiguration {
private final ListableBeanFactory beanFactory;
private final Stream<HandlerMethodArgumentResolver> argumentResolvers;
private final ObjectProvider<HandlerMethodArgumentResolver> argumentResolvers;
private final Stream<CodecCustomizer> codecCustomizers;
private final ObjectProvider<CodecCustomizer> codecCustomizers;
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
private final Stream<ViewResolver> viewResolvers;
private final ObjectProvider<ViewResolver> viewResolvers;
public WebFluxConfig(ResourceProperties resourceProperties,
WebFluxProperties webFluxProperties, ListableBeanFactory beanFactory,
@ -131,21 +130,21 @@ public class WebFluxAutoConfiguration {
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 class WebFluxAutoConfiguration {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
this.viewResolvers.forEach(registry::viewResolver);
this.viewResolvers.orderedStream().forEach(registry::viewResolver);
}
@Override

Loading…
Cancel
Save