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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user