
dagger.grpc.server.processor.GrpcServiceModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dagger-grpc-server-processor Show documentation
Show all versions of dagger-grpc-server-processor Show documentation
A fast dependency injector for Android and Java.
The newest version!
/*
* Copyright (C) 2016 The Dagger 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
*
* http://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 dagger.grpc.server.processor;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
import static com.google.auto.common.MoreElements.getAnnotationMirror;
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import com.google.auto.common.MoreTypes;
import com.google.common.base.Joiner;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import dagger.grpc.server.ForGrpcService;
import dagger.grpc.server.GrpcService;
import dagger.grpc.server.processor.SourceGenerator.IoGrpc;
import java.util.Optional;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.AnnotationValueVisitor;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleAnnotationValueVisitor7;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
class GrpcServiceModel {
private static final String GRPC_SERVICE_PARAMETER_NAME = "grpcClass";
private final Types types;
private final Elements elements;
private final SourceVersion sourceVersion;
private final Messager messager;
final TypeElement serviceImplementation;
final ClassName serviceImplementationClassName;
final ClassName serviceDefinitionTypeName;
final ClassName proxyModuleName;
final ClassName serviceDefinitionTypeFactoryName;
final ClassName serviceModuleName;
final ClassName unscopedServiceModuleName;
GrpcServiceModel(ProcessingEnvironment processingEnv, TypeElement serviceImplementation) {
this.types = processingEnv.getTypeUtils();
this.elements = processingEnv.getElementUtils();
this.sourceVersion = processingEnv.getSourceVersion();
this.messager = processingEnv.getMessager();
this.serviceImplementation = serviceImplementation;
this.serviceImplementationClassName = ClassName.get(serviceImplementation);
this.serviceDefinitionTypeName = peerClassWithSuffix("ServiceDefinition");
this.serviceDefinitionTypeFactoryName = serviceDefinitionTypeName.nestedClass("Factory");
this.proxyModuleName = peerClassWithSuffix("GrpcProxyModule");
this.serviceModuleName = peerClassWithSuffix("GrpcServiceModule");
this.unscopedServiceModuleName = peerClassWithSuffix("UnscopedGrpcServiceModule");
}
/**
* Returns the name of a top-level class in the same package as the service implementation
* class, whose name is the simple name of the service implementation class and its enclosing
* classes, joined with underscores, and appended with {@code suffix}.
*/
private ClassName peerClassWithSuffix(String suffix) {
return serviceImplementationClassName.peerClass(
Joiner.on('_').join(serviceImplementationClassName.simpleNames()) + suffix);
}
String packageName() {
return serviceImplementationClassName.packageName();
}
public boolean validate() {
AnnotationValue argument =
getAnnotationValue(grpcServiceAnnotation(), GRPC_SERVICE_PARAMETER_NAME);
return argument.accept(
new SimpleAnnotationValueVisitor7(false) {
@Override
public Boolean visitType(TypeMirror type, AnnotationValue value) {
return validateGrpcClass(type, value);
}
},
argument);
}
private AnnotationMirror grpcServiceAnnotation() {
return getAnnotationMirror(serviceImplementation, GrpcService.class).get();
}
/** Returns the gRPC service class declared by {@link GrpcService#grpcClass()}. */
protected final TypeElement grpcClass() {
AnnotationValue argument =
getAnnotationValue(grpcServiceAnnotation(), GRPC_SERVICE_PARAMETER_NAME);
return GET_TYPE_ELEMENT_FROM_VALUE.visit(argument, argument);
}
/**
* Returns the annotation spec for the {@code @Generated} annotation to add to any
* type generated by this processor.
*/
protected final Optional generatedAnnotation() {
return generatedAnnotationSpec(
elements,
sourceVersion,
GrpcService.class,
String.format(
"@%s annotation on %s",
GrpcService.class.getCanonicalName(), serviceImplementationClassName));
}
/**
* Returns the annotation spec for a {@link ForGrpcService} annotation whose value is the
* gRPC-generated service class.
*/
protected final AnnotationSpec forGrpcService() {
return AnnotationSpec.builder(ForGrpcService.class)
.addMember("value", "$T.class", grpcClass())
.build();
}
protected final String subcomponentServiceDefinitionMethodName() {
return UPPER_CAMEL.to(LOWER_CAMEL, simpleServiceName()) + "ServiceDefinition";
}
private String simpleServiceName() {
return grpcClass().getSimpleName().toString().replaceFirst("Grpc$", "");
}
private TypeElement serviceImplBase(TypeMirror service) {
ClassName serviceClassName = ClassName.get(MoreTypes.asTypeElement(service));
ClassName serviceImplBaseName = serviceClassName.nestedClass(simpleServiceName() + "ImplBase");
return elements.getTypeElement(serviceImplBaseName.toString());
}
private boolean validateGrpcClass(TypeMirror type, AnnotationValue value) {
TypeElement serviceImplBase = serviceImplBase(type);
if (serviceImplBase == null || !types.isSubtype(serviceImplBase.asType(), bindableService())) {
messager.printMessage(
Kind.ERROR,
String.format("%s is not a gRPC service class", type),
serviceImplementation,
grpcServiceAnnotation(),
value);
return false;
}
if (!(types.isSubtype(serviceImplementation.asType(), serviceImplBase.asType()))) {
messager.printMessage(
Kind.ERROR,
String.format(
"%s must extend %s", serviceImplementation, serviceImplBase.getQualifiedName()),
serviceImplementation,
grpcServiceAnnotation(),
value);
return false;
}
return true;
}
private TypeMirror bindableService() {
return elements.getTypeElement(IoGrpc.BINDABLE_SERVICE.toString()).asType();
}
static final AnnotationValueVisitor GET_TYPE_ELEMENT_FROM_VALUE =
new SimpleAnnotationValueVisitor7() {
@Override
public TypeElement visitType(TypeMirror t, AnnotationValue p) {
return MoreTypes.asTypeElement(t);
}
@Override
protected TypeElement defaultAction(Object o, AnnotationValue p) {
throw new IllegalArgumentException("Expected " + p + " to be a class");
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy