Skip to content

Commit 7734df3

Browse files
authored
Merge pull request #413 from yidongnan/fix/stub-fallback
Add fallback stubfactory
2 parents 14a05c8 + e2ef1de commit 7734df3

File tree

8 files changed

+333
-22
lines changed

8 files changed

+333
-22
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ buildscript {
99
}
1010
}
1111
ext {
12-
projectVersion = '2.10.0.RELEASE'
12+
projectVersion = '2.10.1-SNAPSHOT'
1313

1414
// https://github.com/grpc/grpc-java/releases
1515
grpcVersion = '1.31.1'

docs/en/versions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Current version.
4848
| Version | spring-boot | gRPC | Date |
4949
|:-------:|:-----------:|:----:| ---: |
5050
| 2.11.0* | 2.3.3 | 1.31.1 | TBA |
51+
| 2.10.1* | 2.3.3 | 1.31.1 | Aug, 2020 |
5152
| 2.10.0 | 2.3.3 | 1.31.1 | Aug, 2020 |
5253
| 2.9.0 | 2.3.1 | 1.30.0 | Jun, 2020 |
5354
| 2.8.0 | 2.2.7 | 1.29.0 | Jun, 2020 |

grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import io.grpc.stub.AbstractStub;
4444
import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
4545
import net.devh.boot.grpc.client.nameresolver.NameResolverRegistration;
46+
import net.devh.boot.grpc.client.stubfactory.FallbackStubFactory;
4647
import net.devh.boot.grpc.client.stubfactory.StubFactory;
4748

4849
/**
@@ -229,14 +230,14 @@ protected <T> T valueForMember(final String name, final Member injectionTarget,
229230

230231
/**
231232
* Creates a stub instance for the specified stub type using the resolved {@link StubFactory}.
232-
*
233+
*
233234
* @param stubClass The stub class that needs to be created.
234235
* @param channel The gRPC channel associated with the created stub, passed as a parameter to the stub factory.
235236
* @throws BeanInstantiationException If the stub couldn't be created, either because the type isn't supported or
236237
* because of a failure in creation.
237238
* @return A newly created gRPC stub.
238239
*/
239-
private AbstractStub<?> createStub(Class<? extends AbstractStub<?>> stubClass, Channel channel) {
240+
private AbstractStub<?> createStub(final Class<? extends AbstractStub<?>> stubClass, final Channel channel) {
240241
final StubFactory factory = getStubFactories().stream()
241242
.filter(stubFactory -> stubFactory.isApplicable(stubClass))
242243
.findFirst()
@@ -245,7 +246,7 @@ private AbstractStub<?> createStub(Class<? extends AbstractStub<?>> stubClass, C
245246

246247
try {
247248
return factory.createStub(stubClass, channel);
248-
} catch (Exception exception) {
249+
} catch (final Exception exception) {
249250
throw new BeanInstantiationException(stubClass, "Failed to create gRPC stub of type " + stubClass.getName(),
250251
exception);
251252
}
@@ -258,8 +259,10 @@ private AbstractStub<?> createStub(Class<? extends AbstractStub<?>> stubClass, C
258259
*/
259260
private List<StubFactory> getStubFactories() {
260261
if (this.stubFactories == null) {
261-
stubFactories = new ArrayList<>(applicationContext.getBeansOfType(StubFactory.class).values());
262+
this.stubFactories = new ArrayList<>(this.applicationContext.getBeansOfType(StubFactory.class).values());
263+
this.stubFactories.add(new FallbackStubFactory());
262264
}
263-
return stubFactories;
265+
return this.stubFactories;
264266
}
267+
265268
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2016-2020 Michael Zhang <[email protected]>
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
18+
package net.devh.boot.grpc.client.stubfactory;
19+
20+
import java.lang.reflect.Constructor;
21+
import java.lang.reflect.Method;
22+
import java.lang.reflect.Modifier;
23+
import java.lang.reflect.Parameter;
24+
25+
import org.springframework.beans.BeanInstantiationException;
26+
27+
import io.grpc.Channel;
28+
import io.grpc.stub.AbstractStub;
29+
30+
/**
31+
* The StubFactory which tries to find a suitable factory method or constructor as a last resort. This factory will
32+
* always be the last one that is attempted.
33+
*
34+
* @author Daniel Theuke ([email protected])
35+
*/
36+
public final class FallbackStubFactory implements StubFactory {
37+
38+
@Override
39+
public boolean isApplicable(final Class<? extends AbstractStub<?>> stubType) {
40+
return true;
41+
}
42+
43+
@Override
44+
public AbstractStub<?> createStub(final Class<? extends AbstractStub<?>> stubType, final Channel channel) {
45+
try {
46+
// Search for public static *Grpc#new*Stub(Channel)
47+
final Class<?> declaringClass = stubType.getDeclaringClass();
48+
if (declaringClass != null) {
49+
for (final Method method : declaringClass.getMethods()) {
50+
final String name = method.getName();
51+
final int modifiers = method.getModifiers();
52+
final Parameter[] parameters = method.getParameters();
53+
if (name.startsWith("new") && name.endsWith("Stub")
54+
&& Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
55+
&& method.getReturnType().isAssignableFrom(stubType)
56+
&& parameters.length == 1
57+
&& Channel.class.equals(parameters[0].getType())) {
58+
return AbstractStub.class.cast(method.invoke(null, channel));
59+
}
60+
}
61+
}
62+
63+
// Search for a public constructor *Stub(Channel)
64+
final Constructor<? extends AbstractStub<?>> constructor = stubType.getConstructor(Channel.class);
65+
return constructor.newInstance(channel);
66+
67+
} catch (final Exception e) {
68+
throw new BeanInstantiationException(stubType, "Failed to create gRPC client via FallbackStubFactory", e);
69+
}
70+
}
71+
72+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2016-2020 Michael Zhang <[email protected]>
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
18+
package net.devh.boot.grpc.test.inject;
19+
20+
import io.grpc.CallOptions;
21+
import io.grpc.Channel;
22+
23+
/**
24+
* Fake generated grpc class.
25+
*/
26+
public class CustomGrpc {
27+
28+
public static CustomAccessibleStub custom(final Channel channel) {
29+
return new CustomAccessibleStub(channel);
30+
}
31+
32+
public static FactoryMethodAccessibleStub newFactoryMethodAccessibleStubStub(final Channel channel) {
33+
return new FactoryMethodAccessibleStub(channel);
34+
}
35+
36+
public static class CustomAccessibleStub extends CustomStub<CustomAccessibleStub> {
37+
38+
private CustomAccessibleStub(final Channel channel) {
39+
super(channel);
40+
}
41+
42+
private CustomAccessibleStub(final Channel channel, final CallOptions callOptions) {
43+
super(channel, callOptions);
44+
}
45+
46+
@Override
47+
protected CustomAccessibleStub build(final Channel channel, final CallOptions callOptions) {
48+
return new CustomAccessibleStub(channel, callOptions);
49+
}
50+
51+
}
52+
53+
public static class FactoryMethodAccessibleStub extends OtherStub<FactoryMethodAccessibleStub> {
54+
55+
private FactoryMethodAccessibleStub(final Channel channel) {
56+
super(channel);
57+
}
58+
59+
private FactoryMethodAccessibleStub(final Channel channel, final CallOptions callOptions) {
60+
super(channel, callOptions);
61+
}
62+
63+
@Override
64+
protected FactoryMethodAccessibleStub build(final Channel channel, final CallOptions callOptions) {
65+
return new FactoryMethodAccessibleStub(channel, callOptions);
66+
}
67+
68+
}
69+
70+
public static class ConstructorAccessibleStub extends OtherStub<ConstructorAccessibleStub> {
71+
72+
public ConstructorAccessibleStub(final Channel channel) {
73+
super(channel);
74+
}
75+
76+
public ConstructorAccessibleStub(final Channel channel, final CallOptions callOptions) {
77+
super(channel, callOptions);
78+
}
79+
80+
@Override
81+
protected ConstructorAccessibleStub build(final Channel channel, final CallOptions callOptions) {
82+
return new ConstructorAccessibleStub(channel, callOptions);
83+
}
84+
85+
}
86+
87+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2016-2020 Michael Zhang <[email protected]>
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
6+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
10+
* Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
14+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
15+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16+
*/
17+
18+
package net.devh.boot.grpc.test.inject;
19+
20+
import io.grpc.CallOptions;
21+
import io.grpc.Channel;
22+
import io.grpc.stub.AbstractStub;
23+
24+
/**
25+
* Simulates a custom stub type provided by a third party library, that requires a custom
26+
* {@link net.devh.boot.grpc.client.stubfactory.StubFactory StubFactory}.
27+
*
28+
* @param <S> The type of the stub implementation.
29+
*/
30+
public abstract class CustomStub<S extends CustomStub<S>> extends AbstractStub<S> {
31+
32+
protected CustomStub(final Channel channel) {
33+
super(channel);
34+
}
35+
36+
protected CustomStub(final Channel channel, final CallOptions callOptions) {
37+
super(channel, callOptions);
38+
}
39+
40+
}

0 commit comments

Comments
 (0)