#1252 - Make sure HypermediaWebTestClientConfigurer is only included with spring-test on the classpath.

HypermediaConfigurationImportSelector is now ResourceLoaderAware to make sure it uses the class loader used to bootstrap the application context. This is important for both testing as well as custom classloader arrangements like Boot's DevTools. We now only include WebTestHateoasConfiguration if WebTestClient is on the classpath.

The configuration class has been extracted to not leak references to code tied to spring-test into production deployments. Added test cases to check both the inclusion and exclusion of the configuration classes based on the classpath arrangement.

Original pull request: #1251.
This commit is contained in:
Greg Turnquist
2020-04-02 11:13:48 -05:00
committed by Oliver Drotbohm
parent 599a366c85
commit de38b9e200
7 changed files with 220 additions and 19 deletions

View File

@@ -20,26 +20,44 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.MediaType;
import org.springframework.util.ClassUtils;
/**
* {@link ImportSelector} that looks up configuration classes from all {@link MediaTypeConfigurationProvider}
* implementations listed in {@code META-INF/spring.factories}.
*
* @author Oliver Drotbohm
* @author Greg Turnquist
*/
class HypermediaConfigurationImportSelector implements ImportSelector {
class HypermediaConfigurationImportSelector implements ImportSelector, ResourceLoaderAware {
public static final String SPRING_TEST = "org.springframework.test.web.reactive.server.WebTestClient";
private ResourceLoader resourceLoader;
/*
* (non-Javadoc)
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader)
*/
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/*
* (non-Javadoc)
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
*/
@Override
public String[] selectImports(AnnotationMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(EnableHypermediaSupport.class.getName());
@@ -54,11 +72,17 @@ class HypermediaConfigurationImportSelector implements ImportSelector {
MediaTypeConfigurationProvider.class, HypermediaConfigurationImportSelector.class.getClassLoader());
// Filter the ones supporting the given media types
return configurationProviders.stream() //
Stream<String> imports = configurationProviders.stream() //
.filter(it -> it.supportsAny(types)) //
.map(MediaTypeConfigurationProvider::getConfiguration) //
.map(Class::getName) //
.toArray(String[]::new);
.map(Class::getName);
// Conditionally apply other configurations
if (ClassUtils.isPresent(SPRING_TEST, resourceLoader.getClassLoader())) {
imports = Stream.concat(imports, Stream.of(WebTestHateoasConfiguration.class.getName()));
}
return imports.toArray(String[]::new);
}
public String[] selectImports(List<MediaType> mediaType) {

View File

@@ -37,7 +37,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
public class HypermediaWebClientConfigurer {
Consumer<ClientCodecConfigurer> configurer;
final Consumer<ClientCodecConfigurer> configurer;
/**
* Creates a new {@link HypermediaWebClientConfigurer} for the given {@link ObjectMapper} and

View File

@@ -24,7 +24,6 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull;
import org.springframework.web.reactive.function.client.WebClient;
@@ -45,13 +44,6 @@ class WebClientHateoasConfiguration {
return new HypermediaWebClientConfigurer(mapper.getIfAvailable(ObjectMapper::new), hypermediaTypes);
}
@Bean
@Lazy
HypermediaWebTestClientConfigurer webTestClientConfigurer(ObjectProvider<ObjectMapper> mapper,
List<HypermediaMappingInformation> hypermediaTypes) {
return new HypermediaWebTestClientConfigurer(mapper.getIfAvailable(ObjectMapper::new), hypermediaTypes);
}
@Bean
static HypermediaWebClientBeanPostProcessor webClientBeanPostProcessor(HypermediaWebClientConfigurer configurer) {
return new HypermediaWebClientBeanPostProcessor(configurer);

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES 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.hateoas.config;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Configuration for Spring TEST-specific things
*
* @author Greg Turnquist
* @author Oliver Drotbohm
* @since 1.1
*/
@Configuration(proxyBeanMethods = false)
class WebTestHateoasConfiguration {
@Bean
@Lazy
HypermediaWebTestClientConfigurer webTestClientConfigurer(ObjectProvider<ObjectMapper> mapper,
List<HypermediaMappingInformation> hypermediaTypes) {
return new HypermediaWebTestClientConfigurer(mapper.getIfAvailable(ObjectMapper::new), hypermediaTypes);
}
}