Add AOT support for Registry of HTTP Interface Proxies
This commit adds AOT support for restoring the state of the HttpServiceProxyRegistry. This generates code for the groupsMetadata as well as for the creation of the client proxies. Closes gh-34750
This commit is contained in:
parent
e3e99ac8a0
commit
88e773ae24
|
@ -26,7 +26,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
|
@ -38,7 +38,6 @@ import org.springframework.core.type.MethodMetadata;
|
|||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.service.annotation.HttpExchange;
|
||||
|
||||
/**
|
||||
|
@ -69,6 +68,7 @@ import org.springframework.web.service.annotation.HttpExchange;
|
|||
* @author Rossen Stoyanchev
|
||||
* @author Phillip Webb
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Stephane Nicoll
|
||||
* @since 7.0
|
||||
* @see ImportHttpServices
|
||||
* @see HttpServiceProxyRegistryFactoryBean
|
||||
|
@ -76,6 +76,13 @@ import org.springframework.web.service.annotation.HttpExchange;
|
|||
public abstract class AbstractHttpServiceRegistrar implements
|
||||
ImportBeanDefinitionRegistrar, EnvironmentAware, ResourceLoaderAware, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* The bean name of the {@link HttpServiceProxyRegistry}.
|
||||
*/
|
||||
public static final String HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME = "httpServiceProxyRegistry";
|
||||
|
||||
static final String HTTP_SERVICE_GROUP_NAME_ATTRIBUTE = "httpServiceGroupName";
|
||||
|
||||
private HttpServiceGroup.ClientType defaultClientType = HttpServiceGroup.ClientType.UNSPECIFIED;
|
||||
|
||||
private @Nullable Environment environment;
|
||||
|
@ -127,33 +134,36 @@ public abstract class AbstractHttpServiceRegistrar implements
|
|||
|
||||
registerHttpServices(new DefaultGroupRegistry(), metadata);
|
||||
|
||||
String proxyRegistryBeanName = StringUtils.uncapitalize(HttpServiceProxyRegistry.class.getSimpleName());
|
||||
GenericBeanDefinition proxyRegistryBeanDef;
|
||||
|
||||
if (!beanRegistry.containsBeanDefinition(proxyRegistryBeanName)) {
|
||||
proxyRegistryBeanDef = new GenericBeanDefinition();
|
||||
proxyRegistryBeanDef.setBeanClass(HttpServiceProxyRegistryFactoryBean.class);
|
||||
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
|
||||
args.addIndexedArgumentValue(0, new GroupsMetadata());
|
||||
beanRegistry.registerBeanDefinition(proxyRegistryBeanName, proxyRegistryBeanDef);
|
||||
}
|
||||
else {
|
||||
proxyRegistryBeanDef = (GenericBeanDefinition) beanRegistry.getBeanDefinition(proxyRegistryBeanName);
|
||||
}
|
||||
RootBeanDefinition proxyRegistryBeanDef = createOrGetRegistry(beanRegistry);
|
||||
|
||||
mergeGroups(proxyRegistryBeanDef);
|
||||
|
||||
this.groupsMetadata.forEachRegistration((groupName, types) -> types.forEach(type -> {
|
||||
GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition();
|
||||
RootBeanDefinition proxyBeanDef = new RootBeanDefinition();
|
||||
proxyBeanDef.setBeanClassName(type);
|
||||
proxyBeanDef.setAttribute(HTTP_SERVICE_GROUP_NAME_ATTRIBUTE, groupName);
|
||||
proxyBeanDef.setInstanceSupplier(() -> getProxyInstance(groupName, type));
|
||||
String beanName = (groupName + "#" + type);
|
||||
proxyBeanDef.setInstanceSupplier(() -> getProxyInstance(proxyRegistryBeanName, groupName, type));
|
||||
if (!beanRegistry.containsBeanDefinition(beanName)) {
|
||||
beanRegistry.registerBeanDefinition(beanName, proxyBeanDef);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private RootBeanDefinition createOrGetRegistry(BeanDefinitionRegistry beanRegistry) {
|
||||
if (!beanRegistry.containsBeanDefinition(HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME)) {
|
||||
RootBeanDefinition proxyRegistryBeanDef = new RootBeanDefinition();
|
||||
proxyRegistryBeanDef.setBeanClass(HttpServiceProxyRegistryFactoryBean.class);
|
||||
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
|
||||
args.addIndexedArgumentValue(0, new GroupsMetadata());
|
||||
beanRegistry.registerBeanDefinition(HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME, proxyRegistryBeanDef);
|
||||
return proxyRegistryBeanDef;
|
||||
}
|
||||
else {
|
||||
return (RootBeanDefinition) beanRegistry.getBeanDefinition(HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before any bean definition registrations are made.
|
||||
* Subclasses must implement it to register the HTTP Services for which bean
|
||||
|
@ -175,7 +185,7 @@ public abstract class AbstractHttpServiceRegistrar implements
|
|||
return this.scanner;
|
||||
}
|
||||
|
||||
private void mergeGroups(GenericBeanDefinition proxyRegistryBeanDef) {
|
||||
private void mergeGroups(RootBeanDefinition proxyRegistryBeanDef) {
|
||||
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
|
||||
ConstructorArgumentValues.ValueHolder valueHolder = args.getArgumentValue(0, GroupsMetadata.class);
|
||||
Assert.state(valueHolder != null, "Expected GroupsMetadata constructor argument at index 0");
|
||||
|
@ -184,12 +194,10 @@ public abstract class AbstractHttpServiceRegistrar implements
|
|||
target.mergeWith(this.groupsMetadata);
|
||||
}
|
||||
|
||||
private Object getProxyInstance(String registryBeanName, String groupName, String httpServiceType) {
|
||||
private Object getProxyInstance(String groupName, String httpServiceType) {
|
||||
Assert.state(this.beanFactory != null, "BeanFactory has not been set");
|
||||
HttpServiceProxyRegistry registry = this.beanFactory.getBean(registryBeanName, HttpServiceProxyRegistry.class);
|
||||
Object proxy = registry.getClient(groupName, GroupsMetadata.loadClass(httpServiceType));
|
||||
Assert.notNull(proxy, "No proxy for HTTP Service [" + httpServiceType + "]");
|
||||
return proxy;
|
||||
HttpServiceProxyRegistry registry = this.beanFactory.getBean(HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME, HttpServiceProxyRegistry.class);
|
||||
return registry.getClient(groupName, GroupsMetadata.loadClass(httpServiceType));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
package org.springframework.web.service.registry;
|
||||
|
||||
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.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
@ -37,8 +39,16 @@ import org.springframework.util.ClassUtils;
|
|||
*/
|
||||
final class GroupsMetadata {
|
||||
|
||||
private final Map<String, DefaultRegistration> groupMap = new LinkedHashMap<>();
|
||||
private final Map<String, DefaultRegistration> groupMap;
|
||||
|
||||
public GroupsMetadata() {
|
||||
this(Collections.emptyList());
|
||||
}
|
||||
|
||||
GroupsMetadata(Iterable<DefaultRegistration> registrations) {
|
||||
this.groupMap = new LinkedHashMap<>();
|
||||
registrations.forEach(registration -> this.groupMap.put(registration.name(), registration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a registration for the given group name, or return an existing
|
||||
|
@ -85,6 +95,13 @@ final class GroupsMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the raw {@link DefaultRegistration registrations}.
|
||||
*/
|
||||
Stream<DefaultRegistration> registrations() {
|
||||
return this.groupMap.values().stream();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registration metadata for an {@link HttpServiceGroup}.
|
||||
|
@ -102,17 +119,22 @@ final class GroupsMetadata {
|
|||
/**
|
||||
* Default implementation of {@link Registration}.
|
||||
*/
|
||||
private static class DefaultRegistration implements Registration {
|
||||
static class DefaultRegistration implements Registration {
|
||||
|
||||
private final String name;
|
||||
|
||||
private HttpServiceGroup.ClientType clientType;
|
||||
|
||||
private final Set<String> typeNames = new LinkedHashSet<>();
|
||||
private final Set<String> typeNames;
|
||||
|
||||
DefaultRegistration(String name, HttpServiceGroup.ClientType clientType) {
|
||||
this(name, clientType, new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
DefaultRegistration(String name, HttpServiceGroup.ClientType clientType, Set<String> typeNames) {
|
||||
this.name = name;
|
||||
this.clientType = clientType;
|
||||
this.typeNames = typeNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.web.service.registry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
|
||||
import org.springframework.aot.generate.ValueCodeGenerator;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.web.service.registry.GroupsMetadata.DefaultRegistration;
|
||||
|
||||
/**
|
||||
* {@link ValueCodeGenerator.Delegate} for {@link GroupsMetadata}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 7.0
|
||||
*/
|
||||
final class GroupsMetadataValueDelegate implements ValueCodeGenerator.Delegate {
|
||||
|
||||
@Override
|
||||
public @Nullable CodeBlock generateCode(ValueCodeGenerator valueCodeGenerator, Object value) {
|
||||
if (value instanceof DefaultRegistration registration) {
|
||||
return generateRegistrationCode(valueCodeGenerator, registration);
|
||||
}
|
||||
if (value instanceof GroupsMetadata groupsMetadata) {
|
||||
return generateGroupsMetadataCode(valueCodeGenerator, groupsMetadata);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public CodeBlock generateRegistrationCode(ValueCodeGenerator
|
||||
valueCodeGenerator, DefaultRegistration value) {
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
code.add("new $T($S, $L, $L)", DefaultRegistration.class, value.name(),
|
||||
valueCodeGenerator.generateCode(value.clientType()),
|
||||
!value.httpServiceTypeNames().isEmpty() ?
|
||||
valueCodeGenerator.generateCode(value.httpServiceTypeNames()) :
|
||||
CodeBlock.of("new $T()", LinkedHashSet.class));
|
||||
return code.build();
|
||||
}
|
||||
|
||||
private CodeBlock generateGroupsMetadataCode(ValueCodeGenerator valueCodeGenerator, GroupsMetadata groupsMetadata) {
|
||||
Collection<DefaultRegistration> registrations = groupsMetadata.registrations()
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
if (valueCodeGenerator.getGeneratedMethods() != null) {
|
||||
return valueCodeGenerator.getGeneratedMethods().add("getGroupsMetadata", method -> method
|
||||
.addJavadoc("Create the {@link $T}.", GroupsMetadata.class)
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
|
||||
.returns(GroupsMetadata.class)
|
||||
.addCode(generateGroupsMetadataMethod(valueCodeGenerator, registrations))).toMethodReference().toInvokeCodeBlock(ArgumentCodeGenerator.none());
|
||||
}
|
||||
else {
|
||||
return CodeBlock.of("new $T($L)", GroupsMetadata.class, valueCodeGenerator.generateCode(registrations));
|
||||
}
|
||||
}
|
||||
|
||||
private CodeBlock generateGroupsMetadataMethod(
|
||||
ValueCodeGenerator valueCodeGenerator, Collection<DefaultRegistration> registrations) {
|
||||
|
||||
CodeBlock.Builder code = CodeBlock.builder();
|
||||
String registrationsVariable = "registrations";
|
||||
code.addStatement("$T<$T> $L = new $T<>()", List.class, DefaultRegistration.class,
|
||||
registrationsVariable, ArrayList.class);
|
||||
registrations.forEach(registration ->
|
||||
code.addStatement("$L.add($L)", registrationsVariable,
|
||||
valueCodeGenerator.generateCode(registration))
|
||||
);
|
||||
code.addStatement("return new $T($L)", GroupsMetadata.class, registrationsVariable);
|
||||
return code.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.web.service.registry;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedMethod;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCode;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;
|
||||
import org.springframework.beans.factory.support.InstanceSupplier;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
|
||||
import static org.springframework.web.service.registry.AbstractHttpServiceRegistrar.HTTP_SERVICE_GROUP_NAME_ATTRIBUTE;
|
||||
import static org.springframework.web.service.registry.AbstractHttpServiceRegistrar.HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME;
|
||||
|
||||
/**
|
||||
* {@link BeanRegistrationAotProcessor} for HTTP service proxy support.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see AbstractHttpServiceRegistrar
|
||||
*/
|
||||
final class HttpServiceProxyBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
|
||||
|
||||
@Override
|
||||
public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||
Object value = registeredBean.getMergedBeanDefinition().getAttribute(HTTP_SERVICE_GROUP_NAME_ATTRIBUTE);
|
||||
if (value instanceof String groupName) {
|
||||
return BeanRegistrationAotContribution.withCustomCodeFragments(codeFragments ->
|
||||
new HttpServiceProxyRegistrationCodeFragments(codeFragments, groupName, registeredBean.getBeanClass()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class HttpServiceProxyRegistrationCodeFragments extends BeanRegistrationCodeFragmentsDecorator {
|
||||
|
||||
private static final String REGISTERED_BEAN_PARAMETER = "registeredBean";
|
||||
|
||||
private final String groupName;
|
||||
|
||||
private final Class<?> clientType;
|
||||
|
||||
HttpServiceProxyRegistrationCodeFragments(BeanRegistrationCodeFragments delegate,
|
||||
String groupName, Class<?> clientType) {
|
||||
super(delegate);
|
||||
this.groupName = groupName;
|
||||
this.clientType = clientType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassName getTarget(RegisteredBean registeredBean) {
|
||||
return ClassName.get(registeredBean.getBeanClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeBlock generateInstanceSupplierCode(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {
|
||||
GeneratedMethod generatedMethod = beanRegistrationCode.getMethods()
|
||||
.add("getHttpServiceProxy", method -> {
|
||||
method.addJavadoc("Create the HTTP service proxy for {@link $T} and group {@code $L}.",
|
||||
this.clientType, this.groupName);
|
||||
method.addModifiers(Modifier.PRIVATE, Modifier.STATIC);
|
||||
method.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER);
|
||||
method.returns(Object.class);
|
||||
method.addStatement("return $L.getBeanFactory().getBean($S, $T.class).getClient($S, $T.class)",
|
||||
REGISTERED_BEAN_PARAMETER, HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME,
|
||||
HttpServiceProxyRegistry.class, this.groupName, this.clientType);
|
||||
});
|
||||
return CodeBlock.of("$T.of($L)", InstanceSupplier.class, generatedMethod.toMethodReference().toCodeBlock());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -6,4 +6,8 @@ org.springframework.http.converter.json.ProblemDetailRuntimeHints,\
|
|||
org.springframework.web.util.WebUtilRuntimeHints
|
||||
|
||||
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
|
||||
org.springframework.web.service.annotation.HttpExchangeBeanRegistrationAotProcessor
|
||||
org.springframework.web.service.annotation.HttpExchangeBeanRegistrationAotProcessor,\
|
||||
org.springframework.web.service.registry.HttpServiceProxyBeanRegistrationAotProcessor
|
||||
|
||||
org.springframework.aot.generate.ValueCodeGenerator$Delegate=\
|
||||
org.springframework.web.service.registry.GroupsMetadataValueDelegate
|
|
@ -21,20 +21,32 @@ import java.util.LinkedHashMap;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.aot.ApplicationContextAotGenerator;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.test.tools.CompileWithForkedClassLoader;
|
||||
import org.springframework.core.test.tools.Compiled;
|
||||
import org.springframework.core.test.tools.TestCompiler;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.web.service.registry.HttpServiceGroup.ClientType;
|
||||
import org.springframework.web.service.registry.echo.EchoA;
|
||||
import org.springframework.web.service.registry.echo.EchoB;
|
||||
import org.springframework.web.service.registry.greeting.GreetingA;
|
||||
import org.springframework.web.service.registry.greeting.GreetingB;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotationHttpServiceRegistrar}.
|
||||
* Tests for {@link AnnotationHttpServiceRegistrar}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class AnnotationHttpServiceRegistrarTests {
|
||||
|
||||
|
@ -54,6 +66,19 @@ public class AnnotationHttpServiceRegistrarTests {
|
|||
assertGroups(StubGroup.ofListing(ECHO_GROUP, EchoA.class, EchoB.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@CompileWithForkedClassLoader
|
||||
void basicListingWithAot() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean(ListingConfig.class);
|
||||
compile(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
HttpServiceProxyRegistry registry = freshApplicationContext.getBean(HttpServiceProxyRegistry.class);
|
||||
assertThat(registry.getGroupNames()).containsOnly(ECHO_GROUP);
|
||||
assertThat(registry.getClientTypesInGroup(ECHO_GROUP)).containsOnly(EchoA.class, EchoB.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicScan() {
|
||||
doRegister(ScanConfig.class);
|
||||
|
@ -62,6 +87,20 @@ public class AnnotationHttpServiceRegistrarTests {
|
|||
StubGroup.ofPackageClasses(GREETING_GROUP, GreetingA.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@CompileWithForkedClassLoader
|
||||
void basicScanWithAot() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean(ScanConfig.class);
|
||||
compile(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
HttpServiceProxyRegistry registry = freshApplicationContext.getBean(HttpServiceProxyRegistry.class);
|
||||
assertThat(registry.getGroupNames()).containsOnly(ECHO_GROUP, GREETING_GROUP);
|
||||
assertThat(registry.getClientTypesInGroup(ECHO_GROUP)).containsOnly(EchoA.class, EchoB.class);
|
||||
assertThat(registry.getClientTypesInGroup(GREETING_GROUP)).containsOnly(GreetingA.class, GreetingB.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientType() {
|
||||
doRegister(ClientTypeConfig.class);
|
||||
|
@ -75,6 +114,25 @@ public class AnnotationHttpServiceRegistrarTests {
|
|||
this.registrar.registerHttpServices(this.groupRegistry, metadata);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void compile(GenericApplicationContext applicationContext,
|
||||
BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) {
|
||||
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
|
||||
TestGenerationContext generationContext = new TestGenerationContext();
|
||||
generator.processAheadOfTime(applicationContext, generationContext);
|
||||
generationContext.writeGeneratedContent();
|
||||
TestCompiler.forSystem().with(generationContext).compile(compiled ->
|
||||
result.accept(compiled.getInstance(ApplicationContextInitializer.class), compiled));
|
||||
}
|
||||
|
||||
private GenericApplicationContext toFreshApplicationContext(
|
||||
ApplicationContextInitializer<GenericApplicationContext> initializer) {
|
||||
GenericApplicationContext freshApplicationContext = new GenericApplicationContext();
|
||||
initializer.initialize(freshApplicationContext);
|
||||
freshApplicationContext.refresh();
|
||||
return freshApplicationContext;
|
||||
}
|
||||
|
||||
private void assertGroups(StubGroup... expectedGroups) {
|
||||
Map<String, StubGroup> groupMap = this.groupRegistry.groupMap();
|
||||
assertThat(groupMap.size()).isEqualTo(expectedGroups.length);
|
||||
|
@ -88,18 +146,18 @@ public class AnnotationHttpServiceRegistrarTests {
|
|||
}
|
||||
|
||||
|
||||
@ImportHttpServices(group = ECHO_GROUP, types = {EchoA.class, EchoB.class})
|
||||
private static class ListingConfig {
|
||||
@ImportHttpServices(group = ECHO_GROUP, types = { EchoA.class, EchoB.class })
|
||||
static class ListingConfig {
|
||||
}
|
||||
|
||||
@ImportHttpServices(group = ECHO_GROUP, basePackageClasses = {EchoA.class})
|
||||
@ImportHttpServices(group = GREETING_GROUP, basePackageClasses = {GreetingA.class})
|
||||
private static class ScanConfig {
|
||||
@ImportHttpServices(group = ECHO_GROUP, basePackageClasses = { EchoA.class })
|
||||
@ImportHttpServices(group = GREETING_GROUP, basePackageClasses = { GreetingA.class })
|
||||
static class ScanConfig {
|
||||
}
|
||||
|
||||
@ImportHttpServices(clientType = ClientType.WEB_CLIENT, group = ECHO_GROUP, types = {EchoA.class})
|
||||
@ImportHttpServices(clientType = ClientType.WEB_CLIENT, group = GREETING_GROUP, types = {GreetingA.class})
|
||||
private static class ClientTypeConfig {
|
||||
@ImportHttpServices(clientType = ClientType.WEB_CLIENT, group = ECHO_GROUP, types = { EchoA.class })
|
||||
@ImportHttpServices(clientType = ClientType.WEB_CLIENT, group = GREETING_GROUP, types = { GreetingA.class })
|
||||
static class ClientTypeConfig {
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.web.service.registry;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedClass;
|
||||
import org.springframework.aot.generate.ValueCodeGenerator;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.beans.factory.aot.BeanDefinitionPropertyValueCodeGeneratorDelegates;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.DeferredTypeBuilder;
|
||||
import org.springframework.core.test.tools.CompileWithForkedClassLoader;
|
||||
import org.springframework.core.test.tools.Compiled;
|
||||
import org.springframework.core.test.tools.TestCompiler;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.service.registry.GroupsMetadata.DefaultRegistration;
|
||||
import org.springframework.web.service.registry.GroupsMetadata.Registration;
|
||||
import org.springframework.web.service.registry.HttpServiceGroup.ClientType;
|
||||
import org.springframework.web.service.registry.echo.EchoA;
|
||||
import org.springframework.web.service.registry.echo.EchoB;
|
||||
import org.springframework.web.service.registry.greeting.GreetingA;
|
||||
import org.springframework.web.service.registry.greeting.GreetingB;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link GroupsMetadataValueDelegate}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@CompileWithForkedClassLoader
|
||||
class GroupsMetadataValueDelegateTests {
|
||||
|
||||
@Test
|
||||
void generateRegistrationWithOnlyName() {
|
||||
DefaultRegistration registration = new DefaultRegistration("test", ClientType.UNSPECIFIED);
|
||||
compile(registration, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(Registration.class, hasRegistration("test", ClientType.UNSPECIFIED)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateRegistrationWitNoHttpServiceTypeName() {
|
||||
DefaultRegistration registration = new DefaultRegistration("test", ClientType.REST_CLIENT);
|
||||
compile(registration, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(Registration.class, hasRegistration("test", ClientType.REST_CLIENT)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateRegistrationWitOneHttpServiceTypeName() {
|
||||
DefaultRegistration registration = new DefaultRegistration("test", ClientType.WEB_CLIENT,
|
||||
httpServiceTypeNames("com.example.MyClient"));
|
||||
compile(registration, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(Registration.class, hasRegistration(
|
||||
"test", ClientType.WEB_CLIENT, "com.example.MyClient")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateRegistrationWitHttpServiceTypeNames() {
|
||||
DefaultRegistration registration = new DefaultRegistration("test", ClientType.WEB_CLIENT,
|
||||
httpServiceTypeNames("com.example.MyClient", "com.example.another.TestClient"));
|
||||
compile(registration, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(Registration.class, hasRegistration(
|
||||
"test", ClientType.WEB_CLIENT, "com.example.MyClient", "com.example.another.TestClient")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateGroupsMetadataEmpty() {
|
||||
compile(new GroupsMetadata(), (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(GroupsMetadata.class, metadata -> assertThat(metadata.groups()).isEmpty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateGroupsMetadataSingleGroup() {
|
||||
GroupsMetadata groupsMetadata = new GroupsMetadata();
|
||||
groupsMetadata.getOrCreateGroup("test-group", ClientType.REST_CLIENT).httpServiceTypeNames().add(EchoA.class.getName());
|
||||
compile(groupsMetadata, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(GroupsMetadata.class, metadata -> assertThat(metadata.groups())
|
||||
.singleElement().satisfies(hasHttpServiceGroup("test-group", ClientType.REST_CLIENT, EchoA.class))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateGroupsMetadataMultipleGroupsSimple() {
|
||||
GroupsMetadata groupsMetadata = new GroupsMetadata();
|
||||
groupsMetadata.getOrCreateGroup("test-group", ClientType.UNSPECIFIED).httpServiceTypeNames()
|
||||
.addAll(List.of(EchoA.class.getName(), EchoB.class.getName()));
|
||||
groupsMetadata.getOrCreateGroup("another-group", ClientType.WEB_CLIENT).httpServiceTypeNames()
|
||||
.addAll(List.of(GreetingA.class.getName(), GreetingB.class.getName()));
|
||||
|
||||
Function<GeneratedClass, ValueCodeGenerator> valueCodeGeneratorFactory = generatedClass ->
|
||||
ValueCodeGenerator.withDefaults().add(List.of(new GroupsMetadataValueDelegate()));
|
||||
compile(valueCodeGeneratorFactory, groupsMetadata, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(GroupsMetadata.class, metadata -> assertThat(metadata.groups())
|
||||
.satisfiesOnlyOnce(hasHttpServiceGroup("test-group", ClientType.REST_CLIENT, EchoA.class, EchoB.class))
|
||||
.satisfiesOnlyOnce(hasHttpServiceGroup("another-group", ClientType.WEB_CLIENT, GreetingA.class, GreetingB.class))
|
||||
.hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateGroupsMetadataMultipleGroups() {
|
||||
GroupsMetadata groupsMetadata = new GroupsMetadata();
|
||||
groupsMetadata.getOrCreateGroup("test-group", ClientType.UNSPECIFIED).httpServiceTypeNames()
|
||||
.addAll(List.of(EchoA.class.getName(), EchoB.class.getName()));
|
||||
groupsMetadata.getOrCreateGroup("another-group", ClientType.WEB_CLIENT).httpServiceTypeNames()
|
||||
.addAll(List.of(GreetingA.class.getName(), GreetingB.class.getName()));
|
||||
|
||||
compile(groupsMetadata, (instance, compiled) -> assertThat(instance)
|
||||
.isInstanceOfSatisfying(GroupsMetadata.class, metadata -> assertThat(metadata.groups())
|
||||
.satisfiesOnlyOnce(hasHttpServiceGroup("test-group", ClientType.REST_CLIENT, EchoA.class, EchoB.class))
|
||||
.satisfiesOnlyOnce(hasHttpServiceGroup("another-group", ClientType.WEB_CLIENT, GreetingA.class, GreetingB.class))
|
||||
.hasSize(2)));
|
||||
}
|
||||
|
||||
private LinkedHashSet<String> httpServiceTypeNames(String... names) {
|
||||
return new LinkedHashSet<>(Arrays.asList(names));
|
||||
}
|
||||
|
||||
private Consumer<Registration> hasRegistration(String name, ClientType clientType, String... httpServiceTypeNames) {
|
||||
return registration -> {
|
||||
assertThat(registration.name()).isEqualTo(name);
|
||||
assertThat(registration.clientType()).isEqualTo(clientType);
|
||||
assertThat(registration.httpServiceTypeNames()).isInstanceOf(LinkedHashSet.class)
|
||||
.containsExactly(httpServiceTypeNames);
|
||||
};
|
||||
}
|
||||
|
||||
private Consumer<HttpServiceGroup> hasHttpServiceGroup(String name, ClientType clientType, Class<?>... httpServiceTypeNames) {
|
||||
return group -> {
|
||||
assertThat(group.name()).isEqualTo(name);
|
||||
assertThat(group.clientType()).isEqualTo(clientType);
|
||||
assertThat(group.httpServiceTypes()).containsOnly(httpServiceTypeNames);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void compile(Function<GeneratedClass, ValueCodeGenerator> valueCodeGeneratorFactory,
|
||||
Object value, BiConsumer<Object, Compiled> result) {
|
||||
TestGenerationContext generationContext = new TestGenerationContext();
|
||||
DeferredTypeBuilder typeBuilder = new DeferredTypeBuilder();
|
||||
GeneratedClass generatedClass = generationContext.getGeneratedClasses().addForFeatureComponent("TestCode", GroupsMetadata.class, typeBuilder);
|
||||
ValueCodeGenerator valueCodeGenerator = valueCodeGeneratorFactory.apply(generatedClass);
|
||||
CodeBlock generatedCode = valueCodeGenerator.generateCode(value);
|
||||
typeBuilder.set(type -> {
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
type.addMethod(MethodSpec.methodBuilder("get").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.returns(Object.class).addStatement("return $L", generatedCode).build());
|
||||
});
|
||||
generationContext.writeGeneratedContent();
|
||||
TestCompiler.forSystem().with(generationContext).compile(compiled ->
|
||||
result.accept(getGeneratedCodeReturnValue(compiled, generatedClass), compiled));
|
||||
}
|
||||
|
||||
private void compile(Object value, BiConsumer<Object, Compiled> result) {
|
||||
compile(this::createValueCodeGenerator, value, result);
|
||||
}
|
||||
|
||||
private ValueCodeGenerator createValueCodeGenerator(GeneratedClass generatedClass) {
|
||||
return BeanDefinitionPropertyValueCodeGeneratorDelegates.createValueCodeGenerator(
|
||||
generatedClass.getMethods(), List.of(new GroupsMetadataValueDelegate()));
|
||||
}
|
||||
|
||||
|
||||
private static Object getGeneratedCodeReturnValue(Compiled compiled, GeneratedClass generatedClass) {
|
||||
try {
|
||||
Object instance = compiled.getInstance(Object.class, generatedClass.getName().reflectionName());
|
||||
Method get = ReflectionUtils.findMethod(instance.getClass(), "get");
|
||||
return get.invoke(null);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to invoke generated code '%s':".formatted(generatedClass.getName()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.web.service.registry;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
import org.springframework.beans.factory.aot.AotServices;
|
||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RegisteredBean;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.aot.ApplicationContextAotGenerator;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.test.tools.CompileWithForkedClassLoader;
|
||||
import org.springframework.core.test.tools.Compiled;
|
||||
import org.springframework.core.test.tools.TestCompiler;
|
||||
import org.springframework.web.service.registry.HttpServiceGroup.ClientType;
|
||||
import org.springframework.web.service.registry.echo.EchoA;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpServiceProxyBeanRegistrationAotProcessor}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class HttpServiceProxyRegistrationAotProcessorTests {
|
||||
|
||||
@Test
|
||||
void httpServiceProxyBeanRegistrationAotProcessorIsRegistered() {
|
||||
assertThat(AotServices.factories().load(BeanRegistrationAotProcessor.class))
|
||||
.anyMatch(HttpServiceProxyBeanRegistrationAotProcessor.class::isInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAotContributionWhenBeanHasNoGroup() {
|
||||
assertThat(hasContribution(new RootBeanDefinition(EchoA.class))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAotContributionWhenBeanHasGroup() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(EchoA.class);
|
||||
beanDefinition.setAttribute(AbstractHttpServiceRegistrar.HTTP_SERVICE_GROUP_NAME_ATTRIBUTE, "echo");
|
||||
assertThat(hasContribution(beanDefinition)).isTrue();
|
||||
}
|
||||
|
||||
private boolean hasContribution(RootBeanDefinition beanDefinition) {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||
RegisteredBean registeredBean = RegisteredBean.of(beanFactory, "test");
|
||||
return new HttpServiceProxyBeanRegistrationAotProcessor().processAheadOfTime(registeredBean) != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
@CompileWithForkedClassLoader
|
||||
void processHttpServiceProxyWhenSingleClientType() {
|
||||
GroupsMetadata groupsMetadata = new GroupsMetadata();
|
||||
groupsMetadata.getOrCreateGroup("echo", ClientType.UNSPECIFIED)
|
||||
.httpServiceTypeNames().add(EchoA.class.getName());
|
||||
DefaultListableBeanFactory beanFactory = prepareBeanFactory(groupsMetadata);
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(EchoA.class);
|
||||
beanDefinition.setAttribute(AbstractHttpServiceRegistrar.HTTP_SERVICE_GROUP_NAME_ATTRIBUTE, "echo");
|
||||
beanFactory.registerBeanDefinition("echoA", beanDefinition);
|
||||
compile(beanFactory, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
HttpServiceProxyRegistry registry = freshApplicationContext.getBean(HttpServiceProxyRegistry.class);
|
||||
assertThat(registry.getClient("echo", EchoA.class)).isSameAs(freshApplicationContext.getBean(EchoA.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@CompileWithForkedClassLoader
|
||||
void processHttpServiceProxyWhenSameClientTypeInDifferentGroups() {
|
||||
GroupsMetadata groupsMetadata = new GroupsMetadata();
|
||||
groupsMetadata.getOrCreateGroup("echo", ClientType.UNSPECIFIED)
|
||||
.httpServiceTypeNames().add(EchoA.class.getName());
|
||||
groupsMetadata.getOrCreateGroup("echo2", ClientType.UNSPECIFIED)
|
||||
.httpServiceTypeNames().add(EchoA.class.getName());
|
||||
DefaultListableBeanFactory beanFactory = prepareBeanFactory(groupsMetadata);
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(EchoA.class);
|
||||
beanDefinition.setAttribute(AbstractHttpServiceRegistrar.HTTP_SERVICE_GROUP_NAME_ATTRIBUTE, "echo");
|
||||
beanFactory.registerBeanDefinition("echoA", beanDefinition);
|
||||
RootBeanDefinition beanDefinition2 = new RootBeanDefinition(EchoA.class);
|
||||
beanDefinition2.setAttribute(AbstractHttpServiceRegistrar.HTTP_SERVICE_GROUP_NAME_ATTRIBUTE, "echo2");
|
||||
beanFactory.registerBeanDefinition("echoA2", beanDefinition2);
|
||||
compile(beanFactory, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
HttpServiceProxyRegistry registry = freshApplicationContext.getBean(HttpServiceProxyRegistry.class);
|
||||
assertThat(registry.getClient("echo", EchoA.class)).isSameAs(freshApplicationContext.getBean("echoA", EchoA.class));
|
||||
assertThat(registry.getClient("echo2", EchoA.class)).isSameAs(freshApplicationContext.getBean("echoA2", EchoA.class));
|
||||
});
|
||||
}
|
||||
|
||||
private DefaultListableBeanFactory prepareBeanFactory(GroupsMetadata metadata) {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(HttpServiceProxyRegistryFactoryBean.class);
|
||||
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, metadata);
|
||||
beanFactory.registerBeanDefinition(AbstractHttpServiceRegistrar.HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME, beanDefinition);
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void compile(DefaultListableBeanFactory beanFactory,
|
||||
BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) {
|
||||
ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator();
|
||||
TestGenerationContext generationContext = new TestGenerationContext();
|
||||
generator.processAheadOfTime(new GenericApplicationContext(beanFactory), generationContext);
|
||||
generationContext.writeGeneratedContent();
|
||||
TestCompiler.forSystem().with(generationContext).compile(compiled ->
|
||||
result.accept(compiled.getInstance(ApplicationContextInitializer.class), compiled));
|
||||
}
|
||||
|
||||
private GenericApplicationContext toFreshApplicationContext(
|
||||
ApplicationContextInitializer<GenericApplicationContext> initializer) {
|
||||
GenericApplicationContext freshApplicationContext = new GenericApplicationContext();
|
||||
initializer.initialize(freshApplicationContext);
|
||||
freshApplicationContext.refresh();
|
||||
return freshApplicationContext;
|
||||
}
|
||||
|
||||
}
|
|
@ -149,7 +149,7 @@ public class HttpServiceRegistrarTests {
|
|||
}
|
||||
|
||||
private Map<String, HttpServiceGroup> groupMap() {
|
||||
BeanDefinition beanDef = this.beanDefRegistry.getBeanDefinition("httpServiceProxyRegistry");
|
||||
BeanDefinition beanDef = this.beanDefRegistry.getBeanDefinition(AbstractHttpServiceRegistrar.HTTP_SERVICE_PROXY_REGISTRY_BEAN_NAME);
|
||||
assertThat(beanDef.getBeanClassName()).isEqualTo(HttpServiceProxyRegistryFactoryBean.class.getName());
|
||||
|
||||
ConstructorArgumentValues args = beanDef.getConstructorArgumentValues();
|
||||
|
|
Loading…
Reference in New Issue