aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar shahan <shahan@google.com>2018-01-03 10:18:05 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-01-03 10:19:43 -0800
commitd2acedc4ca87156a6aa6f96008652c2070dfd071 (patch)
tree46544717ab234962ffc513d4a479c418a61404ad /src/main
parente9f4090c67a89247166b7c9607394b350a7c4ef6 (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')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodec.java21
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java29
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/util/RegexFilter.java1
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;