diff --git a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc index 21a9552395d..0417613f496 100644 --- a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc +++ b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc @@ -1195,46 +1195,6 @@ One way to declare HTTP Service groups is via `@ImportHttpServices` annotations <1> Manually list interfaces for group "echo" <2> Detect interfaces for group "greeting" under a base package -The above lets you declare HTTP Services and groups. As an alternative, you can also -annotate HTTP interfaces as follows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - @HttpServiceClient("echo") - public interface EchoServiceA { - // ... - } - - @HttpServiceClient("echo") - public interface EchoServiceB { - // ... - } ----- - -The above requires a dedicated import registrar as follows: - -[source,java,indent=0,subs="verbatim,quotes"] ----- - public class MyClientHttpServiceRegistrar implements AbstractClientHttpServiceRegistrar { // <1> - - @Override - protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) { - findAndRegisterHttpServiceClients(groupRegistry, List.of("org.example.echo")); // <2> - } - } - - @Configuration - @Import(MyClientHttpServiceRegistrar.class) // <3> - public class ClientConfig { - } ----- -<1> Extend dedicated `AbstractClientHttpServiceRegistrar` -<2> Specify base packages where to find client interfaces -<3> Import the registrar - -TIP: `@HttpServiceClient` interfaces are excluded from `@ImportHttpServices` scans, so there -is no overlap with scans for client interfaces when pointed at the same package. - It is also possible to declare groups programmatically by creating an HTTP Service registrar and then importing it: diff --git a/spring-web/src/main/java/org/springframework/web/service/registry/AbstractClientHttpServiceRegistrar.java b/spring-web/src/main/java/org/springframework/web/service/registry/AbstractClientHttpServiceRegistrar.java deleted file mode 100644 index e3fa444cc30..00000000000 --- a/spring-web/src/main/java/org/springframework/web/service/registry/AbstractClientHttpServiceRegistrar.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2002-present 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.List; - -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; -import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.core.type.AnnotationMetadata; - -/** - * Base class for an HTTP Service registrar that detects - * {@link HttpServiceClient @HttpServiceClient} annotated interfaces and - * registers them. - * - *

Subclasses need to implement - * {@link #registerHttpServices(GroupRegistry, AnnotationMetadata)} and invoke - * {@link #findAndRegisterHttpServiceClients(GroupRegistry, List)} with the - * list of base packages to scan. - * - * @author Rossen Stoyanchev - * @since 7.0 - */ -public abstract class AbstractClientHttpServiceRegistrar extends AbstractHttpServiceRegistrar { - - /** - * Find all HTTP Services under the given base packages that also have an - * {@link HttpServiceClient @HttpServiceClient} annotation, and register them - * in the group specified on the annotation. - * @param registry the registry from {@link #registerHttpServices(GroupRegistry, AnnotationMetadata)} - * @param basePackages the base packages to scan - */ - protected void findAndRegisterHttpServiceClients(GroupRegistry registry, List basePackages) { - basePackages.stream() - .flatMap(this::findHttpServices) - .filter(definition -> definition instanceof AnnotatedBeanDefinition) - .map(definition -> (AnnotatedBeanDefinition) definition) - .filter(definition -> definition.getMetadata().hasAnnotation(HttpServiceClient.class.getName())) - .filter(definition -> definition.getBeanClassName() != null) - .forEach(definition -> { - MergedAnnotations annotations = definition.getMetadata().getAnnotations(); - String group = annotations.get(HttpServiceClient.class).getString("group"); - registry.forGroup(group).registerTypeNames(definition.getBeanClassName()); - }); - } - -} diff --git a/spring-web/src/main/java/org/springframework/web/service/registry/AbstractHttpServiceRegistrar.java b/spring-web/src/main/java/org/springframework/web/service/registry/AbstractHttpServiceRegistrar.java index ea8af343994..6eb81fe86d6 100644 --- a/spring-web/src/main/java/org/springframework/web/service/registry/AbstractHttpServiceRegistrar.java +++ b/spring-web/src/main/java/org/springframework/web/service/registry/AbstractHttpServiceRegistrar.java @@ -211,7 +211,7 @@ public abstract class AbstractHttpServiceRegistrar implements * @param basePackage the names of packages to look under * @return match bean definitions */ - protected Stream findHttpServices(String basePackage) { + private Stream findHttpServices(String basePackage) { if (this.scanner == null) { Assert.state(this.environment != null, "Environment has not been set"); Assert.state(this.resourceLoader != null, "ResourceLoader has not been set"); @@ -267,9 +267,6 @@ public abstract class AbstractHttpServiceRegistrar implements /** * Detect HTTP Service types in the given packages, looking for * interfaces with type or method {@link HttpExchange} annotations. - *

The performed scan, however, filters out any interfaces - * annotated with {@link HttpServiceClient} that are instead supported - * by {@link AbstractClientHttpServiceRegistrar}. */ GroupSpec detectInBasePackages(Class... packageClasses); @@ -326,19 +323,11 @@ public abstract class AbstractHttpServiceRegistrar implements private void detectInBasePackage(String packageName) { findHttpServices(packageName) - .filter(DefaultGroupSpec::isNotHttpServiceClientAnnotated) .map(BeanDefinition::getBeanClassName) .filter(Objects::nonNull) .forEach(this::registerServiceTypeName); } - private static boolean isNotHttpServiceClientAnnotated(BeanDefinition defintion) { - if (defintion instanceof AnnotatedBeanDefinition abd) { - return !abd.getMetadata().hasAnnotation(HttpServiceClient.class.getName()); - } - return true; - } - private void registerServiceTypeName(String httpServiceTypeName) { this.registration.httpServiceTypeNames().add(httpServiceTypeName); } diff --git a/spring-web/src/main/java/org/springframework/web/service/registry/HttpServiceClient.java b/spring-web/src/main/java/org/springframework/web/service/registry/HttpServiceClient.java deleted file mode 100644 index 03c285b7629..00000000000 --- a/spring-web/src/main/java/org/springframework/web/service/registry/HttpServiceClient.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2002-present 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.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.core.annotation.AliasFor; - -/** - * Annotation to mark an HTTP Service interface as a candidate client proxy creation. - * Supported through the import of an {@link AbstractClientHttpServiceRegistrar}. - * - * @author Rossen Stoyanchev - * @since 7.0 - * @see AbstractClientHttpServiceRegistrar - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface HttpServiceClient { - - /** - * An alias for {@link #group()}. - */ - @AliasFor("group") - String value() default HttpServiceGroup.DEFAULT_GROUP_NAME; - - /** - * The name of the HTTP Service group for this client. - *

By default, this is {@link HttpServiceGroup#DEFAULT_GROUP_NAME}. - */ - @AliasFor("value") - String group() default HttpServiceGroup.DEFAULT_GROUP_NAME; - -} diff --git a/spring-web/src/main/java/org/springframework/web/service/registry/ImportHttpServices.java b/spring-web/src/main/java/org/springframework/web/service/registry/ImportHttpServices.java index b1abea0323e..03d47f36c02 100644 --- a/spring-web/src/main/java/org/springframework/web/service/registry/ImportHttpServices.java +++ b/spring-web/src/main/java/org/springframework/web/service/registry/ImportHttpServices.java @@ -78,9 +78,6 @@ public @interface ImportHttpServices { /** * Detect HTTP Services in the packages of the specified classes, looking * for interfaces with type or method {@link HttpExchange} annotations. - *

The performed scan, however, filters out interfaces annotated with - * {@link HttpServiceClient} that are instead supported by - * {@link AbstractClientHttpServiceRegistrar}. */ Class[] basePackageClasses() default {}; diff --git a/spring-web/src/test/java/org/springframework/web/service/registry/ClientHttpServiceRegistrarTests.java b/spring-web/src/test/java/org/springframework/web/service/registry/ClientHttpServiceRegistrarTests.java deleted file mode 100644 index 7f737c92501..00000000000 --- a/spring-web/src/test/java/org/springframework/web/service/registry/ClientHttpServiceRegistrarTests.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2002-present 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.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.env.StandardEnvironment; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.web.service.registry.basic.BasicClient; -import org.springframework.web.service.registry.echo.EchoClientA; -import org.springframework.web.service.registry.echo.EchoClientB; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Unit tests for {@link AbstractClientHttpServiceRegistrar}. - * - * @author Rossen Stoyanchev - */ -public class ClientHttpServiceRegistrarTests { - - private final TestGroupRegistry groupRegistry = new TestGroupRegistry(); - - - @Test - void register() { - - List basePackages = List.of( - BasicClient.class.getPackageName(), EchoClientA.class.getPackageName()); - - AbstractClientHttpServiceRegistrar registrar = new AbstractClientHttpServiceRegistrar() { - - @Override - protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata importingClassMetadata) { - findAndRegisterHttpServiceClients(groupRegistry, basePackages); - } - }; - registrar.setEnvironment(new StandardEnvironment()); - registrar.setResourceLoader(new PathMatchingResourcePatternResolver()); - registrar.registerHttpServices(groupRegistry, mock(AnnotationMetadata.class)); - - assertGroups( - TestGroup.ofListing("default", BasicClient.class), - TestGroup.ofListing("echo", EchoClientA.class, EchoClientB.class)); - } - - @Test - void registerWhenNoClientsDoesNotCreateBeans() { - try (AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(NoOpImportConfig.class)) { - assertThat(cxt.getBeanNamesForType(HttpServiceProxyRegistry.class)).isEmpty(); - } - } - - private void assertGroups(TestGroup... expectedGroups) { - Map groupMap = this.groupRegistry.groupMap(); - assertThat(groupMap.size()).isEqualTo(expectedGroups.length); - for (TestGroup expected : expectedGroups) { - TestGroup actual = groupMap.get(expected.name()); - assertThat(actual.httpServiceTypes()).isEqualTo(expected.httpServiceTypes()); - assertThat(actual.clientType()).isEqualTo(expected.clientType()); - assertThat(actual.packageNames()).isEqualTo(expected.packageNames()); - assertThat(actual.packageClasses()).isEqualTo(expected.packageClasses()); - } - } - - - @Configuration(proxyBeanMethods = false) - @Import(NoOpRegistrar.class) - static class NoOpImportConfig { - } - - - static class NoOpRegistrar extends AbstractClientHttpServiceRegistrar { - - @Override - protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) { - } - } - -} diff --git a/spring-web/src/test/java/org/springframework/web/service/registry/basic/BasicClient.java b/spring-web/src/test/java/org/springframework/web/service/registry/basic/BasicClient.java deleted file mode 100644 index 86f49a958f8..00000000000 --- a/spring-web/src/test/java/org/springframework/web/service/registry/basic/BasicClient.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2002-present 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.basic; - -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.service.annotation.GetExchange; -import org.springframework.web.service.registry.HttpServiceClient; - -@HttpServiceClient -public interface BasicClient { - - @GetExchange - String handle(@RequestParam String input); - -} diff --git a/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientA.java b/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientA.java deleted file mode 100644 index 9c25fc5e662..00000000000 --- a/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientA.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2002-present 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.echo; - -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.service.annotation.GetExchange; -import org.springframework.web.service.registry.HttpServiceClient; - -@HttpServiceClient("echo") -public interface EchoClientA { - - @GetExchange - String handle(@RequestParam String input); - -} diff --git a/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientB.java b/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientB.java deleted file mode 100644 index e5b85840959..00000000000 --- a/spring-web/src/test/java/org/springframework/web/service/registry/echo/EchoClientB.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2002-present 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.echo; - -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.service.annotation.GetExchange; -import org.springframework.web.service.registry.HttpServiceClient; - -@HttpServiceClient("echo") -public interface EchoClientB { - - @GetExchange - String handle(@RequestParam String input); - -}