Files
Android11_RK3568_Lubancat2/external/dagger2/java/dagger/internal/codegen/DeserializedComponentImplementationBuilder.java
2023-05-14 11:44:44 +00:00

257 lines
11 KiB
Java

/*
* Copyright (C) 2019 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.internal.codegen;
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
import static com.google.auto.common.MoreElements.getAnnotationMirror;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static dagger.internal.codegen.BindingRequest.bindingRequest;
import static dagger.internal.codegen.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
import static dagger.internal.codegen.serialization.ProtoSerialization.fromAnnotationValue;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static javax.lang.model.util.ElementFilter.typesIn;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import dagger.internal.ComponentDefinitionType;
import dagger.internal.ConfigureInitializationParameters;
import dagger.internal.ModifiableBinding;
import dagger.internal.ModifiableModule;
import dagger.internal.codegen.ComponentImplementation.ConfigureInitializationMethod;
import dagger.internal.codegen.serialization.BindingRequestProto;
import dagger.internal.codegen.serialization.ComponentRequirementProto;
import dagger.internal.codegen.serialization.FrameworkTypeWrapper;
import dagger.internal.codegen.serialization.KeyProto;
import dagger.model.Key;
import dagger.model.RequestKind;
import java.util.Optional;
import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
/**
* Reconstructs {@link ComponentImplementation}s that have already been compiled. Uses metadata
* annotations on the generated type and it's methods to reconstitute the equivalent {@link
* ComponentImplementation} state.
*/
final class DeserializedComponentImplementationBuilder {
private final CompilerOptions compilerOptions;
private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
private final TypeProtoConverter typeProtoConverter;
private final KeyFactory keyFactory;
@Inject
DeserializedComponentImplementationBuilder(
CompilerOptions compilerOptions,
ComponentCreatorImplementationFactory componentCreatorImplementationFactory,
TypeProtoConverter typeProtoConverter,
KeyFactory keyFactory) {
this.compilerOptions = compilerOptions;
this.componentCreatorImplementationFactory = componentCreatorImplementationFactory;
this.typeProtoConverter = typeProtoConverter;
this.keyFactory = keyFactory;
}
/** Creates a new {@link ComponentImplementation} from a compiled component. */
ComponentImplementation create(ComponentDescriptor component, TypeElement generatedComponent) {
Optional<ComponentImplementation> superclassImplementation =
deserializedSuperclassImplementation(
component, MoreTypes.asTypeElement(generatedComponent.getSuperclass()));
ComponentImplementation componentImplementation =
ComponentImplementation.forDeserializedComponent(
component,
ClassName.get(generatedComponent),
generatedComponent.getNestingKind(),
superclassImplementation,
compilerOptions);
componentImplementation.setCreatorImplementation(
superclassImplementation.isPresent()
? Optional.empty()
: componentCreatorImplementationFactory.create(
componentImplementation, Optional.empty()));
// TODO(b/117833324): Consider omitting superclass implementations, so that only one instance of
// ComponentImplementation needs to be created (in most cases, we don't care about nested levels
// of superclass implementations, except for the base implementation). If that's possible, use
// getLocalAndInheritedMethods instead of getEnclosedElements() here.
for (ExecutableElement method : methodsIn(generatedComponent.getEnclosedElements())) {
getAnnotationMirror(method, ModifiableBinding.class)
.asSet()
.forEach(
annotation ->
addModifiableBindingMethod(componentImplementation, method, annotation));
getAnnotationMirror(method, ModifiableModule.class)
.asSet()
.forEach(
annotation -> addModifiableModuleMethod(componentImplementation, method, annotation));
getAnnotationMirror(method, ConfigureInitializationParameters.class)
.asSet()
.forEach(
annotation ->
setConfigureInitializationMethod(componentImplementation, method, annotation));
}
for (TypeElement nestedType : typesIn(generatedComponent.getEnclosedElements())) {
addChildImplementation(component, componentImplementation, nestedType);
}
return componentImplementation;
}
private Optional<ComponentImplementation> deserializedSuperclassImplementation(
ComponentDescriptor component, TypeElement superclassElement) {
return isAnnotationPresent(superclassElement, ComponentDefinitionType.class)
? Optional.of(create(component, superclassElement))
: Optional.empty();
}
private void addModifiableBindingMethod(
ComponentImplementation componentImplementation,
ExecutableElement method,
AnnotationMirror metadataAnnotation) {
ModifiableBindingType modifiableBindingType =
ModifiableBindingType.valueOf(
getAnnotationValue(metadataAnnotation, "modifiableBindingType").getValue().toString());
BindingRequest request =
parseBindingRequest(getAnnotationValue(metadataAnnotation, "bindingRequest"));
ImmutableList<Key> multibindingContributions =
asAnnotationValues(getAnnotationValue(metadataAnnotation, "multibindingContributions"))
.stream()
.map(this::parseKey)
.collect(toImmutableList());
componentImplementation.addModifiableBindingMethod(
modifiableBindingType,
request,
method.getReturnType(),
methodDeclaration(method),
method.getModifiers().contains(FINAL));
componentImplementation.registerImplementedMultibindingKeys(request, multibindingContributions);
}
private BindingRequest fromProto(BindingRequestProto bindingRequest) {
Key key = keyFactory.fromProto(bindingRequest.getKey());
return bindingRequest.getFrameworkType().equals(FrameworkTypeWrapper.FrameworkType.UNKNOWN)
? bindingRequest(key, RequestKind.valueOf(bindingRequest.getRequestKind().name()))
: bindingRequest(key, FrameworkType.valueOf(bindingRequest.getFrameworkType().name()));
}
/**
* Returns a {@link MethodSpec} for a {@link
* dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod}. The method contents
* are not relevant since this represents a method that has already been compiled.
*
* <p>Ideally this could be {@code MethodSpec.overriding(method).build()}, but that doesn't work
* for {@code final} methods
*/
private MethodSpec methodDeclaration(ExecutableElement method) {
return methodBuilder(method.getSimpleName().toString())
.addModifiers(method.getModifiers())
.returns(TypeName.get(method.getReturnType()))
.build();
}
private void addModifiableModuleMethod(
ComponentImplementation componentImplementation,
ExecutableElement method,
AnnotationMirror metadataAnnotation) {
ComponentRequirement moduleRequirement =
parseComponentRequirement(getAnnotationValue(metadataAnnotation, "value"));
componentImplementation.registerModifiableModuleMethod(
moduleRequirement, method.getSimpleName().toString());
}
private void setConfigureInitializationMethod(
ComponentImplementation componentImplementation,
ExecutableElement method,
AnnotationMirror metadataAnnotation) {
ImmutableSet<ComponentRequirement> parameters =
asAnnotationValues(getAnnotationValue(metadataAnnotation, "value")).stream()
.map(this::parseComponentRequirement)
.collect(toImmutableSet());
componentImplementation.setConfigureInitializationMethod(
ConfigureInitializationMethod.create(MethodSpec.overriding(method).build(), parameters));
}
private void addChildImplementation(
ComponentDescriptor component,
ComponentImplementation componentImplementation,
TypeElement nestedType) {
getAnnotationMirror(nestedType, ComponentDefinitionType.class)
.transform(annotation -> (TypeMirror) getAnnotationValue(annotation, "value").getValue())
.transform(MoreTypes::asTypeElement)
.asSet()
.forEach(
componentDefinitionType -> {
ComponentDescriptor child =
component.childComponentsByElement().get(componentDefinitionType);
componentImplementation.addChild(child, create(child, nestedType));
});
}
private Key parseKey(AnnotationValue annotationValue) {
return keyFactory.fromProto(
fromAnnotationValue(annotationValue, KeyProto.getDefaultInstance()));
}
private BindingRequest parseBindingRequest(AnnotationValue annotationValue) {
return fromProto(
fromAnnotationValue(annotationValue, BindingRequestProto.getDefaultInstance()));
}
private ComponentRequirement parseComponentRequirement(AnnotationValue annotationValue) {
return fromProto(
fromAnnotationValue(annotationValue, ComponentRequirementProto.getDefaultInstance()));
}
private ComponentRequirement fromProto(ComponentRequirementProto proto) {
switch (proto.getRequirementCase()) {
case MODULE:
return ComponentRequirement.forModule(typeProtoConverter.fromProto(proto.getModule()));
case DEPENDENCY:
return ComponentRequirement.forDependency(
typeProtoConverter.fromProto(proto.getDependency()));
case BOUND_INSTANCE:
return ComponentRequirement.forBoundInstance(
keyFactory.fromProto(proto.getBoundInstance().getKey()),
proto.getBoundInstance().getNullable(),
proto.getBoundInstance().getVariableName());
case REQUIREMENT_NOT_SET:
// fall through
}
throw new AssertionError(proto);
}
}