Merge "Merge commit 'upstream/auto-value-1.9^'"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ec92243..4471842 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,13 +18,13 @@
     steps:
       # Cancel any previous runs for the same branch that are still running.
       - name: 'Cancel previous runs'
-        uses: styfle/cancel-workflow-action@0.9.0
+        uses: styfle/cancel-workflow-action@0.9.1
         with:
           access_token: ${{ github.token }}
       - name: 'Check out repository'
-        uses: actions/checkout@v2.3.4
+        uses: actions/checkout@v2.4.0
       - name: 'Cache local Maven repository'
-        uses: actions/cache@v2.1.6
+        uses: actions/cache@v2.1.7
         with:
           path: ~/.m2/repository
           key: maven-${{ hashFiles('**/pom.xml') }}
@@ -49,9 +49,9 @@
     runs-on: ubuntu-latest
     steps:
       - name: 'Check out repository'
-        uses: actions/checkout@v2.3.4
+        uses: actions/checkout@v2.4.0
       - name: 'Cache local Maven repository'
-        uses: actions/cache@v2.1.6
+        uses: actions/cache@v2.1.7
         with:
           path: ~/.m2/repository
           key: maven-${{ hashFiles('**/pom.xml') }}
@@ -78,9 +78,9 @@
     runs-on: ubuntu-latest
     steps:
       - name: 'Check out repository'
-        uses: actions/checkout@v2.3.4
+        uses: actions/checkout@v2.4.0
       - name: 'Cache local Maven repository'
-        uses: actions/cache@v2.1.6
+        uses: actions/cache@v2.1.7
         with:
           path: ~/.m2/repository
           key: maven-${{ hashFiles('**/pom.xml') }}
diff --git a/METADATA b/METADATA
index dca6f71..560bb92 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@
     type: GIT
     value: "https://github.com/google/auto"
   }
-  version: "auto-value-1.7.4"
-  last_upgrade_date { year: 2020 month: 11 day: 18 }
+  version: "auto-value-1.9"
+  last_upgrade_date { year: 2022 month: 04 day: 11 }
   license_type: NOTICE
 }
diff --git a/common/pom.xml b/common/pom.xml
index 2754b81..a9c1e3f 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -26,7 +26,7 @@
 
   <groupId>com.google.auto</groupId>
   <artifactId>auto-common</artifactId>
-  <version>0.11</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>Auto Common Libraries</name>
   <description>
     Common utilities for creating annotation processors.
@@ -36,7 +36,7 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <java.version>1.8</java.version>
-    <guava.version>30.1.1-jre</guava.version>
+    <guava.version>31.0.1-jre</guava.version>
     <truth.version>1.1.3</truth.version>
   </properties>
 
@@ -128,7 +128,7 @@
           <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-java</artifactId>
-            <version>1.0.7</version>
+            <version>1.1.0</version>
           </dependency>
         </dependencies>
       </plugin>
diff --git a/common/src/main/java/com/google/auto/common/AnnotationMirrors.java b/common/src/main/java/com/google/auto/common/AnnotationMirrors.java
index 9ce5cd9..2f59dd3 100644
--- a/common/src/main/java/com/google/auto/common/AnnotationMirrors.java
+++ b/common/src/main/java/com/google/auto/common/AnnotationMirrors.java
@@ -191,5 +191,16 @@
         .collect(toImmutableSet());
   }
 
+  /**
+   * Returns a string representation of the given annotation mirror, suitable for inclusion in a
+   * Java source file to reproduce the annotation in source form.
+   *
+   * <p>Fully qualified names are used for types in annotations, class literals, and enum constants,
+   * ensuring that the source form will compile without requiring additional imports.
+   */
+  public static String toString(AnnotationMirror annotationMirror) {
+    return AnnotationOutput.toString(annotationMirror);
+  }
+
   private AnnotationMirrors() {}
 }
diff --git a/common/src/main/java/com/google/auto/common/AnnotationOutput.java b/common/src/main/java/com/google/auto/common/AnnotationOutput.java
new file mode 100644
index 0000000..e52bde6
--- /dev/null
+++ b/common/src/main/java/com/google/auto/common/AnnotationOutput.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2014 Google LLC
+ *
+ * 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.auto.common;
+
+import static com.google.auto.common.MoreTypes.asTypeElement;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * Handling of default values for annotation members.
+ *
+ * @author emcmanus@google.com (Éamonn McManus)
+ */
+final class AnnotationOutput {
+  private AnnotationOutput() {} // There are no instances of this class.
+
+  /**
+   * Visitor that produces a string representation of an annotation value, suitable for inclusion in
+   * a Java source file as an annotation member or as the initializer of a variable of the
+   * appropriate type. The syntax for the two is the same except for annotation members that are
+   * themselves annotations. Within an annotation, an annotation member can be written as
+   * {@code @NestedAnnotation(...)}, while in an initializer it must be written as an object, for
+   * example the construction of an {@code @AutoAnnotation} class. That's why we have this abstract
+   * class and two concrete subclasses.
+   */
+  private static class SourceFormVisitor
+      extends SimpleAnnotationValueVisitor8<@Nullable Void, StringBuilder> {
+
+    private String formatType(TypeMirror typeMirror) {
+      return asTypeElement(typeMirror).getQualifiedName().toString();
+    }
+
+    @Override
+    protected @Nullable Void defaultAction(Object value, StringBuilder sb) {
+      sb.append(value);
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitArray(List<? extends AnnotationValue> values, StringBuilder sb) {
+      sb.append('{');
+      String sep = "";
+      for (AnnotationValue value : values) {
+        sb.append(sep);
+        visit(value, sb);
+        sep = ", ";
+      }
+      sb.append('}');
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitByte(byte b, StringBuilder sb) {
+      sb.append("(byte) ").append(b);
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitShort(short s, StringBuilder sb) {
+      sb.append("(short) ").append(s);
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitChar(char c, StringBuilder sb) {
+      appendQuoted(sb, c);
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitLong(long i, StringBuilder sb) {
+      sb.append(i).append('L');
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitDouble(double d, StringBuilder sb) {
+      if (Double.isNaN(d)) {
+        sb.append("Double.NaN");
+      } else if (d == Double.POSITIVE_INFINITY) {
+        sb.append("Double.POSITIVE_INFINITY");
+      } else if (d == Double.NEGATIVE_INFINITY) {
+        sb.append("Double.NEGATIVE_INFINITY");
+      } else {
+        sb.append(d);
+      }
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitFloat(float f, StringBuilder sb) {
+      if (Float.isNaN(f)) {
+        sb.append("Float.NaN");
+      } else if (f == Float.POSITIVE_INFINITY) {
+        sb.append("Float.POSITIVE_INFINITY");
+      } else if (f == Float.NEGATIVE_INFINITY) {
+        sb.append("Float.NEGATIVE_INFINITY");
+      } else {
+        sb.append(f).append('F');
+      }
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitEnumConstant(VariableElement c, StringBuilder sb) {
+      sb.append(formatType(c.asType())).append('.').append(c.getSimpleName());
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitString(String s, StringBuilder sb) {
+      appendQuoted(sb, s);
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitType(TypeMirror classConstant, StringBuilder sb) {
+      sb.append(formatType(classConstant)).append(".class");
+      return null;
+    }
+
+    @Override
+    public @Nullable Void visitAnnotation(AnnotationMirror a, StringBuilder sb) {
+      sb.append('@').append(formatType(a.getAnnotationType()));
+      ImmutableMap<ExecutableElement, AnnotationValue> map =
+          ImmutableMap.copyOf(a.getElementValues());
+      if (!map.isEmpty()) {
+        sb.append('(');
+        Optional<AnnotationValue> shortForm = shortForm(map);
+        if (shortForm.isPresent()) {
+          this.visit(maybeShorten(shortForm.get()), sb);
+        } else {
+          String sep = "";
+          for (Map.Entry<ExecutableElement, AnnotationValue> entry : map.entrySet()) {
+            sb.append(sep).append(entry.getKey().getSimpleName()).append(" = ");
+            sep = ", ";
+            this.visit(maybeShorten(entry.getValue()), sb);
+          }
+        }
+        sb.append(')');
+      }
+      return null;
+    }
+  }
+
+  private static AnnotationValue maybeShorten(AnnotationValue value) {
+    return ARRAY_VISITOR.visit(value, value);
+  }
+
+  private static final AnnotationValueVisitor<AnnotationValue, AnnotationValue> ARRAY_VISITOR =
+      new SimpleAnnotationValueVisitor8<AnnotationValue, AnnotationValue>() {
+        @Override
+        public AnnotationValue visitArray(
+            List<? extends AnnotationValue> values, AnnotationValue input) {
+          if (values.size() == 1) {
+            // We can shorten @Foo(a = {23}) to @Foo(a = 23). For the specific case where `a` is
+            // actually `value`, we'll already have shortened that in visitAnnotation, so
+            // effectively we go from @Foo(value = {23}) to @Foo({23}) to @Foo(23).
+            return Iterables.getOnlyElement(values);
+          }
+          return input;
+        }
+
+        @Override
+        protected AnnotationValue defaultAction(Object o, AnnotationValue input) {
+          return input;
+        }
+      };
+
+  // We can shorten @Annot(value = 23) to @Annot(23).
+  private static Optional<AnnotationValue> shortForm(
+      Map<ExecutableElement, AnnotationValue> values) {
+    if (values.size() == 1
+        && Iterables.getOnlyElement(values.keySet()).getSimpleName().contentEquals("value")) {
+      return Optional.of(Iterables.getOnlyElement(values.values()));
+    }
+    return Optional.empty();
+  }
+
+  /**
+   * Returns a string representation of the given annotation value, suitable for inclusion in a Java
+   * source file as the initializer of a variable of the appropriate type.
+   */
+  static String toString(AnnotationValue annotationValue) {
+    StringBuilder sb = new StringBuilder();
+    new SourceFormVisitor().visit(annotationValue, sb);
+    return sb.toString();
+  }
+
+  /**
+   * Returns a string representation of the given annotation mirror, suitable for inclusion in a
+   * Java source file to reproduce the annotation in source form.
+   */
+  static String toString(AnnotationMirror annotationMirror) {
+    StringBuilder sb = new StringBuilder();
+    new SourceFormVisitor().visitAnnotation(annotationMirror, sb);
+    return sb.toString();
+  }
+
+  private static StringBuilder appendQuoted(StringBuilder sb, String s) {
+    sb.append('"');
+    for (int i = 0; i < s.length(); i++) {
+      appendEscaped(sb, s.charAt(i));
+    }
+    return sb.append('"');
+  }
+
+  private static StringBuilder appendQuoted(StringBuilder sb, char c) {
+    sb.append('\'');
+    appendEscaped(sb, c);
+    return sb.append('\'');
+  }
+
+  private static void appendEscaped(StringBuilder sb, char c) {
+    switch (c) {
+      case '\\':
+      case '"':
+      case '\'':
+        sb.append('\\').append(c);
+        break;
+      case '\n':
+        sb.append("\\n");
+        break;
+      case '\r':
+        sb.append("\\r");
+        break;
+      case '\t':
+        sb.append("\\t");
+        break;
+      default:
+        if (c < 0x20) {
+          sb.append(String.format("\\%03o", (int) c));
+        } else if (c < 0x7f || Character.isLetter(c)) {
+          sb.append(c);
+        } else {
+          sb.append(String.format("\\u%04x", (int) c));
+        }
+        break;
+    }
+  }
+}
diff --git a/common/src/main/java/com/google/auto/common/AnnotationValues.java b/common/src/main/java/com/google/auto/common/AnnotationValues.java
index 0712e56..a3cc949 100644
--- a/common/src/main/java/com/google/auto/common/AnnotationValues.java
+++ b/common/src/main/java/com/google/auto/common/AnnotationValues.java
@@ -512,5 +512,22 @@
     return ANNOTATION_VALUES_VISITOR.visit(value);
   }
 
+  /**
+   * Returns a string representation of the given annotation value, suitable for inclusion in a Java
+   * source file as part of an annotation. For example, if {@code annotationValue} represents the
+   * string {@code unchecked} in the annotation {@code @SuppressWarnings("unchecked")}, this method
+   * will return the string {@code "unchecked"}, which you can then use as part of an annotation
+   * being generated.
+   *
+   * <p>For all annotation values other than nested annotations, the returned string can also be
+   * used to initialize a variable of the appropriate type.
+   *
+   * <p>Fully qualified names are used for types in annotations, class literals, and enum constants,
+   * ensuring that the source form will compile without requiring additional imports.
+   */
+  public static String toString(AnnotationValue annotationValue) {
+    return AnnotationOutput.toString(annotationValue);
+  }
+
   private AnnotationValues() {}
 }
diff --git a/common/src/main/java/com/google/auto/common/Overrides.java b/common/src/main/java/com/google/auto/common/Overrides.java
index 775c304..cdcd741 100644
--- a/common/src/main/java/com/google/auto/common/Overrides.java
+++ b/common/src/main/java/com/google/auto/common/Overrides.java
@@ -117,7 +117,7 @@
         // can't be overridden.
         return false;
       }
-      if (!(overridden.getEnclosingElement() instanceof TypeElement)) {
+      if (!MoreElements.isType(overridden.getEnclosingElement())) {
         return false;
         // We don't know how this could happen but we avoid blowing up if it does.
       }
@@ -170,9 +170,14 @@
           return false;
         }
       } else {
-        return in.getKind().isInterface();
-        // Method mI in or inherited by interface I (JLS 9.4.1.1). We've already checked everything.
+        // Method mI in or inherited by interface I (JLS 9.4.1.1). We've already checked everything,
+        // except that `overrider` must also be in a subinterface of `overridden`.
         // If this is not an interface then we don't know what it is so we say no.
+        TypeElement overriderType = MoreElements.asType(overrider.getEnclosingElement());
+        return in.getKind().isInterface()
+            && typeUtils.isSubtype(
+                typeUtils.erasure(overriderType.asType()),
+                typeUtils.erasure(overriddenType.asType()));
       }
     }
 
diff --git a/common/src/main/java/com/google/auto/common/Visibility.java b/common/src/main/java/com/google/auto/common/Visibility.java
index 36f4ad6..db15f8b 100644
--- a/common/src/main/java/com/google/auto/common/Visibility.java
+++ b/common/src/main/java/com/google/auto/common/Visibility.java
@@ -16,10 +16,10 @@
 package com.google.auto.common;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Comparators.min;
 import static javax.lang.model.element.ElementKind.PACKAGE;
 
 import com.google.common.base.Enums;
+import com.google.common.collect.Ordering;
 import java.util.Set;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
@@ -77,7 +77,9 @@
     Visibility effectiveVisibility = PUBLIC;
     Element currentElement = element;
     while (currentElement != null) {
-      effectiveVisibility = min(effectiveVisibility, ofElement(currentElement));
+      // NOTE: We don't use Guava's Comparators.min() because that requires Guava 30, which would
+      // make this library unusable in annotation processors using Bazel < 5.0.
+      effectiveVisibility = Ordering.natural().min(effectiveVisibility, ofElement(currentElement));
       currentElement = currentElement.getEnclosingElement();
     }
     return effectiveVisibility;
diff --git a/common/src/test/java/com/google/auto/common/AnnotationMirrorsTest.java b/common/src/test/java/com/google/auto/common/AnnotationMirrorsTest.java
index b1dfe3b..83494a8 100644
--- a/common/src/test/java/com/google/auto/common/AnnotationMirrorsTest.java
+++ b/common/src/test/java/com/google/auto/common/AnnotationMirrorsTest.java
@@ -296,6 +296,73 @@
         AnnotationMirrors.getAnnotatedAnnotations(element, annotatingAnnotationElement));
   }
 
+  @Test
+  public void toSourceString() {
+    assertThat(AnnotationMirrors.toString(annotationOn(AlsoSimplyAnnotated.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.SimpleAnnotation");
+    assertThat(AnnotationMirrors.toString(annotationOn(SimplyAnnotated.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.SimpleAnnotation");
+    assertThat(AnnotationMirrors.toString(annotationOn(StringySet.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.Stringy(\"foo\")");
+    assertThat(AnnotationMirrors.toString(annotationOn(StringyUnset.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.Stringy");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestBlahNestedAnnotated.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.AnnotatedOuter(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH))");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestClassBlah2.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.Outer(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestClassBlah.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.Outer(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestClassFoo.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.Outer(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestDefaultNestedAnnotated.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.AnnotatedOuter(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestFooNestedAnnotated.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.AnnotatedOuter(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO))");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithBlahFoo.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray({@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH),"
+                + " @com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO)})");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithDefault.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithEmpty.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray({})");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithFooAndDefaultBlah.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray({@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO),"
+                + " @com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter})");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithFooBlah2.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray({@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO),"
+                + " @com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH)})");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithFooBlah.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray({@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO),"
+                + " @com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH)})");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithOneBlah.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH))");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithOneDefault.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestValueArrayWithOneFoo.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.OuterWithValueArray(@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO))");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestWithDefaultingOuterBlah.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.BLAH)");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestWithDefaultingOuterDefault.class)))
+        .isEqualTo("@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter");
+    assertThat(AnnotationMirrors.toString(annotationOn(TestWithDefaultingOuterFoo.class)))
+        .isEqualTo(
+            "@com.google.auto.common.AnnotationMirrorsTest.DefaultingOuter(com.google.auto.common.AnnotationMirrorsTest.SimpleEnum.FOO)");
+  }
+
   private void getAnnotatedAnnotationsAsserts(
       ImmutableSet<? extends AnnotationMirror> annotatedAnnotations) {
     assertThat(annotatedAnnotations)
diff --git a/common/src/test/java/com/google/auto/common/AnnotationValuesTest.java b/common/src/test/java/com/google/auto/common/AnnotationValuesTest.java
index 825c85a..c6997b2 100644
--- a/common/src/test/java/com/google/auto/common/AnnotationValuesTest.java
+++ b/common/src/test/java/com/google/auto/common/AnnotationValuesTest.java
@@ -17,8 +17,10 @@
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.common.truth.Truth.assertThat;
+import static java.util.stream.Collectors.joining;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.truth.Correspondence;
 import com.google.testing.compile.CompilationRule;
 import javax.lang.model.element.AnnotationMirror;
@@ -344,6 +346,66 @@
     assertThat(AnnotationValues.getChars(value)).containsExactly('b', 'c').inOrder();
   }
 
+  @Test
+  public void toSourceString() {
+    ImmutableMap<String, String> inputs =
+        ImmutableMap.<String, String>builder()
+            .put("classValue", "com.google.auto.common.AnnotationValuesTest.InsideClassA.class")
+            .put(
+                "classValues",
+                "{com.google.auto.common.AnnotationValuesTest.InsideClassA.class,"
+                    + " com.google.auto.common.AnnotationValuesTest.InsideClassB.class}")
+            .put(
+                "genericClassValue",
+                "com.google.auto.common.AnnotationValuesTest.GenericClass.class")
+            .put(
+                "insideAnnotationValue",
+                "@com.google.auto.common.AnnotationValuesTest.InsideAnnotation(19)")
+            .put(
+                "insideAnnotationValues",
+                "{@com.google.auto.common.AnnotationValuesTest.InsideAnnotation(20),"
+                    + " @com.google.auto.common.AnnotationValuesTest.InsideAnnotation(21)}")
+            .put("stringValue", "\"hello\"")
+            .put("stringValues", "{\"it\\'s\", \"me\"}")
+            .put("enumValue", "com.google.auto.common.AnnotationValuesTest.Foo.BAR")
+            .put(
+                "enumValues",
+                "{com.google.auto.common.AnnotationValuesTest.Foo.BAZ,"
+                    + " com.google.auto.common.AnnotationValuesTest.Foo.BAH}")
+            .put("intValue", "5")
+            .put("intValues", "{1, 2}")
+            .put("longValue", "6L")
+            .put("longValues", "{3L, 4L}")
+            .put("byteValue", "(byte) 7")
+            .put("byteValues", "{(byte) 8, (byte) 9}")
+            .put("shortValue", "(short) 10")
+            .put("shortValues", "{(short) 11, (short) 12}")
+            .put("floatValue", "13.0F")
+            .put("floatValues", "{14.0F, 15.0F}")
+            .put("doubleValue", "16.0")
+            .put("doubleValues", "{17.0, 18.0}")
+            .put("booleanValue", "true")
+            .put("booleanValues", "{true, false}")
+            .put("charValue", "'a'")
+            .put("charValues", "{'b', 'c'}")
+            .build();
+    inputs.forEach(
+        (name, expected) ->
+            assertThat(
+                    AnnotationValues.toString(
+                        AnnotationMirrors.getAnnotationValue(annotationMirror, name)))
+                .isEqualTo(expected));
+    assertThat(AnnotationMirrors.toString(annotationMirror))
+        .isEqualTo(
+            inputs.entrySet().stream()
+                .map(e -> e.getKey() + " = " + e.getValue())
+                .collect(
+                    joining(
+                        ", ",
+                        "@com.google.auto.common.AnnotationValuesTest.MultiValueAnnotation(",
+                        ")")));
+  }
+
   private TypeElement getTypeElement(Class<?> clazz) {
     return elements.getTypeElement(clazz.getCanonicalName());
   }
diff --git a/common/src/test/java/com/google/auto/common/MoreElementsTest.java b/common/src/test/java/com/google/auto/common/MoreElementsTest.java
index b98b79b..eaa504a 100644
--- a/common/src/test/java/com/google/auto/common/MoreElementsTest.java
+++ b/common/src/test/java/com/google/auto/common/MoreElementsTest.java
@@ -388,40 +388,6 @@
         .inOrder();
   }
 
-  static class Injectable {}
-
-  public static class MenuManager {
-    public interface ParentComponent extends MenuItemA.ParentComponent, MenuItemB.ParentComponent {}
-  }
-
-  public static class MenuItemA {
-    public interface ParentComponent {
-      Injectable injectable();
-    }
-  }
-
-  public static class MenuItemB {
-    public interface ParentComponent {
-      Injectable injectable();
-    }
-  }
-
-  public static class Main {
-    public interface ParentComponent extends MenuManager.ParentComponent {}
-  }
-
-  // Example from https://github.com/williamlian/daggerbug
-  @Test
-  public void getLocalAndInheritedMethods_DaggerBug() {
-    TypeElement main = elements.getTypeElement(Main.ParentComponent.class.getCanonicalName());
-    Set<ExecutableElement> methods =
-        MoreElements.getLocalAndInheritedMethods(main, compilation.getTypes(), elements);
-    assertThat(methods).hasSize(1);
-    ExecutableElement method = methods.iterator().next();
-    assertThat(method.getSimpleName().toString()).isEqualTo("injectable");
-    assertThat(method.getParameters()).isEmpty();
-  }
-
   private Set<ExecutableElement> visibleMethodsFromObject() {
     Types types = compilation.getTypes();
     TypeMirror intMirror = types.getPrimitiveType(TypeKind.INT);
diff --git a/common/src/test/java/com/google/auto/common/OverridesTest.java b/common/src/test/java/com/google/auto/common/OverridesTest.java
index c5ccc5f..8d77fc7 100644
--- a/common/src/test/java/com/google/auto/common/OverridesTest.java
+++ b/common/src/test/java/com/google/auto/common/OverridesTest.java
@@ -79,8 +79,8 @@
 @RunWith(Parameterized.class)
 public class OverridesTest {
   @Parameterized.Parameters(name = "{0}")
-  public static ImmutableList<CompilerType> data() {
-    return ImmutableList.of(CompilerType.JAVAC, CompilerType.ECJ);
+  public static CompilerType[] data() {
+    return CompilerType.values();
   }
 
   @Rule public CompilationRule compilation = new CompilationRule();
@@ -133,12 +133,16 @@
       void m(String x);
 
       void n();
+
+      Number number();
     }
 
     interface Two {
       void m();
 
       void m(int x);
+
+      Integer number();
     }
 
     static class Parent {
@@ -156,6 +160,11 @@
 
       @Override
       public void n() {}
+
+      @Override
+      public Number number() {
+        return 0;
+      }
     }
 
     static class ChildOfOneAndTwo implements One, Two {
@@ -170,6 +179,11 @@
 
       @Override
       public void n() {}
+
+      @Override
+      public Integer number() {
+        return 0;
+      }
     }
 
     static class ChildOfParentAndOne extends Parent implements One {
@@ -181,6 +195,11 @@
 
       @Override
       public void n() {}
+
+      @Override
+      public Number number() {
+        return 0;
+      }
     }
 
     static class ChildOfParentAndOneAndTwo extends Parent implements One, Two {
@@ -192,6 +211,11 @@
 
       @Override
       public void n() {}
+
+      @Override
+      public Integer number() {
+        return 0;
+      }
     }
 
     abstract static class AbstractChildOfOne implements One {}
@@ -199,6 +223,8 @@
     abstract static class AbstractChildOfOneAndTwo implements One, Two {}
 
     abstract static class AbstractChildOfParentAndOneAndTwo extends Parent implements One, Two {}
+
+    interface ExtendingOneAndTwo extends One, Two {}
   }
 
   static class MoreTypesForInheritance {
diff --git a/factory/pom.xml b/factory/pom.xml
index 629223a..922cdba 100644
--- a/factory/pom.xml
+++ b/factory/pom.xml
@@ -19,12 +19,6 @@
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.sonatype.oss</groupId>
-    <artifactId>oss-parent</artifactId>
-    <version>7</version>
-  </parent>
-
   <groupId>com.google.auto.factory</groupId>
   <artifactId>auto-factory</artifactId>
   <version>HEAD-SNAPSHOT</version>
@@ -36,10 +30,10 @@
 
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <auto-service.version>1.0</auto-service.version>
-    <auto-value.version>1.8.1</auto-value.version>
+    <auto-service.version>1.0.1</auto-service.version>
+    <auto-value.version>1.8.2</auto-value.version>
     <java.version>1.8</java.version>
-    <guava.version>30.1.1-jre</guava.version>
+    <guava.version>31.0.1-jre</guava.version>
     <truth.version>1.1.3</truth.version>
   </properties>
 
@@ -67,11 +61,24 @@
     <url>http://www.google.com</url>
   </organization>
 
+  <distributionManagement>
+    <snapshotRepository>
+      <id>sonatype-nexus-snapshots</id>
+      <name>Sonatype Nexus Snapshots</name>
+      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+    </snapshotRepository>
+    <repository>
+      <id>sonatype-nexus-staging</id>
+      <name>Nexus Release Repository</name>
+      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+    </repository>
+  </distributionManagement>
+
   <dependencies>
     <dependency>
       <groupId>com.google.auto</groupId>
       <artifactId>auto-common</artifactId>
-      <version>1.1</version>
+      <version>1.2.1</version>
     </dependency>
     <dependency>
       <groupId>com.google.auto.value</groupId>
@@ -170,7 +177,7 @@
           <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-java</artifactId>
-            <version>1.0.7</version>
+            <version>1.1.0</version>
           </dependency>
         </dependencies>
       </plugin>
diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
index b7f9c3e..8d6027d 100644
--- a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
+++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
@@ -29,6 +29,7 @@
 
 import com.google.auto.common.AnnotationMirrors;
 import com.google.auto.common.AnnotationValues;
+import com.google.auto.common.MoreTypes;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
@@ -59,6 +60,7 @@
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.type.TypeVariable;
@@ -338,9 +340,28 @@
     for (ProviderField provider : descriptor.providers().values()) {
       typeVariables.addAll(getReferencedTypeParameterNames(provider.key().type().get()));
     }
+    // If a parent type has a type parameter, like FooFactory<T>, then the generated factory needs
+    // to have the same parameter, like FooImplFactory<T> extends FooFactory<T>. This is a little
+    // approximate, at least in the case where there is more than one parent type that has a type
+    // parameter. But that should be pretty rare, so let's keep it simple for now.
+    typeVariables.addAll(typeVariablesFrom(descriptor.extendingType()));
+    for (TypeMirror implementing : descriptor.implementingTypes()) {
+      typeVariables.addAll(typeVariablesFrom(implementing));
+    }
     return typeVariables.build();
   }
 
+  private static List<TypeVariableName> typeVariablesFrom(TypeMirror type) {
+    if (type.getKind().equals(TypeKind.DECLARED)) {
+      DeclaredType declaredType = MoreTypes.asDeclared(type);
+      return declaredType.getTypeArguments().stream()
+          .filter(t -> t.getKind().equals(TypeKind.TYPEVAR))
+          .map(t -> TypeVariableName.get(MoreTypes.asTypeVariable(t)))
+          .collect(toList());
+    }
+    return ImmutableList.of();
+  }
+
   private static ImmutableSet<TypeVariableName> getMethodTypeVariables(
       FactoryMethodDescriptor methodDescriptor,
       ImmutableSet<TypeVariableName> factoryTypeVariables) {
diff --git a/factory/src/main/java/com/google/auto/factory/processor/Key.java b/factory/src/main/java/com/google/auto/factory/processor/Key.java
index 728149e..6dc7644 100644
--- a/factory/src/main/java/com/google/auto/factory/processor/Key.java
+++ b/factory/src/main/java/com/google/auto/factory/processor/Key.java
@@ -97,7 +97,7 @@
   public final String toString() {
     String typeQualifiedName = MoreTypes.asTypeElement(type().get()).toString();
     return qualifier().isPresent()
-        ? qualifier().get() + "/" + typeQualifiedName
+        ? AnnotationMirrors.toString(qualifier().get()) + "/" + typeQualifiedName
         : typeQualifiedName;
   }
 }
diff --git a/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java b/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java
index 0df4c9c..2ab0fe9 100644
--- a/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java
+++ b/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java
@@ -508,6 +508,22 @@
         .hasSourceEquivalentTo(loadExpectedFile("expected/DefaultPackageFactory.java"));
   }
 
+  @Test
+  public void generics() {
+    JavaFileObject file = JavaFileObjects.forResource("good/Generics.java");
+    Compilation compilation = javac.compile(file);
+    assertThat(compilation).succeededWithoutWarnings();
+    assertThat(compilation)
+        .generatedSourceFile("tests.Generics_FooImplFactory")
+        .hasSourceEquivalentTo(loadExpectedFile("expected/Generics_FooImplFactory.java"));
+    assertThat(compilation)
+        .generatedSourceFile("tests.Generics_ExplicitFooImplFactory")
+        .hasSourceEquivalentTo(loadExpectedFile("expected/Generics_ExplicitFooImplFactory.java"));
+    assertThat(compilation)
+        .generatedSourceFile("tests.Generics_FooImplWithClassFactory")
+        .hasSourceEquivalentTo(loadExpectedFile("expected/Generics_FooImplWithClassFactory.java"));
+  }
+
   private JavaFileObject loadExpectedFile(String resourceName) {
     if (isJavaxAnnotationProcessingGeneratedAvailable()) {
       return JavaFileObjects.forResource(resourceName);
diff --git a/factory/src/test/resources/expected/Generics_ExplicitFooImplFactory.java b/factory/src/test/resources/expected/Generics_ExplicitFooImplFactory.java
new file mode 100644
index 0000000..00c6d92
--- /dev/null
+++ b/factory/src/test/resources/expected/Generics_ExplicitFooImplFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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 tests;
+
+import javax.annotation.processing.Generated;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+@Generated(
+    value = "com.google.auto.factory.processor.AutoFactoryProcessor",
+    comments = "https://github.com/google/auto/tree/master/factory"
+    )
+final class Generics_ExplicitFooImplFactory<M extends Generics.Bar>
+    implements Generics.FooFactory<M> {
+  private final Provider<M> unusedProvider;
+
+  @Inject
+  Generics_ExplicitFooImplFactory(Provider<M> unusedProvider) {
+    this.unusedProvider = checkNotNull(unusedProvider, 1);
+  }
+
+  @Override
+  public Generics.ExplicitFooImpl<M> create() {
+    return new Generics.ExplicitFooImpl<M>(checkNotNull(unusedProvider.get(), 1));
+  }
+
+  private static <T> T checkNotNull(T reference, int argumentIndex) {
+    if (reference == null) {
+      throw new NullPointerException(
+          "@AutoFactory method argument is null but is not marked @Nullable. Argument index: "
+              + argumentIndex);
+    }
+    return reference;
+  }
+}
diff --git a/factory/src/test/resources/expected/Generics_FooImplFactory.java b/factory/src/test/resources/expected/Generics_FooImplFactory.java
new file mode 100644
index 0000000..2fb560a
--- /dev/null
+++ b/factory/src/test/resources/expected/Generics_FooImplFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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 tests;
+
+import javax.annotation.processing.Generated;
+import javax.inject.Inject;
+
+@Generated(
+    value = "com.google.auto.factory.processor.AutoFactoryProcessor",
+    comments = "https://github.com/google/auto/tree/master/factory"
+    )
+final class Generics_FooImplFactory<M extends Generics.Bar> implements Generics.FooFactory<M> {
+  @Inject
+  Generics_FooImplFactory() {
+  }
+
+  @Override
+  public Generics.FooImpl<M> create() {
+    return new Generics.FooImpl<M>();
+  }
+}
diff --git a/factory/src/test/resources/expected/Generics_FooImplWithClassFactory.java b/factory/src/test/resources/expected/Generics_FooImplWithClassFactory.java
new file mode 100644
index 0000000..b338454
--- /dev/null
+++ b/factory/src/test/resources/expected/Generics_FooImplWithClassFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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 tests;
+
+import javax.annotation.processing.Generated;
+import javax.inject.Inject;
+
+@Generated(
+    value = "com.google.auto.factory.processor.AutoFactoryProcessor",
+    comments = "https://github.com/google/auto/tree/master/factory"
+    )
+final class Generics_FooImplWithClassFactory<M extends Generics.Bar> extends Generics.FooFactoryClass<M> {
+  @Inject
+  Generics_FooImplWithClassFactory() {
+  }
+
+  @Override
+  public Generics.FooImplWithClass<M> create() {
+    return new Generics.FooImplWithClass<M>();
+  }
+}
diff --git a/factory/src/test/resources/good/Generics.java b/factory/src/test/resources/good/Generics.java
new file mode 100644
index 0000000..638302f
--- /dev/null
+++ b/factory/src/test/resources/good/Generics.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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 tests;
+
+import com.google.auto.factory.AutoFactory;
+import com.google.auto.factory.Provided;
+
+class Generics {
+  interface Bar {}
+
+  interface Foo<M extends Bar> {}
+
+  interface FooFactory<M extends Bar> {
+    Foo<M> create();
+  }
+
+  // The generated FooImplFactory should also have an <M extends Bar> type parameter, so we can
+  // have FooImplFactory<M extends Bar> implements FooFactory<M>.
+  @AutoFactory(implementing = FooFactory.class)
+  static final class FooImpl<M extends Bar> implements Foo<M> {
+    FooImpl() {}
+  }
+
+  // The generated ExplicitFooImplFactory should have an <M extends Bar> type parameter, which
+  // serves both for FooFactory<M> and for Provider<M> in the constructor.
+  @AutoFactory(implementing = FooFactory.class)
+  static final class ExplicitFooImpl<M extends Bar> implements Foo<M> {
+    ExplicitFooImpl(@Provided M unused) {}
+  }
+
+  abstract static class FooFactoryClass<M extends Bar> {
+    abstract Foo<M> create();
+  }
+
+  @AutoFactory(extending = FooFactoryClass.class)
+  static final class FooImplWithClass<M extends Bar> implements Foo<M> {}
+}
diff --git a/service/pom.xml b/service/pom.xml
index e29bdc3..f306885 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -37,7 +37,7 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <java.version>1.8</java.version>
-    <guava.version>30.1.1-jre</guava.version>
+    <guava.version>31.0.1-jre</guava.version>
     <truth.version>1.1.3</truth.version>
   </properties>
 
@@ -123,7 +123,7 @@
             <dependency>
               <groupId>org.codehaus.plexus</groupId>
               <artifactId>plexus-java</artifactId>
-              <version>1.0.7</version>
+              <version>1.1.0</version>
             </dependency>
           </dependencies>
         </plugin>
diff --git a/service/processor/pom.xml b/service/processor/pom.xml
index 262493a..cef19ad 100644
--- a/service/processor/pom.xml
+++ b/service/processor/pom.xml
@@ -49,7 +49,7 @@
     <dependency>
       <groupId>com.google.auto</groupId>
       <artifactId>auto-common</artifactId>
-      <version>1.1</version>
+      <version>1.2.1</version>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
diff --git a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
index f12299a..85a24cb 100644
--- a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
+++ b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java
@@ -25,12 +25,15 @@
 import com.google.auto.service.AutoService;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -68,6 +71,8 @@
   @VisibleForTesting
   static final String MISSING_SERVICES_ERROR = "No service interfaces provided for element!";
 
+  private final List<String> exceptionStacks = Collections.synchronizedList(new ArrayList<>());
+
   /**
    * Maps the class names of service provider interfaces to the
    * class names of the concrete classes which implement them.
@@ -109,11 +114,17 @@
       processImpl(annotations, roundEnv);
     } catch (RuntimeException e) {
       // We don't allow exceptions of any kind to propagate to the compiler
-      fatalError(getStackTraceAsString(e));
+      String trace = getStackTraceAsString(e);
+      exceptionStacks.add(trace);
+      fatalError(trace);
     }
     return false;
   }
 
+  ImmutableList<String> exceptionStacks() {
+    return ImmutableList.copyOf(exceptionStacks);
+  }
+
   private void processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
     if (roundEnv.processingOver()) {
       generateConfigFiles();
@@ -291,7 +302,7 @@
   private ImmutableSet<DeclaredType> getValueFieldOfClasses(AnnotationMirror annotationMirror) {
     return getAnnotationValue(annotationMirror, "value")
         .accept(
-            new SimpleAnnotationValueVisitor8<ImmutableSet<DeclaredType>, Void>() {
+            new SimpleAnnotationValueVisitor8<ImmutableSet<DeclaredType>, Void>(ImmutableSet.of()) {
               @Override
               public ImmutableSet<DeclaredType> visitType(TypeMirror typeMirror, Void v) {
                 // TODO(ronshapiro): class literals may not always be declared types, i.e.
diff --git a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
index 3561568..7a176dd 100644
--- a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
+++ b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java
@@ -17,6 +17,7 @@
 
 import static com.google.auto.service.processor.AutoServiceProcessor.MISSING_SERVICES_ERROR;
 import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.io.Resources;
 import com.google.testing.compile.Compilation;
@@ -144,4 +145,18 @@
         .contentsAsUtf8String()
         .isEqualTo("test.EnclosingGeneric$GenericServiceProvider\n");
   }
+
+  @Test
+  public void missing() {
+    AutoServiceProcessor processor = new AutoServiceProcessor();
+    Compilation compilation =
+        Compiler.javac()
+            .withProcessors(processor)
+            .withOptions("-Averify=true")
+            .compile(
+                JavaFileObjects.forResource(
+                    "test/GenericServiceProviderWithMissingServiceClass.java"));
+    assertThat(compilation).failed();
+    assertThat(processor.exceptionStacks()).isEmpty();
+  }
 }
diff --git a/service/processor/src/test/resources/test/GenericServiceProviderWithMissingServiceClass.java b/service/processor/src/test/resources/test/GenericServiceProviderWithMissingServiceClass.java
new file mode 100644
index 0000000..3ca3445
--- /dev/null
+++ b/service/processor/src/test/resources/test/GenericServiceProviderWithMissingServiceClass.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * 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 test;
+
+import com.google.auto.service.AutoService;
+
+/**
+ * A service that references a missing class. This is useful for testing that the processor behaves
+ * correctly.
+ */
+@AutoService(MissingServiceClass.class)
+public class GenericServiceProviderWithMissingServiceClass<T> implements MissingServiceClass<T> {}
diff --git a/value/annotations/pom.xml b/value/annotations/pom.xml
index 8bc63ac..4fc183b 100644
--- a/value/annotations/pom.xml
+++ b/value/annotations/pom.xml
@@ -21,15 +21,14 @@
   <parent>
     <groupId>com.google.auto.value</groupId>
     <artifactId>auto-value-parent</artifactId>
-    <version>1.7.4</version>
+    <version>HEAD-SNAPSHOT</version>
   </parent>
 
-  <groupId>com.google.auto.value</groupId>
   <artifactId>auto-value-annotations</artifactId>
-  <version>1.7.4</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>AutoValue Annotations</name>
   <description>
-    Immutable value-type code generation for Java 1.6+.
+    Immutable value-type code generation for Java 1.7+.
   </description>
   <url>https://github.com/google/auto/tree/master/value</url>
 
diff --git a/value/pom.xml b/value/pom.xml
index 5405c7c..8b1e238 100644
--- a/value/pom.xml
+++ b/value/pom.xml
@@ -18,15 +18,9 @@
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.sonatype.oss</groupId>
-    <artifactId>oss-parent</artifactId>
-    <version>7</version>
-  </parent>
-
   <groupId>com.google.auto.value</groupId>
   <artifactId>auto-value-parent</artifactId>
-  <version>1.7.4</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>AutoValue Parent</name>
   <description>
     Immutable value-type code generation for Java 7+.
@@ -37,7 +31,7 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <java.version>1.8</java.version>
-    <guava.version>30.1.1-jre</guava.version>
+    <guava.version>31.0.1-jre</guava.version>
     <truth.version>1.1.3</truth.version>
   </properties>
 
@@ -65,6 +59,21 @@
     <url>http://www.google.com</url>
   </organization>
 
+  <developers>
+    <developer>
+      <id>eamonnmcmanus</id>
+      <name>Éamonn McManus</name>
+      <email>emcmanus@google.com</email>
+      <organization>Google</organization>
+      <organizationUrl>http://www.google.com</organizationUrl>
+      <roles>
+        <role>owner</role>
+        <role>developer</role>
+      </roles>
+      <timezone>-8</timezone>
+    </developer>
+  </developers>
+
   <modules>
     <module>annotations</module>
     <module>processor</module>
@@ -72,6 +81,19 @@
     <module>src/it/gwtserializer</module>
   </modules>
 
+  <distributionManagement>
+    <snapshotRepository>
+      <id>sonatype-nexus-snapshots</id>
+      <name>Sonatype Nexus Snapshots</name>
+      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+    </snapshotRepository>
+    <repository>
+      <id>sonatype-nexus-staging</id>
+      <name>Nexus Release Repository</name>
+      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+    </repository>
+  </distributionManagement>
+
   <dependencyManagement>
     <dependencies>
       <!-- main dependencies -->
@@ -150,7 +172,7 @@
             <dependency>
               <groupId>org.codehaus.plexus</groupId>
               <artifactId>plexus-java</artifactId>
-              <version>1.0.7</version>
+              <version>1.1.0</version>
             </dependency>
           </dependencies>
         </plugin>
@@ -189,4 +211,56 @@
       </plugins>
     </pluginManagement>
   </build>
+  <profiles>
+    <profile>
+      <id>sonatype-oss-release</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>3.2.1</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar-no-fork</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>3.3.1</version>
+            <configuration>
+              <failOnError>false</failOnError>
+            </configuration>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>3.0.1</version>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>
diff --git a/value/processor/pom.xml b/value/processor/pom.xml
index 8892c4f..b00457d 100644
--- a/value/processor/pom.xml
+++ b/value/processor/pom.xml
@@ -21,15 +21,14 @@
   <parent>
     <groupId>com.google.auto.value</groupId>
     <artifactId>auto-value-parent</artifactId>
-    <version>1.7.4</version>
+    <version>HEAD-SNAPSHOT</version>
   </parent>
 
-  <groupId>com.google.auto.value</groupId>
   <artifactId>auto-value</artifactId>
-  <version>1.7.4</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>AutoValue Processor</name>
   <description>
-    Immutable value-type code generation for Java 1.6+.
+    Immutable value-type code generation for Java 1.7+.
   </description>
   <url>https://github.com/google/auto/tree/master/value</url>
 
@@ -41,15 +40,15 @@
   </scm>
 
   <properties>
-    <auto-service.version>1.0</auto-service.version>
-    <errorprone.version>2.7.1</errorprone.version>
+    <auto-service.version>1.0.1</auto-service.version>
+    <errorprone.version>2.10.0</errorprone.version>
   </properties>
 
   <dependencies>
     <dependency>
       <groupId>com.google.auto</groupId>
       <artifactId>auto-common</artifactId>
-      <version>1.1</version>
+      <version>1.2.1</version>
     </dependency>
     <dependency>
       <groupId>com.google.auto.service</groupId>
@@ -125,7 +124,7 @@
     <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
-       <version>3.11.2</version>
+       <version>4.1.0</version>
        <scope>test</scope>
      </dependency>
   </dependencies>
diff --git a/value/src/it/functional/pom.xml b/value/src/it/functional/pom.xml
index d4ae138..18f3718 100644
--- a/value/src/it/functional/pom.xml
+++ b/value/src/it/functional/pom.xml
@@ -22,17 +22,17 @@
   <parent>
     <groupId>com.google.auto.value</groupId>
     <artifactId>auto-value-parent</artifactId>
-    <version>1.7.4</version>
+    <version>HEAD-SNAPSHOT</version>
     <relativePath>../../../pom.xml</relativePath>
   </parent>
   <url>https://github.com/google/auto/tree/master/value</url>
 
   <groupId>com.google.auto.value.it.functional</groupId>
   <artifactId>functional</artifactId>
-  <version>1.7.4</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>Auto-Value Functional Integration Test</name>
   <properties>
-    <kotlin.version>1.5.21</kotlin.version>
+    <kotlin.version>1.6.0</kotlin.version>
     <exclude.tests>this-matches-nothing</exclude.tests>
   </properties>
   <dependencies>
@@ -49,7 +49,7 @@
     <dependency>
       <groupId>com.google.auto.service</groupId>
       <artifactId>auto-service</artifactId>
-      <version>1.0</version>
+      <version>1.0.1</version>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
@@ -93,13 +93,13 @@
     <dependency>
       <groupId>dev.gradleplugins</groupId>
       <artifactId>gradle-test-kit</artifactId>
-      <version>6.8.3</version>
+      <version>7.3</version>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
-      <version>3.11.2</version>
+      <version>4.1.0</version>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -166,7 +166,7 @@
           <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-java</artifactId>
-            <version>1.0.7</version>
+            <version>1.1.0</version>
           </dependency>
         </dependencies>
         <configuration>
@@ -176,7 +176,6 @@
             <arg>-Xlint:all</arg>
             <arg>-encoding</arg>
             <arg>utf8</arg>
-            <arg>-Acom.google.auto.value.AutoBuilderIsUnstable</arg>
           </compilerArgs>
           <showWarnings>true</showWarnings>
           <showDeprecation>true</showDeprecation>
@@ -221,7 +220,7 @@
               <dependency>
                 <groupId>org.codehaus.plexus</groupId>
                 <artifactId>plexus-java</artifactId>
-                <version>1.0.7</version>
+                <version>1.1.0</version>
               </dependency>
             </dependencies>
             <configuration>
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java
index 952edaa..dba8199 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoBuilderTest.java
@@ -149,6 +149,12 @@
     return new AutoAnnotation_AutoBuilderTest_myAnnotation(value, truthiness);
   }
 
+  // This method has parameters for all the annotation elements.
+  @AutoAnnotation
+  static MyAnnotation myAnnotationAll(String value, int id, Truthiness truthiness) {
+    return new AutoAnnotation_AutoBuilderTest_myAnnotationAll(value, id, truthiness);
+  }
+
   @AutoBuilder(callMethod = "myAnnotation")
   interface MyAnnotationBuilder {
     MyAnnotationBuilder value(String x);
@@ -159,12 +165,28 @@
   }
 
   static MyAnnotationBuilder myAnnotationBuilder() {
-    return new AutoBuilder_AutoBuilderTest_MyAnnotationBuilder()
-        .truthiness(MyAnnotation.DEFAULT_TRUTHINESS);
+    return new AutoBuilder_AutoBuilderTest_MyAnnotationBuilder();
+  }
+
+  @AutoBuilder(callMethod = "myAnnotationAll")
+  interface MyAnnotationAllBuilder {
+    MyAnnotationAllBuilder value(String x);
+
+    MyAnnotationAllBuilder id(int x);
+
+    MyAnnotationAllBuilder truthiness(Truthiness x);
+
+    MyAnnotation build();
+  }
+
+  static MyAnnotationAllBuilder myAnnotationAllBuilder() {
+    return new AutoBuilder_AutoBuilderTest_MyAnnotationAllBuilder();
   }
 
   @Test
   public void simpleAutoAnnotation() {
+    // We haven't supplied a value for `truthiness`, so AutoBuilder should use the default one in
+    // the annotation.
     MyAnnotation annotation1 = myAnnotationBuilder().value("foo").build();
     assertThat(annotation1.value()).isEqualTo("foo");
     assertThat(annotation1.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
@@ -174,6 +196,15 @@
     assertThat(annotation2.value()).isEqualTo("bar");
     assertThat(annotation2.id()).isEqualTo(MyAnnotation.DEFAULT_ID);
     assertThat(annotation2.truthiness()).isEqualTo(Truthiness.TRUTHY);
+
+    MyAnnotation annotation3 = myAnnotationAllBuilder().value("foo").build();
+    MyAnnotation annotation4 =
+        myAnnotationAllBuilder()
+            .value("foo")
+            .id(MyAnnotation.DEFAULT_ID)
+            .truthiness(MyAnnotation.DEFAULT_TRUTHINESS)
+            .build();
+    assertThat(annotation3).isEqualTo(annotation4);
   }
 
   static class Overload {
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
index 3a7e7bc..fd87b3e 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueTest.java
@@ -3623,4 +3623,48 @@
     } catch (IllegalStateException expected) {
     }
   }
+
+  @AutoValue
+  public abstract static class Stepped {
+    public abstract String one();
+
+    public abstract int two();
+
+    public abstract double three();
+
+    public interface StepOne<T> {
+      StepTwo setOne(T x);
+    }
+
+    public interface StepTwo {
+      StepThree setTwo(int x);
+    }
+
+    public interface StepThree {
+      Stepped setThreeAndBuild(double x);
+    }
+
+    public static StepOne<String> builder() {
+      return new AutoValue_AutoValueTest_Stepped.Builder();
+    }
+
+    @AutoValue.Builder
+    abstract static class Builder implements StepOne<String>, StepTwo, StepThree {
+      abstract Builder setThree(double x);
+      abstract Stepped build();
+
+      @Override
+      public Stepped setThreeAndBuild(double x) {
+        return setThree(x).build();
+      }
+    }
+  }
+
+  @Test
+  public void stepBuilder() {
+    Stepped stepped = Stepped.builder().setOne("one").setTwo(2).setThreeAndBuild(3.0);
+    assertThat(stepped.one()).isEqualTo("one");
+    assertThat(stepped.two()).isEqualTo(2);
+    assertThat(stepped.three()).isEqualTo(3.0);
+  }
 }
diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java b/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
index ca10fb4..5f08a72 100644
--- a/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
+++ b/value/src/it/functional/src/test/java/com/google/auto/value/CompileWithEclipseTest.java
@@ -127,8 +127,7 @@
             version,
             "-target",
             version,
-            "-warn:-warningToken,-intfAnnotation",
-            "-Acom.google.auto.value.AutoBuilderIsUnstable");
+            "-warn:-warningToken,-intfAnnotation");
     JavaCompiler.CompilationTask task =
         compiler.getTask(null, fileManager, null, options, null, sourceFileObjects);
     // Explicitly supply an empty list of extensions for AutoValueProcessor, because otherwise this
diff --git a/value/src/it/gwtserializer/pom.xml b/value/src/it/gwtserializer/pom.xml
index 42cc2fe..88bf677 100644
--- a/value/src/it/gwtserializer/pom.xml
+++ b/value/src/it/gwtserializer/pom.xml
@@ -22,14 +22,14 @@
   <parent>
     <groupId>com.google.auto.value</groupId>
     <artifactId>auto-value-parent</artifactId>
-    <version>1.7.4</version>
+    <version>HEAD-SNAPSHOT</version>
     <relativePath>../../../pom.xml</relativePath>
   </parent>
   <url>https://github.com/google/auto/tree/master/value</url>
 
   <groupId>com.google.auto.value.it.gwtserializer</groupId>
   <artifactId>gwtserializer</artifactId>
-  <version>1.7.4</version>
+  <version>HEAD-SNAPSHOT</version>
   <name>Auto-Value GWT-RPC Serialization Integration Test</name>
   <dependencyManagement>
     <dependencies>
@@ -99,7 +99,7 @@
           <dependency>
             <groupId>org.codehaus.plexus</groupId>
             <artifactId>plexus-java</artifactId>
-            <version>1.0.7</version>
+            <version>1.1.0</version>
           </dependency>
         </dependencies>
         <configuration>
diff --git a/value/src/main/java/com/google/auto/value/AutoAnnotation.java b/value/src/main/java/com/google/auto/value/AutoAnnotation.java
index d36d8e2..c6fab24 100644
--- a/value/src/main/java/com/google/auto/value/AutoAnnotation.java
+++ b/value/src/main/java/com/google/auto/value/AutoAnnotation.java
@@ -71,6 +71,39 @@
  * parameter corresponding to an array-valued annotation member, and the implementation of each such
  * member will also return a clone of the array.
  *
+ * <p>If your annotation has many elements, you may consider using {@code @AutoBuilder} to make it
+ * easier to construct instances. In that case, {@code default} values from the annotation will
+ * become default values for the parameters of the {@code @AutoAnnotation} method. For example:
+ *
+ * <pre>
+ * class Example {
+ *   {@code @interface} MyAnnotation {
+ *     String name() default "foo";
+ *     int number() default 23;
+ *   }
+ *
+ *   {@code @AutoAnnotation}
+ *   static MyAnnotation myAnnotation(String value) {
+ *     return new AutoAnnotation_Example_myAnnotation(value);
+ *   }
+ *
+ *   {@code @AutoBuilder(callMethod = "myAnnotation")}
+ *   interface MyAnnotationBuilder {
+ *     MyAnnotationBuilder name(String name);
+ *     MyAnnotationBuilder number(int number);
+ *     MyAnnotation build();
+ *   }
+ *
+ *   static MyAnnotationBuilder myAnnotationBuilder() {
+ *     return new AutoBuilder_Example_MyAnnotationBuilder();
+ *   }
+ * }
+ * </pre>
+ *
+ * Here, {@code myAnnotationBuilder().build()} is the same as {@code
+ * myAnnotationBuilder().name("foo").number(23).build()} because those are the defaults in the
+ * annotation definition.
+ *
  * @author emcmanus@google.com (Éamonn McManus)
  */
 @Target(ElementType.METHOD)
diff --git a/value/src/main/java/com/google/auto/value/processor/AnnotationOutput.java b/value/src/main/java/com/google/auto/value/processor/AnnotationOutput.java
index ed986ab..ed6abaa 100644
--- a/value/src/main/java/com/google/auto/value/processor/AnnotationOutput.java
+++ b/value/src/main/java/com/google/auto/value/processor/AnnotationOutput.java
@@ -15,6 +15,8 @@
  */
 package com.google.auto.value.processor;
 
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.processor.MissingTypes.MissingTypeException;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import java.util.List;
@@ -24,8 +26,10 @@
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.SimpleAnnotationValueVisitor8;
 import javax.tools.Diagnostic;
@@ -130,13 +134,13 @@
   private static class InitializerSourceFormVisitor extends SourceFormVisitor {
     private final ProcessingEnvironment processingEnv;
     private final String memberName;
-    private final Element context;
+    private final Element errorContext;
 
     InitializerSourceFormVisitor(
-        ProcessingEnvironment processingEnv, String memberName, Element context) {
+        ProcessingEnvironment processingEnv, String memberName, Element errorContext) {
       this.processingEnv = processingEnv;
       this.memberName = memberName;
-      this.context = context;
+      this.errorContext = errorContext;
     }
 
     @Override
@@ -148,7 +152,7 @@
               "@AutoAnnotation cannot yet supply a default value for annotation-valued member '"
                   + memberName
                   + "'",
-              context);
+              errorContext);
       sb.append("null");
       return null;
     }
@@ -209,9 +213,9 @@
       AnnotationValue annotationValue,
       ProcessingEnvironment processingEnv,
       String memberName,
-      Element context) {
+      Element errorContext) {
     SourceFormVisitor visitor =
-        new InitializerSourceFormVisitor(processingEnv, memberName, context);
+        new InitializerSourceFormVisitor(processingEnv, memberName, errorContext);
     StringBuilder sb = new StringBuilder();
     visitor.visit(annotationValue, sb);
     return sb.toString();
@@ -222,11 +226,59 @@
    * Java source file to reproduce the annotation in source form.
    */
   static String sourceFormForAnnotation(AnnotationMirror annotationMirror) {
+    // If a value in the annotation is a reference to a class constant and that class constant is
+    // undefined, javac unhelpfully converts it into a string "<error>" and visits that instead. We
+    // want to catch this case and defer processing to allow the class to be defined by another
+    // annotation processor. So we look for annotation elements whose type is Class but whose
+    // reported value is a string. Unfortunately we can't extract the ErrorType corresponding to the
+    // missing class portably. With javac, the AttributeValue is a
+    // com.sun.tools.javac.code.Attribute.UnresolvedClass, which has a public field classType that
+    // is the ErrorType we need, but obviously that's nonportable and fragile.
+    validateClassValues(annotationMirror);
     StringBuilder sb = new StringBuilder();
     new AnnotationSourceFormVisitor().visitAnnotation(annotationMirror, sb);
     return sb.toString();
   }
 
+  /**
+   * Throws an exception if this annotation contains a value for a Class element that is not
+   * actually a type. The assumption is that the value is the string {@code "<error>"} which javac
+   * presents when a Class value is an undefined type.
+   */
+  private static void validateClassValues(AnnotationMirror annotationMirror) {
+    // A class literal can appear in three places:
+    // * for an element of type Class, for example @SomeAnnotation(Foo.class);
+    // * for an element of type Class[], for example @SomeAnnotation({Foo.class, Bar.class});
+    // * inside a nested annotation, for example @SomeAnnotation(@Nested(Foo.class)).
+    // These three possibilities are the three branches of the if/else chain below.
+    annotationMirror
+        .getElementValues()
+        .forEach(
+            (method, value) -> {
+              TypeMirror type = method.getReturnType();
+              if (isJavaLangClass(type) && !(value.getValue() instanceof TypeMirror)) {
+                throw new MissingTypeException(null);
+              } else if (type.getKind().equals(TypeKind.ARRAY)
+                  && isJavaLangClass(MoreTypes.asArray(type).getComponentType())
+                  && value.getValue() instanceof List<?>) {
+                @SuppressWarnings("unchecked") // a List can only be a List<AnnotationValue> here
+                List<AnnotationValue> values = (List<AnnotationValue>) value.getValue();
+                if (values.stream().anyMatch(av -> !(av.getValue() instanceof TypeMirror))) {
+                  throw new MissingTypeException(null);
+                }
+              } else if (type.getKind().equals(TypeKind.DECLARED)
+                  && MoreTypes.asElement(type).getKind().equals(ElementKind.ANNOTATION_TYPE)
+                  && value.getValue() instanceof AnnotationMirror) {
+                validateClassValues((AnnotationMirror) value.getValue());
+              }
+            });
+  }
+
+  private static boolean isJavaLangClass(TypeMirror type) {
+    return type.getKind().equals(TypeKind.DECLARED)
+        && MoreTypes.asTypeElement(type).getQualifiedName().contentEquals("java.lang.Class");
+  }
+
   private static StringBuilder appendQuoted(StringBuilder sb, String s) {
     sb.append('"');
     for (int i = 0; i < s.length(); i++) {
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoAnnotationProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoAnnotationProcessor.java
index 3acf933..cc0e62e 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoAnnotationProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoAnnotationProcessor.java
@@ -287,7 +287,7 @@
   private String generatedClassName(ExecutableElement method) {
     TypeElement type = MoreElements.asType(method.getEnclosingElement());
     String name = type.getSimpleName().toString();
-    while (type.getEnclosingElement() instanceof TypeElement) {
+    while (MoreElements.isType(type.getEnclosingElement())) {
       type = MoreElements.asType(type.getEnclosingElement());
       name = type.getSimpleName() + "_" + name;
     }
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoBuilderProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoBuilderProcessor.java
index b6a578f..fc0d8b3 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoBuilderProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoBuilderProcessor.java
@@ -20,6 +20,7 @@
 import static com.google.auto.common.MoreStreams.toImmutableList;
 import static com.google.auto.common.MoreStreams.toImmutableSet;
 import static com.google.auto.value.processor.AutoValueProcessor.OMIT_IDENTIFIERS_OPTION;
+import static com.google.auto.value.processor.ClassNames.AUTO_ANNOTATION_NAME;
 import static com.google.auto.value.processor.ClassNames.AUTO_BUILDER_NAME;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toCollection;
@@ -38,6 +39,7 @@
 import com.google.common.base.Ascii;
 import com.google.common.base.VerifyException;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import java.lang.reflect.Field;
@@ -60,6 +62,7 @@
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
 import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType;
@@ -77,7 +80,7 @@
   private static final String ALLOW_OPTION = "com.google.auto.value.AutoBuilderIsUnstable";
 
   public AutoBuilderProcessor() {
-    super(AUTO_BUILDER_NAME);
+    super(AUTO_BUILDER_NAME, /* appliesToInterfaces= */ true);
   }
 
   @Override
@@ -95,21 +98,9 @@
 
   @Override
   void processType(TypeElement autoBuilderType) {
-    if (!processingEnv.getOptions().containsKey(ALLOW_OPTION)) {
-      errorReporter()
-          .abortWithError(
-              autoBuilderType,
-              "Compile with -A%s to enable this UNSUPPORTED AND UNSTABLE prototype",
-              ALLOW_OPTION);
+    if (processingEnv.getOptions().containsKey(ALLOW_OPTION)) {
+      errorReporter().reportWarning(autoBuilderType, "The -A%s option is obsolete", ALLOW_OPTION);
     }
-    if (autoBuilderType.getKind() != ElementKind.CLASS
-        && autoBuilderType.getKind() != ElementKind.INTERFACE) {
-      errorReporter()
-          .abortWithError(
-              autoBuilderType,
-              "[AutoBuilderWrongType] @AutoBuilder only applies to classes and interfaces");
-    }
-    checkModifiersIfNested(autoBuilderType);
     // The annotation is guaranteed to be present by the contract of Processor#process
     AnnotationMirror autoBuilderAnnotation =
         getAnnotationMirror(autoBuilderType, AUTO_BUILDER_NAME).get();
@@ -126,7 +117,7 @@
     Optional<BuilderMethodClassifier<VariableElement>> maybeClassifier =
         BuilderMethodClassifierForAutoBuilder.classify(
             methods, errorReporter(), processingEnv, executable, builtType, autoBuilderType);
-    if (!maybeClassifier.isPresent()) {
+    if (!maybeClassifier.isPresent() || errorReporter().errorCount() > 0) {
       // We've already output one or more error messages.
       return;
     }
@@ -134,7 +125,7 @@
     Map<String, String> propertyToGetterName =
         Maps.transformValues(classifier.builderGetters(), PropertyGetter::getName);
     AutoBuilderTemplateVars vars = new AutoBuilderTemplateVars();
-    vars.props = propertySet(executable, propertyToGetterName);
+    vars.props = propertySet(autoBuilderType, executable, propertyToGetterName);
     builder.defineVars(vars, classifier);
     vars.identifiers = !processingEnv.getOptions().containsKey(OMIT_IDENTIFIERS_OPTION);
     String generatedClassName = generatedClassName(autoBuilderType, "AutoBuilder_");
@@ -152,7 +143,15 @@
   }
 
   private ImmutableSet<Property> propertySet(
-      ExecutableElement executable, Map<String, String> propertyToGetterName) {
+      TypeElement autoBuilderType,
+      ExecutableElement executable,
+      Map<String, String> propertyToGetterName) {
+    boolean autoAnnotation =
+        MoreElements.getAnnotationMirror(executable, AUTO_ANNOTATION_NAME).isPresent();
+    ImmutableMap<String, String> builderInitializers =
+        autoAnnotation
+            ? autoAnnotationInitializers(autoBuilderType, executable)
+            : ImmutableMap.of();
     // Fix any parameter names that are reserved words in Java. Java source code can't have
     // such parameter names, but Kotlin code might, for example.
     Map<VariableElement, String> identifiers =
@@ -161,18 +160,58 @@
     fixReservedIdentifiers(identifiers);
     return executable.getParameters().stream()
         .map(
-            v ->
-                newProperty(
-                    v, identifiers.get(v), propertyToGetterName.get(v.getSimpleName().toString())))
+            v -> {
+              String name = v.getSimpleName().toString();
+              return newProperty(
+                  v,
+                  identifiers.get(v),
+                  propertyToGetterName.get(name),
+                  Optional.ofNullable(builderInitializers.get(name)));
+            })
         .collect(toImmutableSet());
   }
 
-  private Property newProperty(VariableElement var, String identifier, String getterName) {
+  private Property newProperty(
+      VariableElement var,
+      String identifier,
+      String getterName,
+      Optional<String> builderInitializer) {
     String name = var.getSimpleName().toString();
     TypeMirror type = var.asType();
     Optional<String> nullableAnnotation = nullableAnnotationFor(var, var.asType());
     return new Property(
-        name, identifier, TypeEncoder.encode(type), type, nullableAnnotation, getterName);
+        name,
+        identifier,
+        TypeEncoder.encode(type),
+        type,
+        nullableAnnotation,
+        getterName,
+        builderInitializer);
+  }
+
+  private ImmutableMap<String, String> autoAnnotationInitializers(
+      TypeElement autoBuilderType, ExecutableElement autoAnnotationMethod) {
+    // We expect the return type of an @AutoAnnotation method to be an annotation type. If it isn't,
+    // AutoAnnotation will presumably complain, so we don't need to complain further.
+    TypeMirror returnType = autoAnnotationMethod.getReturnType();
+    if (!returnType.getKind().equals(TypeKind.DECLARED)) {
+      return ImmutableMap.of();
+    }
+    // This might not actually be an annotation (if the code is wrong), but if that's the case we
+    // just won't see any contained ExecutableElement where getDefaultValue() returns something.
+    TypeElement annotation = MoreTypes.asTypeElement(returnType);
+    ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+    for (ExecutableElement method : methodsIn(annotation.getEnclosedElements())) {
+      AnnotationValue defaultValue = method.getDefaultValue();
+      if (defaultValue != null) {
+        String memberName = method.getSimpleName().toString();
+        builder.put(
+            memberName,
+            AnnotationOutput.sourceFormForInitializer(
+                defaultValue, processingEnv, memberName, autoBuilderType));
+      }
+    }
+    return builder.build();
   }
 
   private ExecutableElement findExecutable(
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java
index 711b138..4d19d21 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java
@@ -60,7 +60,7 @@
 @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.ISOLATING)
 public class AutoOneOfProcessor extends AutoValueishProcessor {
   public AutoOneOfProcessor() {
-    super(AUTO_ONE_OF_NAME);
+    super(AUTO_ONE_OF_NAME, /* appliesToInterfaces= */ false);
   }
 
   @Override
@@ -75,13 +75,6 @@
 
   @Override
   void processType(TypeElement autoOneOfType) {
-    if (autoOneOfType.getKind() != ElementKind.CLASS) {
-      errorReporter()
-          .abortWithError(
-              autoOneOfType,
-              "[AutoOneOfNotClass] @" + AUTO_ONE_OF_NAME + " only applies to classes");
-    }
-    checkModifiersIfNested(autoOneOfType);
     DeclaredType kindMirror = mirrorForKindType(autoOneOfType);
 
     // We are going to classify the methods of the @AutoOneOf class into several categories.
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueOrBuilderTemplateVars.java b/value/src/main/java/com/google/auto/value/processor/AutoValueOrBuilderTemplateVars.java
index 86cf497..9fbc165 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoValueOrBuilderTemplateVars.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoValueOrBuilderTemplateVars.java
@@ -109,7 +109,8 @@
    *
    * <ul>
    *   <li>it is {@code @Nullable} (in which case it defaults to null);
-   *   <li>it is {@code Optional} (in which case it defaults to empty);
+   *   <li>it has a builder initializer (for example it is {@code Optional}, which will have an
+   *       initializer of {@code Optional.empty()});
    *   <li>it has a property-builder method (in which case it defaults to empty).
    * </ul>
    */
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java
index ab7da92..4479a05 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java
@@ -18,6 +18,7 @@
 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
 import static com.google.auto.common.MoreStreams.toImmutableList;
 import static com.google.auto.value.processor.ClassNames.AUTO_VALUE_NAME;
+import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Sets.difference;
 import static com.google.common.collect.Sets.intersection;
 import static java.util.Comparator.naturalOrder;
@@ -45,7 +46,6 @@
 import javax.annotation.processing.Processor;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.TypeKind;
@@ -79,21 +79,24 @@
 
   @VisibleForTesting
   AutoValueProcessor(ClassLoader loaderForExtensions) {
-    super(AUTO_VALUE_NAME);
-    this.extensions = null;
-    this.loaderForExtensions = loaderForExtensions;
+    this(ImmutableList.of(), loaderForExtensions);
   }
 
   @VisibleForTesting
-  public AutoValueProcessor(Iterable<? extends AutoValueExtension> extensions) {
-    super(AUTO_VALUE_NAME);
-    this.extensions = ImmutableList.copyOf(extensions);
-    this.loaderForExtensions = null;
+  public AutoValueProcessor(Iterable<? extends AutoValueExtension> testExtensions) {
+    this(testExtensions, null);
+  }
+
+  private AutoValueProcessor(
+      Iterable<? extends AutoValueExtension> testExtensions, ClassLoader loaderForExtensions) {
+    super(AUTO_VALUE_NAME, /* appliesToInterfaces= */ false);
+    this.extensions = ImmutableList.copyOf(testExtensions);
+    this.loaderForExtensions = loaderForExtensions;
   }
 
   // Depending on how this AutoValueProcessor was constructed, we might already have a list of
-  // extensions when init() is run, or, if `extensions` is null, we have a ClassLoader that will be
-  // used to get the list using the ServiceLoader API.
+  // extensions when init() is run, or, if `loaderForExtensions` is not null, it is a ClassLoader
+  // that will be used to get the list using the ServiceLoader API.
   private ImmutableList<AutoValueExtension> extensions;
   private final ClassLoader loaderForExtensions;
 
@@ -108,7 +111,8 @@
   public synchronized void init(ProcessingEnvironment processingEnv) {
     super.init(processingEnv);
 
-    if (extensions == null) {
+    if (loaderForExtensions != null) {
+      checkState(extensions.isEmpty());
       try {
         extensions = extensionsFromLoader(loaderForExtensions);
       } catch (RuntimeException | Error e) {
@@ -165,10 +169,6 @@
 
   @Override
   void processType(TypeElement type) {
-    if (type.getKind() != ElementKind.CLASS) {
-      errorReporter()
-          .abortWithError(type, "[AutoValueNotClass] @AutoValue only applies to classes");
-    }
     if (ancestorIsAutoValue(type)) {
       errorReporter()
           .abortWithError(type, "[AutoValueExtend] One @AutoValue class may not extend another");
@@ -180,7 +180,6 @@
               "[AutoValueImplAnnotation] @AutoValue may not be used to implement an annotation"
                   + " interface; try using @AutoAnnotation instead");
     }
-    checkModifiersIfNested(type);
 
     // We are going to classify the methods of the @AutoValue class into several categories.
     // This covers the methods in the class itself and the ones it inherits from supertypes.
diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
index 93f2f79..31f1ec1 100644
--- a/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
+++ b/value/src/main/java/com/google/auto/value/processor/AutoValueishProcessor.java
@@ -29,6 +29,7 @@
 import static java.util.stream.Collectors.toCollection;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
+import static javax.lang.model.util.ElementFilter.constructorsIn;
 
 import com.google.auto.common.MoreElements;
 import com.google.auto.common.MoreTypes;
@@ -92,19 +93,22 @@
  */
 abstract class AutoValueishProcessor extends AbstractProcessor {
   private final String annotationClassName;
+  private final boolean appliesToInterfaces;
 
   /**
-   * Qualified names of {@code @AutoValue} or {@code AutoOneOf} classes that we attempted to process
-   * but had to abandon because we needed other types that they referenced and those other types
-   * were missing.
+   * Qualified names of {@code @AutoValue} (etc) classes that we attempted to process but had to
+   * abandon because we needed other types that they referenced and those other types were missing.
    */
   private final List<String> deferredTypeNames = new ArrayList<>();
 
-  AutoValueishProcessor(String annotationClassName) {
+  AutoValueishProcessor(String annotationClassName, boolean appliesToInterfaces) {
     this.annotationClassName = annotationClassName;
+    this.appliesToInterfaces = appliesToInterfaces;
   }
 
-  /** The annotation we are processing, {@code AutoValue} or {@code AutoOneOf}. */
+  /**
+   * The annotation we are processing, for example {@code AutoValue} or {@code AutoBuilder}.
+   */
   private TypeElement annotationType;
   /** The simple name of {@link #annotationType}. */
   private String simpleAnnotationName;
@@ -117,6 +121,10 @@
     super.init(processingEnv);
     errorReporter = new ErrorReporter(processingEnv);
     nullables = new Nullables(processingEnv);
+    annotationType = elementUtils().getTypeElement(annotationClassName);
+    if (annotationType != null) {
+      simpleAnnotationName = annotationType.getSimpleName().toString();
+    }
   }
 
   final ErrorReporter errorReporter() {
@@ -132,9 +140,9 @@
   }
 
   /**
-   * Qualified names of {@code @AutoValue} or {@code AutoOneOf} classes that we attempted to process
-   * but had to abandon because we needed other types that they referenced and those other types
-   * were missing. This is used by tests.
+   * Qualified names of {@code @AutoValue} (etc) classes that we attempted to process but had to
+   * abandon because we needed other types that they referenced and those other types were missing.
+   * This is used by tests.
    */
   final ImmutableList<String> deferredTypeNames() {
     return ImmutableList.copyOf(deferredTypeNames);
@@ -160,6 +168,7 @@
     private final Optional<String> nullableAnnotation;
     private final Optionalish optional;
     private final String getter;
+    private final String builderInitializer; // empty, or with initial ` = `.
 
     Property(
         String name,
@@ -167,17 +176,41 @@
         String type,
         TypeMirror typeMirror,
         Optional<String> nullableAnnotation,
-        String getter) {
+        String getter,
+        Optional<String> maybeBuilderInitializer) {
       this.name = name;
       this.identifier = identifier;
       this.type = type;
       this.typeMirror = typeMirror;
       this.nullableAnnotation = nullableAnnotation;
       this.optional = Optionalish.createIfOptional(typeMirror);
+      this.builderInitializer =
+          maybeBuilderInitializer.isPresent()
+              ? " = " + maybeBuilderInitializer.get()
+              : builderInitializer();
       this.getter = getter;
     }
 
     /**
+     * Returns the appropriate initializer for a builder property. Builder properties are never
+     * primitive; if the built property is an {@code int} the builder property will be an {@code
+     * Integer}. So the default value for a builder property will be null unless there is an
+     * initializer. The caller of the constructor may have supplied an initializer, but otherwise we
+     * supply one only if this property is an {@code Optional} and is not {@code @Nullable}. In that
+     * case the initializer sets it to {@code Optional.empty()}.
+     */
+    private String builderInitializer() {
+      if (nullableAnnotation.isPresent()) {
+        return "";
+      }
+      Optionalish optional = Optionalish.createIfOptional(typeMirror);
+      if (optional == null) {
+        return "";
+      }
+      return " = " + optional.getEmpty();
+    }
+
+    /**
      * Returns the name of the property as it should be used when declaring identifiers (fields and
      * parameters). If the original getter method was {@code foo()} then this will be {@code foo}.
      * If it was {@code getFoo()} then it will be {@code foo}. If it was {@code getPackage()} then
@@ -219,6 +252,14 @@
     }
 
     /**
+     * Returns a string to be used as an initializer for a builder field for this property,
+     * including the leading {@code =}, or an empty string if there is no explicit initializer.
+     */
+    public String getBuilderInitializer() {
+      return builderInitializer;
+    }
+
+    /**
      * Returns the string to use as a method annotation to indicate the nullability of this
      * property. It is either the empty string, if the property is not nullable, or an annotation
      * string with a trailing space, such as {@code "@`javax.annotation.Nullable` "}, where the
@@ -266,7 +307,8 @@
           type,
           method.getReturnType(),
           nullableAnnotation,
-          method.getSimpleName().toString());
+          method.getSimpleName().toString(),
+          Optional.empty());
       this.method = method;
       this.fieldAnnotations = fieldAnnotations;
       this.methodAnnotations = methodAnnotations;
@@ -305,7 +347,6 @@
 
   @Override
   public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-    annotationType = elementUtils().getTypeElement(annotationClassName);
     if (annotationType == null) {
       // This should not happen. If the annotation type is not found, how did the processor get
       // triggered?
@@ -318,7 +359,6 @@
                   + " because the annotation class was not found");
       return false;
     }
-    simpleAnnotationName = annotationType.getSimpleName().toString();
     List<TypeElement> deferredTypes =
         deferredTypeNames.stream()
             .map(name -> elementUtils().getTypeElement(name))
@@ -330,9 +370,10 @@
       for (TypeElement type : deferredTypes) {
         errorReporter.reportError(
             type,
-            "[AutoValueUndefined] Did not generate @%s class for %s because it references"
+            "[%sUndefined] Did not generate @%s class for %s because it references"
                 + " undefined types",
             simpleAnnotationName,
+            simpleAnnotationName,
             type.getQualifiedName());
       }
       return false;
@@ -347,6 +388,7 @@
     deferredTypeNames.clear();
     for (TypeElement type : types) {
       try {
+        validateType(type);
         processType(type);
       } catch (AbortProcessingException e) {
         // We abandoned this type; continue with the next.
@@ -362,7 +404,8 @@
         String trace = Throwables.getStackTraceAsString(e);
         errorReporter.reportError(
             type,
-            "[AutoValueException] @%s processor threw an exception: %s",
+            "[%sException] @%s processor threw an exception: %s",
+            simpleAnnotationName,
             simpleAnnotationName,
             trace);
         throw e;
@@ -372,8 +415,44 @@
   }
 
   /**
-   * Analyzes a single {@code @AutoValue} or {@code @AutoOneOf} class, and outputs the corresponding
-   * implementation class or classes.
+   * Validations common to all the subclasses. An {@code @AutoFoo} type must be a class, or possibly
+   * an interface for {@code @AutoBuilder}. If it is a class then it must have a non-private no-arg
+   * constructor. And, since we'll be generating a subclass, it can't be final.
+   */
+  private void validateType(TypeElement type) {
+    ElementKind kind = type.getKind();
+    boolean kindOk =
+        kind.equals(ElementKind.CLASS)
+            || (appliesToInterfaces && kind.equals(ElementKind.INTERFACE));
+    if (!kindOk) {
+      String appliesTo = appliesToInterfaces ? "classes and interfaces" : "classes";
+      errorReporter.abortWithError(
+          type,
+          "[%sWrongType] @%s only applies to %s",
+          simpleAnnotationName,
+          simpleAnnotationName,
+          appliesTo);
+    }
+    checkModifiersIfNested(type);
+    if (!hasVisibleNoArgConstructor(type)) {
+      errorReporter.reportError(
+          type,
+          "[%sConstructor] @%s class must have a non-private no-arg constructor",
+          simpleAnnotationName,
+          simpleAnnotationName);
+    }
+    if (type.getModifiers().contains(Modifier.FINAL)) {
+      errorReporter.abortWithError(
+          type,
+          "[%sFinal] @%s class must not be final",
+          simpleAnnotationName,
+          simpleAnnotationName);
+    }
+  }
+
+  /**
+   * Analyzes a single {@code @AutoValue} (etc) class, and outputs the corresponding implementation
+   * class or classes.
    *
    * @param type the class with the {@code @AutoValue} or {@code @AutoOneOf} annotation.
    */
@@ -435,7 +514,9 @@
           if (p.isNullable() && returnType.getKind().isPrimitive()) {
             errorReporter()
                 .reportError(
-                    propertyMethod, "[AutoValueNullPrimitive] Primitive types cannot be @Nullable");
+                    propertyMethod,
+                    "[%sNullPrimitive] Primitive types cannot be @Nullable",
+                    simpleAnnotationName);
           }
         });
     return props.build();
@@ -467,24 +548,23 @@
 
   /** Returns the spelling to be used in the generated code for the given list of annotations. */
   static ImmutableList<String> annotationStrings(List<? extends AnnotationMirror> annotations) {
-    // TODO(b/68008628): use ImmutableList.toImmutableList() when that works.
     return annotations.stream()
         .map(AnnotationOutput::sourceFormForAnnotation)
+        .sorted() // ensures deterministic order
         .collect(toImmutableList());
   }
 
   /**
-   * Returns the name of the generated {@code @AutoValue} or {@code @AutoOneOf} class, for example
-   * {@code AutoOneOf_TaskResult} or {@code $$AutoValue_SimpleMethod}.
+   * Returns the name of the generated {@code @AutoValue} (etc) class, for example {@code
+   * AutoOneOf_TaskResult} or {@code $$AutoValue_SimpleMethod}.
    *
-   * @param type the name of the type bearing the {@code @AutoValue} or {@code @AutoOneOf}
-   *     annotation.
+   * @param type the name of the type bearing the {@code @AutoValue} (etc) annotation.
    * @param prefix the prefix to use in the generated class. This may start with one or more dollar
    *     signs, for an {@code @AutoValue} implementation where there are AutoValue extensions.
    */
   static String generatedClassName(TypeElement type, String prefix) {
     String name = type.getSimpleName().toString();
-    while (type.getEnclosingElement() instanceof TypeElement) {
+    while (MoreElements.isType(type.getEnclosingElement())) {
       type = MoreElements.asType(type.getEnclosingElement());
       name = type.getSimpleName() + "_" + name;
     }
@@ -555,7 +635,8 @@
         for (ExecutableElement context : contexts) {
           errorReporter.reportError(
               context,
-              "[AutoValueDupProperty] More than one @%s property called %s",
+              "[%sDupProperty] More than one @%s property called %s",
+              simpleAnnotationName,
               simpleAnnotationName,
               name);
         }
@@ -589,8 +670,9 @@
     List<? extends AnnotationMirror> elementAnnotations = element.getAnnotationMirrors();
     OptionalInt nullableAnnotationIndex = nullableAnnotationIndex(elementAnnotations);
     if (nullableAnnotationIndex.isPresent()) {
-      ImmutableList<String> annotations = annotationStrings(elementAnnotations);
-      return Optional.of(annotations.get(nullableAnnotationIndex.getAsInt()) + " ");
+      AnnotationMirror annotation = elementAnnotations.get(nullableAnnotationIndex.getAsInt());
+      String annotationString = AnnotationOutput.sourceFormForAnnotation(annotation);
+      return Optional.of(annotationString + " ");
     } else {
       return Optional.empty();
     }
@@ -1152,6 +1234,14 @@
     return getAnnotationMirror(element, annotationName).isPresent();
   }
 
+  /** True if the type is a class with a non-private no-arg constructor, or is an interface. */
+  static boolean hasVisibleNoArgConstructor(TypeElement type) {
+    return type.getKind().isInterface()
+        || constructorsIn(type.getEnclosedElements()).stream()
+            .anyMatch(
+                c -> c.getParameters().isEmpty() && !c.getModifiers().contains(Modifier.PRIVATE));
+  }
+
   final void writeSourceFile(String className, String text, TypeElement originatingType) {
     try {
       JavaFileObject sourceFile =
diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
index 51773e6..a4336f5 100644
--- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
+++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java
@@ -386,14 +386,17 @@
       DeclaredType builderTypeMirror = MoreTypes.asDeclared(builderType.asType());
       ExecutableType methodMirror =
           MoreTypes.asExecutable(typeUtils.asMemberOf(builderTypeMirror, method));
-      if (TYPE_EQUIVALENCE.equivalent(methodMirror.getReturnType(), builderType.asType())) {
+      TypeMirror returnType = methodMirror.getReturnType();
+      if (typeUtils.isSubtype(builderType.asType(), returnType)
+          && !MoreTypes.isTypeOf(Object.class, returnType)) {
+        // We allow the return type to be a supertype (other than Object), to support step builders.
         TypeMirror parameterType = Iterables.getOnlyElement(methodMirror.getParameterTypes());
         propertyNameToSetters.put(
             propertyName, new PropertySetter(method, parameterType, function.get()));
       } else {
         errorReporter.reportError(
             method,
-            "[%sBuilderRet] Setter methods must return %s",
+            "[%sBuilderRet] Setter methods must return %s or a supertype",
             autoWhat(),
             builderType.asType());
       }
diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java
index 9f45d17..b612c10 100644
--- a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java
+++ b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java
@@ -18,6 +18,7 @@
 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
 import static com.google.auto.common.MoreStreams.toImmutableSet;
 import static com.google.auto.value.processor.AutoValueishProcessor.hasAnnotationMirror;
+import static com.google.auto.value.processor.AutoValueishProcessor.hasVisibleNoArgConstructor;
 import static com.google.auto.value.processor.AutoValueishProcessor.nullableAnnotationFor;
 import static com.google.auto.value.processor.ClassNames.AUTO_VALUE_BUILDER_NAME;
 import static com.google.common.collect.Sets.immutableEnumSet;
@@ -86,16 +87,9 @@
     Optional<TypeElement> builderTypeElement = Optional.empty();
     for (TypeElement containedClass : typesIn(autoValueClass.getEnclosedElements())) {
       if (hasAnnotationMirror(containedClass, AUTO_VALUE_BUILDER_NAME)) {
-        if (!CLASS_OR_INTERFACE.contains(containedClass.getKind())) {
-          errorReporter.reportError(
-              containedClass,
-              "[AutoValueBuilderClass] @AutoValue.Builder can only apply to a class or an"
-                  + " interface");
-        } else if (!containedClass.getModifiers().contains(Modifier.STATIC)) {
-          errorReporter.reportError(
-              containedClass,
-              "[AutoValueInnerBuilder] @AutoValue.Builder cannot be applied to a non-static class");
-        } else if (builderTypeElement.isPresent()) {
+        findBuilderError(containedClass)
+            .ifPresent(error -> errorReporter.reportError(containedClass, "%s", error));
+        if (builderTypeElement.isPresent()) {
           errorReporter.reportError(
               containedClass,
               "[AutoValueTwoBuilders] %s already has a Builder: %s",
@@ -114,6 +108,24 @@
     }
   }
 
+  /** Finds why this {@code @AutoValue.Builder} class is bad, if it is bad. */
+  private Optional<String> findBuilderError(TypeElement builderTypeElement) {
+    if (!CLASS_OR_INTERFACE.contains(builderTypeElement.getKind())) {
+      return Optional.of(
+          "[AutoValueBuilderClass] @AutoValue.Builder can only apply to a class or an"
+              + " interface");
+    } else if (!builderTypeElement.getModifiers().contains(Modifier.STATIC)) {
+      return Optional.of(
+          "[AutoValueInnerBuilder] @AutoValue.Builder cannot be applied to a non-static class");
+    } else if (builderTypeElement.getKind().equals(ElementKind.CLASS)
+        && !hasVisibleNoArgConstructor(builderTypeElement)) {
+      return Optional.of(
+          "[AutoValueBuilderConstructor] @AutoValue.Builder class must have a non-private no-arg"
+              + " constructor");
+    }
+    return Optional.empty();
+  }
+
   /** Representation of an {@code AutoValue.Builder} class or interface. */
   class Builder implements AutoValueExtension.BuilderContext {
     private final TypeElement builderTypeElement;
@@ -333,7 +345,7 @@
       vars.builderRequiredProperties =
           vars.props.stream()
               .filter(p -> !p.isNullable())
-              .filter(p -> p.getOptional() == null)
+              .filter(p -> p.getBuilderInitializer().isEmpty())
               .filter(p -> !vars.builderPropertyBuilders.containsKey(p.getName()))
               .collect(toImmutableSet());
     }
diff --git a/value/src/main/java/com/google/auto/value/processor/GwtCompatibility.java b/value/src/main/java/com/google/auto/value/processor/GwtCompatibility.java
index fae4e09..35fcbbf 100644
--- a/value/src/main/java/com/google/auto/value/processor/GwtCompatibility.java
+++ b/value/src/main/java/com/google/auto/value/processor/GwtCompatibility.java
@@ -15,15 +15,9 @@
  */
 package com.google.auto.value.processor;
 
-import static java.util.stream.Collectors.joining;
-
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Name;
 import javax.lang.model.element.TypeElement;
 
@@ -46,29 +40,7 @@
     return gwtCompatibleAnnotation;
   }
 
-  // Get rid of the misconceived <? extends ExecutableElement, ? extends AnnotationValue>
-  // in the return type of getElementValues().
-  static Map<ExecutableElement, AnnotationValue> getElementValues(AnnotationMirror annotation) {
-    return Collections.<ExecutableElement, AnnotationValue>unmodifiableMap(
-        annotation.getElementValues());
-  }
-
   String gwtCompatibleAnnotationString() {
-    if (gwtCompatibleAnnotation.isPresent()) {
-      AnnotationMirror annotation = gwtCompatibleAnnotation.get();
-      TypeElement annotationElement = (TypeElement) annotation.getAnnotationType().asElement();
-      String annotationArguments;
-      if (annotation.getElementValues().isEmpty()) {
-        annotationArguments = "";
-      } else {
-        annotationArguments =
-            getElementValues(annotation).entrySet().stream()
-                .map(e -> e.getKey().getSimpleName() + " = " + e.getValue())
-                .collect(joining(", ", "(", ")"));
-      }
-      return "@" + annotationElement.getQualifiedName() + annotationArguments;
-    } else {
-      return "";
-    }
+    return gwtCompatibleAnnotation.map(AnnotationOutput::sourceFormForAnnotation).orElse("");
   }
 }
diff --git a/value/src/main/java/com/google/auto/value/processor/GwtSerialization.java b/value/src/main/java/com/google/auto/value/processor/GwtSerialization.java
index 30ad092..8673d3d 100644
--- a/value/src/main/java/com/google/auto/value/processor/GwtSerialization.java
+++ b/value/src/main/java/com/google/auto/value/processor/GwtSerialization.java
@@ -18,6 +18,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.stream.Collectors.toList;
 
+import com.google.auto.common.AnnotationMirrors;
 import com.google.auto.value.processor.AutoValueishProcessor.GetterProperty;
 import com.google.auto.value.processor.PropertyBuilderClassifier.PropertyBuilder;
 import com.google.common.collect.ImmutableMap;
@@ -26,13 +27,10 @@
 import java.io.IOException;
 import java.io.Writer;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.zip.CRC32;
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.TypeMirror;
 import javax.tools.Diagnostic;
@@ -60,13 +58,11 @@
     Optional<AnnotationMirror> optionalGwtCompatible = gwtCompatibility.gwtCompatibleAnnotation();
     if (optionalGwtCompatible.isPresent()) {
       AnnotationMirror gwtCompatible = optionalGwtCompatible.get();
-      for (Map.Entry<ExecutableElement, AnnotationValue> entry :
-          GwtCompatibility.getElementValues(gwtCompatible).entrySet()) {
-        if (entry.getKey().getSimpleName().contentEquals("serializable")
-            && entry.getValue().getValue().equals(true)) {
-          return true;
-        }
-      }
+      return AnnotationMirrors.getAnnotationValuesWithDefaults(gwtCompatible).entrySet().stream()
+          .anyMatch(
+              e ->
+                  e.getKey().getSimpleName().contentEquals("serializable")
+                      && e.getValue().getValue().equals(true));
     }
     return false;
   }
diff --git a/value/src/main/java/com/google/auto/value/processor/autovalue.vm b/value/src/main/java/com/google/auto/value/processor/autovalue.vm
index 86cfe49..18ca827 100644
--- a/value/src/main/java/com/google/auto/value/processor/autovalue.vm
+++ b/value/src/main/java/com/google/auto/value/processor/autovalue.vm
@@ -75,15 +75,11 @@
     ## the constructor is called from the extension code.
 
     #if ($identifiers)
-
     if ($p == null) {
       throw new NullPointerException("Null $p.name");
     }
     #else
-      ## Just throw NullPointerException with no message if it's null.
-      ## The Object cast has no effect on the code but silences an ErrorProne warning.
-
-    ((`java.lang.Object`) ${p}).getClass();
+    `java.util.Objects`.requireNonNull($p);
     #end
 
   #end
diff --git a/value/src/main/java/com/google/auto/value/processor/builder.vm b/value/src/main/java/com/google/auto/value/processor/builder.vm
index 630330c..b1787f2 100644
--- a/value/src/main/java/com/google/auto/value/processor/builder.vm
+++ b/value/src/main/java/com/google/auto/value/processor/builder.vm
@@ -40,7 +40,7 @@
 
   #if ($p.kind.primitive)
 
-  private $types.boxedClass($p.typeMirror).simpleName $p;
+  private $types.boxedClass($p.typeMirror).simpleName $p $p.builderInitializer;
 
   #else
 
@@ -54,7 +54,7 @@
 
     #end
 
-  private $p.type $p #if ($p.optional && !$p.nullable) = $p.optional.empty #end ;
+  private $p.type $p $p.builderInitializer;
 
   #end
 #end
@@ -94,15 +94,11 @@
     #if (!$setter.primitiveParameter && !$p.nullable && ${setter.copy($p)} == $p)
 
       #if ($identifiers)
-
     if ($p == null) {
       throw new NullPointerException("Null $p.name");
     }
       #else
-        ## Just throw NullPointerException with no message if it's null.
-        ## The Object cast has no effect on the code but silences an ErrorProne warning.
-
-    ((`java.lang.Object`) ${p}).getClass();
+    `java.util.Objects`.requireNonNull($p);
       #end
 
     #end
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java
index 50b6b27..96649bd 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java
@@ -115,7 +115,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation)
         .generatedSourceFile("foo.bar.AutoBuilder_Baz_Builder")
@@ -148,7 +147,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation)
         .generatedSourceFile("foo.bar.AutoBuilder_Baz_Builder")
@@ -192,7 +190,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(built, builder);
     assertThat(compilation).succeededWithoutWarnings();
     assertThat(compilation).generatedSourceFile("foo.bar.AutoBuilder_Builder");
@@ -214,7 +211,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -242,7 +238,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -252,6 +247,66 @@
   }
 
   @Test
+  public void autoBuilderClassMustHaveNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoBuilder;",
+            "",
+            "public class Baz {",
+            "  @AutoBuilder",
+            "  abstract static class Builder {",
+            "    Builder(int bogus) {}",
+            "    Baz build();",
+            "  }",
+            "}");
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoBuilderProcessor())
+            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+            .compile(javaFileObject);
+    assertThat(compilation).failed();
+    assertThat(compilation)
+        .hadErrorContaining(
+            "[AutoBuilderConstructor] @AutoBuilder class must have a non-private no-arg"
+                + " constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Builder");
+  }
+
+  @Test
+  public void autoBuilderClassMustHaveVisibleNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoBuilder;",
+            "",
+            "public class Baz {",
+            "  @AutoBuilder",
+            "  abstract static class Builder {",
+            "    private Builder() {}",
+            "    Baz build();",
+            "  }",
+            "}");
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoBuilderProcessor())
+            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
+            .compile(javaFileObject);
+    assertThat(compilation).failed();
+    assertThat(compilation)
+        .hadErrorContaining(
+            "[AutoBuilderConstructor] @AutoBuilder class must have a non-private no-arg"
+                + " constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Builder");
+  }
+
+  @Test
   public void autoBuilderNestedInPrivate() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
@@ -271,7 +326,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -299,7 +353,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -328,7 +381,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -355,7 +407,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -386,7 +437,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -418,7 +468,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -451,7 +500,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -489,7 +537,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -519,7 +566,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -553,7 +599,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -584,7 +629,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -618,7 +662,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -650,7 +693,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -686,7 +728,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -719,12 +760,11 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
         .hadErrorContaining(
-            "[AutoBuilderBuilderRet] Setter methods must return foo.bar.Baz.Builder")
+            "[AutoBuilderBuilderRet] Setter methods must return foo.bar.Baz.Builder or a supertype")
         .inFile(javaFileObject)
         .onLineContaining("two(int x)");
   }
@@ -761,7 +801,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject, nullableFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -794,7 +833,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -827,7 +865,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
@@ -862,7 +899,6 @@
     Compilation compilation =
         javac()
             .withProcessors(new AutoBuilderProcessor())
-            .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable")
             .compile(javaFileObject);
     assertThat(compilation).failed();
     assertThat(compilation)
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
index 788b543..a55b74d 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoOneOfCompilationTest.java
@@ -463,6 +463,33 @@
   }
 
   @Test
+  public void mustBeClass() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Pet",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoOneOf;",
+            "",
+            "@AutoOneOf(Pet.Kind.class)",
+            "public interface Pet {",
+            "  public enum Kind {",
+            "    DOG,",
+            "    CAT,",
+            "  }",
+            "  Kind getKind();",
+            "  String dog();",
+            "  String cat();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoOneOfProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoOneOf only applies to classes")
+        .inFile(javaFileObject)
+        .onLineContaining("interface Pet");
+  }
+
+  @Test
   public void cantBeNullable() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
@@ -490,4 +517,62 @@
         .inFile(javaFileObject)
         .onLineContaining("@Nullable String dog()");
   }
+
+  @Test
+  public void mustHaveNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Pet",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoOneOf;",
+            "",
+            "@AutoOneOf(Pet.Kind.class)",
+            "public abstract class Pet {",
+            "  Pet(boolean cuddly) {}",
+            "",
+            "  public enum Kind {",
+            "    DOG,",
+            "    CAT,",
+            "  }",
+            "  public abstract Kind getKind();",
+            "  public abstract String dog();",
+            "  public abstract String cat();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoOneOfProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoOneOf class must have a non-private no-arg constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Pet");
+  }
+
+  @Test
+  public void mustHaveVisibleNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Pet",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoOneOf;",
+            "",
+            "@AutoOneOf(Pet.Kind.class)",
+            "public abstract class Pet {",
+            "  private Pet() {}",
+            "",
+            "  public enum Kind {",
+            "    DOG,",
+            "    CAT,",
+            "  }",
+            "  public abstract Kind getKind();",
+            "  public abstract String dog();",
+            "  public abstract String cat();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoOneOfProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoOneOf class must have a non-private no-arg constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Pet");
+  }
 }
diff --git a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
index ab6690f..09d4faf 100644
--- a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java
@@ -21,6 +21,7 @@
 import static com.google.testing.compile.Compiler.javac;
 import static java.util.stream.Collectors.joining;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.truth.Expect;
@@ -555,6 +556,50 @@
   }
 
   @Test
+  public void autoValueMustBeClass() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "",
+            "@AutoValue",
+            "public interface Baz {",
+            "  String buh();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoValue only applies to classes")
+        .inFile(javaFileObject)
+        .onLineContaining("interface Baz");
+  }
+
+  @Test
+  public void autoValueMustNotBeFinal() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "",
+            "@AutoValue",
+            "public final class Baz {",
+            "  public Baz create() {",
+            "    return new AutoValue_Baz();",
+            "  }",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoValue class must not be final")
+        .inFile(javaFileObject)
+        .onLineContaining("class Baz");
+  }
+
+  @Test
   public void autoValueMustBeStatic() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
@@ -581,7 +626,7 @@
   }
 
   @Test
-  public void autoValueMustBeNotBePrivate() {
+  public void autoValueMustNotBePrivate() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
             "foo.bar.Baz",
@@ -635,6 +680,52 @@
   }
 
   @Test
+  public void autoValueMustHaveNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "",
+            "@AutoValue",
+            "public abstract class Baz {",
+            "  Baz(int buh) {}",
+            "",
+            "  public abstract int buh();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoValue class must have a non-private no-arg constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Baz");
+  }
+
+  @Test
+  public void autoValueMustHaveVisibleNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "",
+            "@AutoValue",
+            "public abstract class Baz {",
+            "  private Baz() {}",
+            "",
+            "  public abstract int buh();",
+            "}");
+    Compilation compilation =
+        javac().withProcessors(new AutoValueProcessor()).compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoValue class must have a non-private no-arg constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Baz");
+  }
+
+  @Test
   public void noMultidimensionalPrimitiveArrays() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
@@ -1448,6 +1539,42 @@
   }
 
   @Test
+  public void autoValueBuilderMustHaveNoArgConstructor() {
+    JavaFileObject javaFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Example",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "",
+            "class Example {",
+            "  @AutoValue",
+            "  abstract static class Baz {",
+            "    abstract int foo();",
+            "",
+            "    static Builder builder() {",
+            "      return new AutoValue_Example_Baz.Builder();",
+            "    }",
+            "",
+            "    @AutoValue.Builder",
+            "    abstract static class Builder {",
+            "      Builder(int defaultFoo) {}",
+            "      abstract Builder foo(int x);",
+            "      abstract Baz build();",
+            "    }",
+            "  }",
+            "}");
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
+            .compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("@AutoValue.Builder class must have a non-private no-arg constructor")
+        .inFile(javaFileObject)
+        .onLineContaining("class Builder");
+  }
+
+  @Test
   public void autoValueBuilderOnEnum() {
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
@@ -1850,6 +1977,8 @@
 
   @Test
   public void autoValueBuilderSetterReturnType() {
+    // We do allow the return type of a setter to be a supertype of the builder type, to support
+    // step builders. But we don't allow it to be Object.
     JavaFileObject javaFileObject =
         JavaFileObjects.forSourceLines(
             "foo.bar.Baz",
@@ -1863,7 +1992,7 @@
             "",
             "  @AutoValue.Builder",
             "  public interface Builder {",
-            "    void blim(int x);",
+            "    Object blim(int x);",
             "    Baz build();",
             "  }",
             "}");
@@ -1874,7 +2003,7 @@
     assertThat(compilation)
         .hadErrorContaining("Setter methods must return foo.bar.Baz.Builder")
         .inFile(javaFileObject)
-        .onLineContaining("void blim(int x)");
+        .onLineContaining("Object blim(int x)");
   }
 
   @Test
@@ -2913,8 +3042,6 @@
             "foo.bar.Bar",
             "package foo.bar;",
             "",
-            "import com.google.auto.value.AutoValue;",
-            "",
             "@" + Foo.class.getCanonicalName(),
             "public abstract class Bar {",
             "  public abstract BarFoo barFoo();",
@@ -2928,6 +3055,73 @@
   }
 
   @Test
+  public void referencingGeneratedClassInAnnotation() {
+    // Test that ensures that a type that does not exist can be referenced by a copied annotation
+    // as long as it later does come into existence. The BarFoo type referenced here does not exist
+    // when the AutoValueProcessor runs on the first round, but the FooProcessor then generates it.
+    // That generation provokes a further round of annotation processing and AutoValueProcessor
+    // should succeed then.
+    // We test the three places that a class reference could appear: as the value of a Class
+    // element, as the value of a Class[] element, in a nested annotation.
+    JavaFileObject barFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Bar",
+            "package foo.bar;",
+            "",
+            "@" + Foo.class.getCanonicalName(),
+            "public abstract class Bar {",
+            "}");
+    JavaFileObject referenceClassFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.ReferenceClass",
+            "package foo.bar;",
+            "",
+            "@interface ReferenceClass {",
+            "  Class<?> value() default Void.class;",
+            "  Class<?>[] values() default {};",
+            "  Nested nested() default @Nested;",
+            "  @interface Nested {",
+            "    Class<?>[] values() default {};",
+            "  }",
+            "}");
+    ImmutableList<String> annotations = ImmutableList.of(
+        "@ReferenceClass(BarFoo.class)",
+        "@ReferenceClass(values = {Void.class, BarFoo.class})",
+        "@ReferenceClass(nested = @ReferenceClass.Nested(values = {Void.class, BarFoo.class}))");
+    for (String annotation : annotations) {
+      JavaFileObject bazFileObject =
+          JavaFileObjects.forSourceLines(
+              "foo.bar.Baz",
+              "package foo.bar;",
+              "",
+              "import com.google.auto.value.AutoValue;",
+              "",
+              "@AutoValue",
+              "@AutoValue.CopyAnnotations",
+              annotation,
+              "public abstract class Baz {",
+              "  public abstract int foo();",
+              "",
+              "  public static Baz create(int foo) {",
+              "    return new AutoValue_Baz(foo);",
+              "  }",
+              "}");
+      Compilation compilation =
+          javac()
+              .withProcessors(new AutoValueProcessor(), new FooProcessor())
+              .withOptions("-Xlint:-processing", "-implicit:none")
+              .compile(bazFileObject, barFileObject, referenceClassFileObject);
+      expect.about(compilations()).that(compilation).succeededWithoutWarnings();
+      if (compilation.status().equals(Compilation.Status.SUCCESS)) {
+        expect.about(compilations()).that(compilation)
+            .generatedSourceFile("foo.bar.AutoValue_Baz")
+            .contentsAsUtf8String()
+            .contains(annotation);
+      }
+    }
+  }
+
+  @Test
   public void annotationReferencesUndefined() {
     // Test that we don't throw an exception if asked to compile @SuppressWarnings(UNDEFINED)
     // where UNDEFINED is an undefined symbol.
@@ -3052,6 +3246,63 @@
   }
 
   @Test
+  public void methodAnnotationsCopiedInLexicographicalOrder() {
+    JavaFileObject bazFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Baz",
+            "package foo.bar;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "import com.package1.Annotation1;",
+            "import com.package2.Annotation0;",
+            "",
+            "@AutoValue",
+            "public abstract class Baz extends Parent {",
+            "  @Annotation0",
+            "  @Annotation1",
+            "  @Override",
+            "  public abstract String foo();",
+            "}");
+    JavaFileObject parentFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.Parent",
+            "package foo.bar;",
+            "",
+            "public abstract class Parent {",
+            "  public abstract String foo();",
+            "}");
+    JavaFileObject annotation1FileObject =
+        JavaFileObjects.forSourceLines(
+            "com.package1.Annotation1",
+            "package com.package1;",
+            "",
+            "import java.lang.annotation.ElementType;",
+            "import java.lang.annotation.Target;",
+            "",
+            "@Target({ElementType.FIELD, ElementType.METHOD})",
+            "public @interface Annotation1 {}");
+    JavaFileObject annotation0FileObject =
+        JavaFileObjects.forSourceLines(
+            "com.package2.Annotation0",
+            "package com.package2;",
+            "",
+            "public @interface Annotation0 {}");
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoValueProcessor())
+            .withOptions("-Xlint:-processing", "-implicit:none")
+            .compile(bazFileObject, parentFileObject, annotation1FileObject, annotation0FileObject);
+    assertThat(compilation).succeededWithoutWarnings();
+    assertThat(compilation)
+        .generatedSourceFile("foo.bar.AutoValue_Baz")
+        .contentsAsUtf8String()
+        .containsMatch(
+            "(?s:@Annotation1\\s+@Annotation0\\s+@Override\\s+public String foo\\(\\))");
+    // @Annotation1 precedes @Annotation 0 because
+    // @com.package2.Annotation1 precedes @com.package1.Annotation0
+  }
+
+  @Test
   public void nonVisibleProtectedAnnotationFromOtherPackage() {
     JavaFileObject bazFileObject =
         JavaFileObjects.forSourceLines(
diff --git a/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java b/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
index 48d8cd6..1d7e89f 100644
--- a/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
+++ b/value/src/test/java/com/google/auto/value/processor/PropertyAnnotationsTest.java
@@ -510,11 +510,14 @@
                 "@PropertyAnnotationsTest.InheritedAnnotation")
             .build();
 
+    // Annotations are in lexicographical order of FQN:
+    // @com.google.auto.value.processor.PropertyAnnotationsTest.InheritedAnnotation precedes
+    // @java.lang.Deprecated
     JavaFileObject outputFile =
         new OutputFileBuilder()
             .setImports(imports)
-            .addMethodAnnotations("@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation")
-            .addFieldAnnotations("@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation")
+            .addMethodAnnotations("@PropertyAnnotationsTest.InheritedAnnotation", "@Deprecated")
+            .addFieldAnnotations("@PropertyAnnotationsTest.InheritedAnnotation", "@Deprecated")
             .build();
 
     Compilation compilation =
@@ -548,12 +551,16 @@
             .addInnerTypes("@Target(ElementType.METHOD) @interface MethodsOnly {}")
             .build();
 
+    // Annotations are in lexicographical order of FQN:
+    // @com.google.auto.value.processor.PropertyAnnotationsTest.InheritedAnnotation precedes
+    // @foo.bar.Baz.MethodsOnly precedes
+    // @java.lang.Deprecated
     JavaFileObject outputFile =
         new OutputFileBuilder()
             .setImports(getImports(PropertyAnnotationsTest.class))
-            .addFieldAnnotations("@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation")
+            .addFieldAnnotations("@PropertyAnnotationsTest.InheritedAnnotation", "@Deprecated")
             .addMethodAnnotations(
-                "@Deprecated", "@PropertyAnnotationsTest.InheritedAnnotation", "@Baz.MethodsOnly")
+                "@PropertyAnnotationsTest.InheritedAnnotation", "@Baz.MethodsOnly", "@Deprecated")
             .build();
 
     Compilation compilation =
diff --git a/value/userguide/autobuilder.md b/value/userguide/autobuilder.md
index ccd191c..af9058b 100644
--- a/value/userguide/autobuilder.md
+++ b/value/userguide/autobuilder.md
@@ -13,9 +13,6 @@
 has setter methods corresponding to the parameters of a constructor or static
 method. Apart from that, the two are very similar.
 
-AutoBuilder is **unstable** and it is possible that its API
-may change. We do not recommend depending on it for production code yet.
-
 ## Example: calling a constructor
 
 Here is a simple example:
diff --git a/value/userguide/builders-howto.md b/value/userguide/builders-howto.md
index e7cf537..3ff8946 100644
--- a/value/userguide/builders-howto.md
+++ b/value/userguide/builders-howto.md
@@ -154,7 +154,7 @@
 
   abstract Builder toBuilder();
 
-  public Animal withName(String name) {
+  public final Animal withName(String name) {
     return toBuilder().setName(name).build();
   }
 
@@ -201,7 +201,7 @@
 
     abstract Animal autoBuild();  // not public
 
-    public Animal build() {
+    public final Animal build() {
       Animal animal = autoBuild();
       Preconditions.checkState(animal.numberOfLegs() >= 0, "Negative legs");
       return animal;
@@ -235,7 +235,7 @@
 
     abstract Animal autoBuild(); // not public
 
-    public Animal build() {
+    public final Animal build() {
       setName(name().toLowerCase());
       return autoBuild();
     }
@@ -279,8 +279,8 @@
 
     abstract Animal autoBuild(); // not public
 
-    public Animal build() {
-      if (!name().isPresent()) {
+    public final Animal build() {
+      if (name().isEmpty()) {
         setName(numberOfLegs() + "-legged creature");
       }
       return autoBuild();
@@ -491,7 +491,7 @@
     public abstract Builder setNumberOfLegs(int value);
 
     abstract ImmutableSet.Builder<String> countriesBuilder();
-    public Builder addCountry(String value) {
+    public final Builder addCountry(String value) {
       countriesBuilder().add(value);
       return this;
     }
@@ -623,11 +623,75 @@
 
 A [_step builder_](http://rdafbn.blogspot.com/2012/07/step-builder-pattern_28.html)
 is a collection of builder interfaces that take you step by step through the
-setting of each of a list of required properties. We think that these are a nice
-idea in principle but not necessarily in practice. Regardless, if you want to
-use AutoValue to implement a step builder,
-[this example](https://github.com/google/auto/issues/1000#issuecomment-792875738)
-shows you how.
+setting of each of a list of required properties. This means you can be sure at
+compile time that all the properties are set before you build, at the expense of
+some extra code and a bit less flexibility.
+
+Here is an example:
+
+```java
+@AutoValue
+public abstract class Stepped {
+  public abstract String foo();
+  public abstract String bar();
+  public abstract int baz();
+
+  public static FooStep builder() {
+    return new AutoValue_Stepped.Builder();
+  }
+
+  public interface FooStep {
+    BarStep setFoo(String foo);
+  }
+
+  public interface BarStep {
+    BazStep setBar(String bar);
+  }
+
+  public interface BazStep {
+    Build setBaz(int baz);
+  }
+
+  public interface Build {
+    Stepped build();
+  }
+
+  @AutoValue.Builder
+  abstract static class Builder implements FooStep, BarStep, BazStep, Build {}
+}
+```
+
+It might be used like this:
+
+```java
+Stepped stepped = Stepped.builder().setFoo("foo").setBar("bar").setBaz(3).build();
+```
+
+The idea is that the only way to build an instance of `Stepped`
+is to go through the steps imposed by the `FooStep`, `BarStep`, and
+`BazStep` interfaces to set the properties in order, with a final build step.
+
+Once you have set the `baz` property there is nothing else to do except build,
+so you could also combine the `setBaz` and `build` methods like this:
+
+```java
+  ...
+
+  public interface BazStep {
+    Stepped setBazAndBuild(int baz);
+  }
+
+  @AutoValue.Builder
+  abstract static class Builder implements FooStep, BarStep, BazStep {
+    abstract Builder setBaz(int baz);
+    abstract Stepped build();
+
+    @Override
+    public Stepped setBazAndBuild(int baz) {
+      return setBaz(baz).build();
+    }
+  }
+```
 
 ## <a name="autobuilder"></a> ... create a builder for something other than an `@AutoValue`?
 
diff --git a/value/userguide/howto.md b/value/userguide/howto.md
index c451185..0a7607b 100644
--- a/value/userguide/howto.md
+++ b/value/userguide/howto.md
@@ -608,7 +608,7 @@
 ### Copying to the generated class
 
 If you want to copy annotations from your `@AutoValue`-annotated class to the
-generated `AutoValue_...` implemention, annotate your class with
+generated `AutoValue_...` implementation, annotate your class with
 [`@AutoValue.CopyAnnotations`].
 
 For example, if `Example.java` is: