diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodec.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodec.java index 3f3319f278ed8a..d40c5aac73bd92 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodec.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodec.java @@ -92,7 +92,7 @@ public static enum Strategy { * com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec#deserialize}. * *

A compiler error will result if more than one constructor parameter has the - * {@code @Dependency} annotation. + * {@code @Dependency} annotation or if the annotation itself has a dependency element. */ @Target(ElementType.PARAMETER) public static @interface Dependency {} @@ -106,8 +106,7 @@ public static enum Strategy { * {@link com.google.devtools.build.lib.skyframe.serialization.ObjectCodec} with the dependency * type parameter matching the returned type. * - *

This is for use with {@code PUBLIC_FIELDS}, and {@code POLYMORPHIC} strategies. It is an - * error to use this with the {@code CONSTRUCTOR} strategy. + *

It is an error to use this in conjunction with {@code @AutoCodec.Dependency}. */ Class dependency() default Void.class; } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java index af07ff529e53c5..744323240ff5b9 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java @@ -97,13 +97,7 @@ public boolean process(Set annotations, RoundEnvironment TypeSpec.Builder codecClassBuilder = null; switch (annotation.strategy()) { case CONSTRUCTOR: - if (dependencyType != null) { - throw new IllegalArgumentException( - encodedType.getQualifiedName() - + " uses the CONSTRUCTOR strategy and has a non-Void dependency " - + dependencyType.getQualifiedName()); - } - codecClassBuilder = buildClassWithConstructorStrategy(encodedType); + codecClassBuilder = buildClassWithConstructorStrategy(encodedType, dependencyType); break; case PUBLIC_FIELDS: codecClassBuilder = buildClassWithPublicFieldsStrategy(encodedType, dependencyType); @@ -150,9 +144,20 @@ private TypeElement getDependencyType(AutoCodec annotation) { } } - private TypeSpec.Builder buildClassWithConstructorStrategy(TypeElement encodedType) { + private TypeSpec.Builder buildClassWithConstructorStrategy( + TypeElement encodedType, @Nullable TypeElement dependency) { ExecutableElement constructor = selectConstructorForConstructorStrategy(encodedType); PartitionedParameters parameters = isolateDependency(constructor); + if (dependency != null) { + if (parameters.dependency != null) { + throw new IllegalArgumentException( + encodedType.getQualifiedName() + + " has both a @Dependency annotated constructor parameter " + + "and a non-Void dependency element " + + dependency.getQualifiedName()); + } + parameters.dependency = dependency; + } TypeSpec.Builder codecClassBuilder = AutoCodecUtil.initializeCodecClassBuilder(encodedType, parameters.dependency); @@ -174,11 +179,7 @@ private TypeSpec.Builder buildClassWithConstructorStrategy(TypeElement encodedTy private static class PartitionedParameters { /** Non-dependency parameters. */ List fields; - /** - * Parameter having the {@link AutoCodec.Dependency} annotation. - * - *

Null if no such parameter exists. - */ + /** Dependency for this codec or null if no such dependency exists. */ @Nullable TypeElement dependency; } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java index 7a01498151bc10..d6d7bd04464a63 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Maps; +import com.google.common.hash.HashCode; import com.google.devtools.build.lib.skyframe.serialization.InjectingObjectCodec; import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.Marshaller.Context; @@ -421,6 +422,26 @@ public void addDeserializationCode(Context context) { } }; + /** Since we cannot add a codec to {@link HashCode}, it needs to be supported natively. */ + private final Marshaller hashCodeMarshaller = + new Marshaller() { + @Override + public boolean matches(DeclaredType type) { + return matchesType(type, HashCode.class); + } + + @Override + public void addSerializationCode(Context context) { + context.builder.addStatement("codedOut.writeByteArrayNoTag($L.asBytes())", context.name); + } + + @Override + public void addDeserializationCode(Context context) { + context.builder.addStatement( + "$L = $T.fromBytes(codedIn.readByteArray())", context.name, HashCode.class); + } + }; + private final Marshaller protoMarshaller = new Marshaller() { @Override @@ -484,6 +505,7 @@ public void addDeserializationCode(Context context) { mapMarshaller, multimapMarshaller, patternMarshaller, + hashCodeMarshaller, protoMarshaller, codecMarshaller);