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
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 b36dd4e..2d67bed 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 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 @@
     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 c6d0df9..8df0f87 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 @@
 
   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 052d856..e3c7898 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 @@
       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 220ff02..4d3b7ef 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 @@
    * <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;