diff options
author | shahan <shahan@google.com> | 2018-01-03 10:18:05 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-01-03 10:19:43 -0800 |
commit | d2acedc4ca87156a6aa6f96008652c2070dfd071 (patch) | |
tree | 46544717ab234962ffc513d4a479c418a61404ad /src/main | |
parent | e9f4090c67a89247166b7c9607394b350a7c4ef6 (diff) |
Adds the @AutoCodec.Constructor annotation for selecting constructors.
Uses the constructor having the @AutoCodec.Constructor annotation to generate a codec (instead of choosing the first in source code). This annotation is required when a class has more than one constructor.
PiperOrigin-RevId: 180685902
Diffstat (limited to 'src/main')
4 files changed, 42 insertions, 10 deletions
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 b36dd4effb..2d67bedf6c 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 @@ -40,19 +40,17 @@ public @interface AutoCodec { */ public static enum Strategy { /** - * Uses the first constructor of the class to synthesize a codec. + * Uses a constructor of the class to synthesize a codec. * * <p>This strategy depends on * * <ul> - * <li>the first class constructor taking all serialized fields as parameters - * <li>and each serialized field having a corresponding getter. + * <li>a designated constructor to inspect to generate the codec + * <li>the parameters must match member fields on name and type. * </ul> * - * For example, a constructor having parameter, {@code target}, should having a matching getter, - * {@code getTarget()}. - * - * <p>The first constructor is the first ocurring in the source code. + * <p>If there is a unique constructor, that is the designated constructor, otherwise one must + * be selected using the {@link AutoCodec.Constructor} annotation. */ CONSTRUCTOR, /** @@ -71,5 +69,14 @@ public @interface AutoCodec { POLYMORPHIC, } + /** + * Marks a specific constructor when using the CONSTRUCTOR strategy. + * + * <p>Indicates a constructor for codec generation. A compile-time error will result if multiple + * constructors are thus tagged. + */ + @Target(ElementType.CONSTRUCTOR) + public static @interface Constructor {} + Strategy strategy() default Strategy.CONSTRUCTOR; } 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 c6d0df9dac..8df0f8743e 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 @@ -14,7 +14,10 @@ package com.google.devtools.build.lib.skyframe.serialization.autocodec; +import static com.google.common.collect.ImmutableList.toImmutableList; + import com.google.auto.service.AutoService; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec; import com.google.devtools.build.lib.skyframe.serialization.strings.StringCodecs; @@ -127,9 +130,29 @@ public class AutoCodecProcessor extends AbstractProcessor { private void buildClassWithConstructorStrategy( TypeSpec.Builder codecClassBuilder, TypeElement encodedType) { - // In Java, every class has a constructor, so this always succeeds. - ExecutableElement constructor = - ElementFilter.constructorsIn(encodedType.getEnclosedElements()).get(0); + List<ExecutableElement> constructors = + ElementFilter.constructorsIn(encodedType.getEnclosedElements()); + ImmutableList<ExecutableElement> markedConstructors = + constructors + .stream() + .filter(c -> c.getAnnotation(AutoCodec.Constructor.class) != null) + .collect(toImmutableList()); + ExecutableElement constructor = null; + if (markedConstructors.isEmpty()) { + // If nothing is marked, see if there is a unique constructor. + if (constructors.size() > 1) { + throw new IllegalArgumentException( + encodedType.getQualifiedName() + + " has multiple constructors but no Constructor annotation."); + } + // In Java, every class has at least one constructor, so this never fails. + constructor = constructors.get(0); + } else if (markedConstructors.size() == 1) { + constructor = markedConstructors.get(0); + } else { + throw new IllegalArgumentException( + encodedType.getQualifiedName() + " has multiple Constructor annotations."); + } List<? extends VariableElement> constructorParameters = constructor.getParameters(); initializeUnsafeOffsets(codecClassBuilder, encodedType, constructorParameters); codecClassBuilder.addMethod( 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 052d856461..e3c7898c58 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 @@ -68,6 +68,7 @@ class Marshallers { new Marshaller() { @Override public boolean matches(DeclaredType type) { + // TODO(shahan): check for getCodec or CODEC. // CODEC is the final fallback for all Marshallers so this returns true. return true; } diff --git a/src/main/java/com/google/devtools/build/lib/util/RegexFilter.java b/src/main/java/com/google/devtools/build/lib/util/RegexFilter.java index 220ff0235c..4d3b7ef670 100644 --- a/src/main/java/com/google/devtools/build/lib/util/RegexFilter.java +++ b/src/main/java/com/google/devtools/build/lib/util/RegexFilter.java @@ -91,6 +91,7 @@ public final class RegexFilter { * <p>Null {@code inclusionPattern} or {@code exclusionPattern} means that inclusion or exclusion * matching will not be applied, respectively. */ + @AutoCodec.Constructor RegexFilter(@Nullable Pattern inclusionPattern, @Nullable Pattern exclusionPattern) { this.inclusionPattern = inclusionPattern; this.exclusionPattern = exclusionPattern; |