Implement CoroutineStubFactory
Signed-off-by: Alexey Genus <genus.alexey@gmail.com>
This commit is contained in:
@@ -93,6 +93,11 @@
|
||||
<groupId>com.google.api.grpc</groupId>
|
||||
<artifactId>proto-google-common-protos</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-kotlin-stub</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.salesforce.servicelibs</groupId>
|
||||
<artifactId>reactor-grpc-stub</artifactId>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 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.grpc.client;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.kotlin.AbstractCoroutineStub;
|
||||
|
||||
public class CoroutineStubFactory implements StubFactory<AbstractCoroutineStub<?>> {
|
||||
|
||||
@Override
|
||||
public AbstractCoroutineStub<?> create(Supplier<ManagedChannel> channel,
|
||||
Class<? extends AbstractCoroutineStub<?>> type) {
|
||||
try {
|
||||
return type.getConstructor(Channel.class, CallOptions.class)
|
||||
.newInstance(channel.get(), CallOptions.DEFAULT);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to create stub", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean supports(Class<?> type) {
|
||||
return AbstractCoroutineStub.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
* Copyright 2024-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.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.grpc.client.GrpcClientFactoryTests.MyProto.MyStub;
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ManagedChannel;
|
||||
import io.grpc.kotlin.AbstractCoroutineStub;
|
||||
import io.grpc.stub.AbstractStub;
|
||||
|
||||
public class GrpcClientFactoryTests {
|
||||
@@ -88,6 +89,16 @@ public class GrpcClientFactoryTests {
|
||||
assertThat(factory.getClient("local", OtherStub.class, null)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCoroutineStubFactory() {
|
||||
context.registerBean(CoroutineStubFactory.class, CoroutineStubFactory::new);
|
||||
GrpcClientFactory.register(context,
|
||||
GrpcClientRegistrationSpec.of("local")
|
||||
.factory(CoroutineStubFactory.class)
|
||||
.types(MyCoroutineStub.class));
|
||||
assertThat(factory.getClient("local", MyCoroutineStub.class, null)).isNotNull();
|
||||
}
|
||||
|
||||
static class OtherStubFactory implements StubFactory<OtherStub> {
|
||||
|
||||
@Override
|
||||
@@ -135,6 +146,19 @@ public class GrpcClientFactoryTests {
|
||||
|
||||
}
|
||||
|
||||
public static class MyCoroutineStub extends AbstractCoroutineStub<MyCoroutineStub> {
|
||||
|
||||
public MyCoroutineStub(Channel channel, CallOptions callOptions) {
|
||||
super(channel, callOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MyCoroutineStub build(Channel channel, CallOptions callOptions) {
|
||||
return new MyCoroutineStub(channel, callOptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class MyConfiguration {
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
<properties>
|
||||
<grpc.version>1.72.0</grpc.version>
|
||||
<grpc-kotlin.version>1.4.3</grpc-kotlin.version>
|
||||
<protobuf-java.version>4.30.2</protobuf-java.version>
|
||||
<google-common-protos.version>2.54.1</google-common-protos.version>
|
||||
<micrometer.version>1.13.6</micrometer.version>
|
||||
@@ -101,6 +102,11 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-kotlin-stub</artifactId>
|
||||
<version>${grpc-kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-bom</artifactId>
|
||||
|
||||
@@ -141,6 +141,11 @@
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-kotlin-stub</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
|
||||
@@ -18,13 +18,16 @@ package org.springframework.grpc.autoconfigure.client;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.grpc.autoconfigure.common.codec.GrpcCodecConfiguration;
|
||||
import org.springframework.grpc.client.ChannelCredentialsProvider;
|
||||
import org.springframework.grpc.client.CoroutineStubFactory;
|
||||
import org.springframework.grpc.client.GrpcChannelBuilderCustomizer;
|
||||
|
||||
import io.grpc.CompressorRegistry;
|
||||
@@ -71,4 +74,16 @@ public class GrpcClientAutoConfiguration {
|
||||
return new ChannelBuilderCustomizers(customizers.orderedStream().toList());
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "io.grpc.kotlin.AbstractCoroutineStub")
|
||||
static class GrpcClientCoroutineStubConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CoroutineStubFactory coroutineStubFactory() {
|
||||
return new CoroutineStubFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import io.grpc.Codec;
|
||||
import io.grpc.CompressorRegistry;
|
||||
import io.grpc.DecompressorRegistry;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.kotlin.AbstractCoroutineStub;
|
||||
import io.grpc.netty.NettyChannelBuilder;
|
||||
import io.grpc.stub.AbstractStub;
|
||||
|
||||
@@ -73,6 +74,14 @@ class GrpcClientAutoConfigurationTests {
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenGrpcKotlinIsNotOnClasspathThenAutoConfigurationIsSkipped() {
|
||||
this.contextRunner()
|
||||
.withClassLoader(new FilteredClassLoader(AbstractCoroutineStub.class))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(GrpcClientAutoConfiguration.GrpcClientCoroutineStubConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenClientEnabledPropertySetFalseThenAutoConfigurationIsSkipped() {
|
||||
this.contextRunner()
|
||||
|
||||
Reference in New Issue
Block a user