codes.sf.springboot.grpc.client.context.GrpcStubFactoryBean Maven / Gradle / Ivy
package codes.sf.springboot.grpc.client.context;
import codes.sf.springboot.grpc.client.GrpcChannelSource;
import codes.sf.springboot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
import codes.sf.springboot.grpc.client.stubpostprocess.GenericGrpcStubPostProcessor;
import io.grpc.stub.AbstractStub;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.util.MethodInvoker;
import java.util.List;
import static java.util.Arrays.asList;
/**
* {@link FactoryBean} for instantiating gRPC stubs from static classes
* generated by the
*
* gRPC Java Protobuf Compiler
* .
*
* These static factory classes follow a consistent pattern where each
* stub type is instantiated with static function:
*
* - {@code .newXyzStub(Channel)}
* - {@code .newXyzFutureStub(Channel)}
* - {@code .newXyzBlockingStub(Channel)}
*
* where Xyz is the stub service name. This factory invokes
* the appropriate static function via reflection.
*
* @param the gRPC stub type this factory produces
* @author Semyon Fishman
* @since 0.0.1
*/
class GrpcStubFactoryBean> implements FactoryBean {
// Order matters!
private static final List STUB_SUFFIXES
= asList("BlockingStub", "FutureStub", "Stub");
private final String factoryClassName;
private final Class stubClass;
private GrpcChannelSource channelSource;
private List postProcessors;
public GrpcStubFactoryBean(String factoryClassName, Class stubClass) {
this.factoryClassName = factoryClassName;
this.stubClass = stubClass;
}
@Required
public void setChannelSource(GrpcChannelSource channelSource) {
this.channelSource = channelSource;
}
@Required
@Qualifier(GrpcClientAutoConfiguration.GENERIC_GRPC_STUB_POST_PROCESSORS_BEAN_NAME)
public void setGrpcStubPostProcessors(List postProcessors) {
this.postProcessors = postProcessors;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
@SuppressWarnings("unchecked")
public S getObject() throws Exception {
String suffix = STUB_SUFFIXES.stream()
.filter(s -> stubClass.getCanonicalName().endsWith(s))
.findFirst()
.get();
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.setStaticMethod(factoryClassName + ".new" + suffix);
methodInvoker.setArguments(channelSource.resolve(stubClass));
methodInvoker.prepare();
S stub = (S) methodInvoker.invoke();
for (GenericGrpcStubPostProcessor processor : postProcessors) {
if (processor.supportsStubType(stub.getClass()))
stub = (S) processor.postProcess(stub);
}
return stub;
}
@Override
public Class> getObjectType() {
return stubClass;
}
}