pull/35165/head
Phillip Webb 2 years ago
parent c13041201d
commit fc5339f81c

@ -27,8 +27,16 @@ package org.springframework.boot.autoconfigure.service.connection;
*/
public class ConnectionDetailsFactoryNotFoundException extends RuntimeException {
public <S> ConnectionDetailsFactoryNotFoundException(S source) {
super("No ConnectionDetailsFactory found for source '%s'".formatted(source));
<S> ConnectionDetailsFactoryNotFoundException(S source) {
this("No ConnectionDetailsFactory found for source '%s'".formatted(source));
}
public ConnectionDetailsFactoryNotFoundException(String message) {
super(message);
}
public ConnectionDetailsFactoryNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}

@ -27,8 +27,16 @@ package org.springframework.boot.autoconfigure.service.connection;
*/
public class ConnectionDetailsNotFoundException extends RuntimeException {
public <S> ConnectionDetailsNotFoundException(S source) {
super("No ConnectionDetails found for source '%s'".formatted(source));
<S> ConnectionDetailsNotFoundException(S source) {
this("No ConnectionDetails found for source '%s'".formatted(source));
}
public ConnectionDetailsNotFoundException(String message) {
super(message);
}
public ConnectionDetailsNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}

@ -30,11 +30,11 @@ class BeanOrigin implements Origin {
private final String beanName;
private final BeanDefinition beanDefinition;
private final String resourceDescription;
BeanOrigin(String beanName, BeanDefinition beanDefinition) {
this.beanName = beanName;
this.beanDefinition = beanDefinition;
this.resourceDescription = (beanDefinition != null) ? beanDefinition.getResourceDescription() : null;
}
@Override
@ -46,8 +46,7 @@ class BeanOrigin implements Origin {
return false;
}
BeanOrigin other = (BeanOrigin) obj;
return Objects.equals(this.beanName, other.beanName) && Objects
.equals(this.beanDefinition.getResourceDescription(), other.beanDefinition.getResourceDescription());
return Objects.equals(this.beanName, other.beanName);
}
@Override
@ -57,14 +56,13 @@ class BeanOrigin implements Origin {
@Override
public String toString() {
String resourceDescription = this.beanDefinition.getResourceDescription();
StringBuilder result = new StringBuilder();
result.append("Bean '");
result.append(this.beanName);
result.append("'");
if (resourceDescription != null) {
if (this.resourceDescription != null) {
result.append(" defined in ");
result.append(resourceDescription);
result.append(this.resourceDescription);
}
return result.toString();
}

@ -18,6 +18,7 @@ package org.springframework.boot.testcontainers.service.connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -36,35 +37,31 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Class used to register bean definitions from a list of
* Class used to register {@link ConnectionDetails} bean definitions from
* {@link ContainerConnectionSource} instances.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ContainerConnectionSourcesRegistrar {
class ConnectionDetailsRegistrar {
private static final Log logger = LogFactory.getLog(ContainerConnectionSourcesRegistrar.class);
private static final Log logger = LogFactory.getLog(ConnectionDetailsRegistrar.class);
private final ListableBeanFactory beanFactory;
private final ConnectionDetailsFactories connectionDetailsFactories;
private final List<ContainerConnectionSource<?>> sources;
ContainerConnectionSourcesRegistrar(ListableBeanFactory beanFactory,
ConnectionDetailsFactories connectionDetailsFactories, List<ContainerConnectionSource<?>> sources) {
ConnectionDetailsRegistrar(ListableBeanFactory beanFactory, ConnectionDetailsFactories connectionDetailsFactories) {
this.beanFactory = beanFactory;
this.connectionDetailsFactories = connectionDetailsFactories;
this.sources = sources;
}
void registerBeanDefinitions(BeanDefinitionRegistry registry) {
this.sources.forEach((source) -> registerBeanDefinition(registry, source));
void registerBeanDefinitions(BeanDefinitionRegistry registry, Collection<ContainerConnectionSource<?>> sources) {
sources.forEach((source) -> registerBeanDefinitions(registry, source));
}
private void registerBeanDefinition(BeanDefinitionRegistry registry, ContainerConnectionSource<?> source) {
private void registerBeanDefinitions(BeanDefinitionRegistry registry, ContainerConnectionSource<?> source) {
this.connectionDetailsFactories.getConnectionDetails(source, true)
.forEach((connectionDetailsType, connectionDetails) -> registerBeanDefinition(registry, source,
connectionDetailsType, connectionDetails));

@ -16,24 +16,12 @@
package org.springframework.boot.testcontainers.service.connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.testcontainers.containers.Container;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
import org.springframework.boot.origin.Origin;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
@ -45,53 +33,10 @@ import org.springframework.core.type.AnnotationMetadata;
*/
@AutoConfiguration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Import(ServiceConnectionAutoConfiguration.Registrar.class)
@Import(ServiceConnectionAutoConfigurationRegistrar.class)
public class ServiceConnectionAutoConfiguration {
ServiceConnectionAutoConfiguration() {
}
static class Registrar implements ImportBeanDefinitionRegistrar {
private final BeanFactory beanFactory;
Registrar(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {
ConnectionDetailsFactories connectionDetailsFactories = new ConnectionDetailsFactories();
List<ContainerConnectionSource<?>> sources = getSources(listableBeanFactory);
new ContainerConnectionSourcesRegistrar(listableBeanFactory, connectionDetailsFactories, sources)
.registerBeanDefinitions(registry);
}
}
private List<ContainerConnectionSource<?>> getSources(ConfigurableListableBeanFactory beanFactory) {
List<ContainerConnectionSource<?>> sources = new ArrayList<>();
for (String candidate : beanFactory.getBeanNamesForType(Container.class)) {
Set<ServiceConnection> annotations = beanFactory.findAllAnnotationsOnBean(candidate,
ServiceConnection.class, false);
if (!annotations.isEmpty()) {
addSources(sources, beanFactory, candidate, annotations);
}
}
return sources;
}
private void addSources(List<ContainerConnectionSource<?>> sources, ConfigurableListableBeanFactory beanFactory,
String beanName, Set<ServiceConnection> annotations) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
Origin origin = new BeanOrigin(beanName, beanDefinition);
Container<?> container = beanFactory.getBean(beanName, Container.class);
for (ServiceConnection annotation : annotations) {
sources.add(new ContainerConnectionSource<>(beanName, origin, container, annotation));
}
}
}
}

@ -0,0 +1,80 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.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.boot.testcontainers.service.connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.testcontainers.containers.Container;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
import org.springframework.boot.origin.Origin;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* {@link ImportBeanDefinitionRegistrar} used by
* {@link ServiceConnectionAutoConfiguration}.
*
* @author Phillip Webb
*/
class ServiceConnectionAutoConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
private final BeanFactory beanFactory;
ServiceConnectionAutoConfigurationRegistrar(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {
ConnectionDetailsFactories connectionDetailsFactories = new ConnectionDetailsFactories();
List<ContainerConnectionSource<?>> sources = getSources(listableBeanFactory);
new ConnectionDetailsRegistrar(listableBeanFactory, connectionDetailsFactories)
.registerBeanDefinitions(registry, sources);
}
}
private List<ContainerConnectionSource<?>> getSources(ConfigurableListableBeanFactory beanFactory) {
List<ContainerConnectionSource<?>> sources = new ArrayList<>();
for (String candidate : beanFactory.getBeanNamesForType(Container.class)) {
Set<ServiceConnection> annotations = beanFactory.findAllAnnotationsOnBean(candidate,
ServiceConnection.class, false);
if (!annotations.isEmpty()) {
addSources(sources, beanFactory, candidate, annotations);
}
}
return sources;
}
private void addSources(List<ContainerConnectionSource<?>> sources, ConfigurableListableBeanFactory beanFactory,
String beanName, Set<ServiceConnection> annotations) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
Origin origin = new BeanOrigin(beanName, beanDefinition);
Container<?> container = beanFactory.getBean(beanName, Container.class);
for (ServiceConnection annotation : annotations) {
sources.add(new ContainerConnectionSource<>(beanName, origin, container, annotation));
}
}
}

@ -53,8 +53,8 @@ class ServiceConnectionContextCustomizer implements ContextCustomizer {
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
if (beanFactory instanceof BeanDefinitionRegistry registry) {
new ContainerConnectionSourcesRegistrar(beanFactory, this.connectionDetailsFactories, this.sources)
.registerBeanDefinitions(registry);
new ConnectionDetailsRegistrar(beanFactory, this.connectionDetailsFactories)
.registerBeanDefinitions(registry, this.sources);
}
}

@ -33,7 +33,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ServiceConnectionAutoConfiguration}.
* Tests for {@link ServiceConnectionAutoConfiguration} and
* {@link ServiceConnectionAutoConfigurationRegistrar}.
*
* @author Phillip Webb
*/

Loading…
Cancel
Save