| // Copyright 2023 The Bazel Authors. All rights reserved. |
| // |
| // 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 com.google.devtools.build.lib.skyframe.serialization.autocodec; |
| |
| import static com.google.devtools.build.lib.skyframe.serialization.autocodec.Initializers.initializeCodecClassBuilder; |
| import static com.google.devtools.build.lib.skyframe.serialization.autocodec.Initializers.initializeSerializeMethodBuilder; |
| |
| import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; |
| import com.squareup.javapoet.MethodSpec; |
| import com.squareup.javapoet.TypeSpec; |
| import java.util.List; |
| import javax.annotation.processing.ProcessingEnvironment; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.element.TypeElement; |
| |
| /** Defines an abstract strategy for generating {@link ObjectCodec} implementations. */ |
| // TODO(b/297857068): migrate other types to this class. |
| abstract class CodecGenerator { |
| final ProcessingEnvironment env; |
| |
| CodecGenerator(ProcessingEnvironment env) { |
| this.env = env; |
| } |
| |
| /** Creates the codec by delegating lower level implementation methods. */ |
| final TypeSpec defineCodec( |
| TypeElement encodedType, AutoCodec annotation, ExecutableElement instantiator) |
| throws SerializationProcessingException { |
| List<? extends FieldGenerator> fieldGenerators = getFieldGenerators(encodedType); |
| |
| TypeSpec.Builder classBuilder = initializeCodecClassBuilder(encodedType, env); |
| performAdditionalCodecInitialization(classBuilder, encodedType, instantiator); |
| |
| MethodSpec.Builder constructor = initializeConstructor(!fieldGenerators.isEmpty()); |
| MethodSpec.Builder serialize = initializeSerializeMethodBuilder(encodedType, annotation, env); |
| MethodSpec.Builder deserialize = initializeDeserializeMethod(encodedType); |
| |
| for (FieldGenerator generator : fieldGenerators) { |
| generator.generateOffsetMember(classBuilder, constructor); |
| generator.generateAdditionalMemberVariables(classBuilder); |
| generator.generateConstructorCode(constructor); |
| generator.generateSerializeCode(serialize); |
| generator.generateDeserializeCode(deserialize); |
| } |
| |
| addImplementationToEndOfMethods( |
| instantiator, constructor, deserialize, !fieldGenerators.isEmpty()); |
| |
| return classBuilder |
| .addMethod(constructor.build()) |
| .addMethod(serialize.build()) |
| .addMethod(deserialize.build()) |
| .build(); |
| } |
| |
| /** |
| * Performs additional initialization steps on the codec being created. |
| * |
| * <p>Adds the correct superclass. May define additional field-independent methods. |
| */ |
| abstract void performAdditionalCodecInitialization( |
| TypeSpec.Builder classBuilder, TypeElement encodedType, ExecutableElement instantiator); |
| |
| /** Creates {@link FieldGenerator} instances that generate code for serialized fields. */ |
| abstract List<? extends FieldGenerator> getFieldGenerators(TypeElement type) |
| throws SerializationProcessingException; |
| |
| /** |
| * Initializes the field-independent parts of the constructor. |
| * |
| * @param hasFields true if there are any fields to serialize. Exception handling logic may depend |
| * on the presence of fields. |
| */ |
| abstract MethodSpec.Builder initializeConstructor(boolean hasFields); |
| |
| /** Initializes the method that performs deserialization work. */ |
| abstract MethodSpec.Builder initializeDeserializeMethod(TypeElement encodedType); |
| |
| /** |
| * Adds field-independent code at the end of methods after per-field code is added. |
| * |
| * @param hasFields true if there are any fields to serialize, based on the result of {@link |
| * #getFieldGenerators}. Exception handling logic may depend on the presence of fields. |
| */ |
| abstract void addImplementationToEndOfMethods( |
| ExecutableElement instantiator, |
| MethodSpec.Builder constructor, |
| MethodSpec.Builder deserialize, |
| boolean hasFields); |
| } |