Replace @BlazeRule with a getMetadata() method. This lets us avoid Java Reflection, and saves ~15% of initialization time in []RuleClassProvider.create().

Before change:
Over 14 samples,
average = 976
median = 969.9

After change:
Over 14 samples,
average = 811.5
median = 813.9

--
MOS_MIGRATED_REVID=89036261
diff --git a/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java b/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
index 769c010..0d6f5d6 100644
--- a/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
+++ b/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
@@ -16,7 +16,6 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.TriState;
@@ -204,13 +203,16 @@
       Class<? extends RuleDefinition> usingClass,
       Map<Class<? extends RuleDefinition>, Integer> visited,
       LinkedList<Class<? extends RuleDefinition>> toVisit) {
-    BlazeRule ann = usingClass.getAnnotation(BlazeRule.class);
-    if (ann != null) {
-      for (Class<? extends RuleDefinition> ancestor : ann.ancestors()) {
-        if (!visited.containsKey(ancestor)) {
-          toVisit.addLast(ancestor);
-          visited.put(ancestor, visited.get(usingClass) + 1);
-        }
+    RuleDefinition instance;
+    try {
+      instance = usingClass.newInstance();
+    } catch (IllegalAccessException | InstantiationException e) {
+      throw new IllegalStateException(e);
+    }
+    for (Class<? extends RuleDefinition> ancestor : instance.getMetadata().ancestors()) {
+      if (!visited.containsKey(ancestor)) {
+        toVisit.addLast(ancestor);
+        visited.put(ancestor, visited.get(usingClass) + 1);
       }
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AutoValueRuleDefinitionMetadata.java b/src/main/java/com/google/devtools/build/lib/analysis/AutoValueRuleDefinitionMetadata.java
new file mode 100644
index 0000000..5356889
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AutoValueRuleDefinitionMetadata.java
@@ -0,0 +1,180 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// 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.
+
+/**
+ * TODO(bazel-team): This file has been generated by @AutoValue, and copied here because we do not
+ * support @AutoValue yet. Remove this file and add @AutoValue annotations to RuleDefinition
+ * once possible.
+ */
+package com.google.devtools.build.lib.analysis;
+
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+import java.util.List;
+
+import javax.annotation.Generated;
+
+@Generated("com.google.auto.value.processor.AutoValueProcessor")
+final class AutoValueRuleDefinitionMetadata extends RuleDefinition.Metadata {
+
+  private final String name;
+  private final RuleClassType type;
+  private final Class<? extends RuleConfiguredTargetFactory> factoryClass;
+  private final List<Class<? extends RuleDefinition>> ancestors;
+
+  private AutoValueRuleDefinitionMetadata(
+      String name,
+      RuleClassType type,
+      Class<? extends RuleConfiguredTargetFactory> factoryClass,
+      List<Class<? extends RuleDefinition>> ancestors) {
+    if (name == null) {
+      throw new NullPointerException("Null name");
+    }
+    this.name = name;
+    if (type == null) {
+      throw new NullPointerException("Null type");
+    }
+    this.type = type;
+    if (factoryClass == null) {
+      throw new NullPointerException("Null factoryClass");
+    }
+    this.factoryClass = factoryClass;
+    if (ancestors == null) {
+      throw new NullPointerException("Null ancestors");
+    }
+    this.ancestors = ancestors;
+  }
+
+  @Override
+  public String name() {
+    return name;
+  }
+
+  @Override
+  public RuleClassType type() {
+    return type;
+  }
+
+  @Override
+  public Class<? extends RuleConfiguredTargetFactory> factoryClass() {
+    return factoryClass;
+  }
+
+  @Override
+  public List<Class<? extends RuleDefinition>> ancestors() {
+    return ancestors;
+  }
+
+  @Override
+  public String toString() {
+    return "Metadata{"
+        + "name=" + name + ", "
+        + "type=" + type + ", "
+        + "factoryClass=" + factoryClass + ", "
+        + "ancestors=" + ancestors
+        + "}";
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (o instanceof RuleDefinition.Metadata) {
+      RuleDefinition.Metadata that = (RuleDefinition.Metadata) o;
+      return (this.name.equals(that.name()))
+           && (this.type.equals(that.type()))
+           && (this.factoryClass.equals(that.factoryClass()))
+           && (this.ancestors.equals(that.ancestors()));
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    int h = 1;
+    h *= 1000003;
+    h ^= name.hashCode();
+    h *= 1000003;
+    h ^= type.hashCode();
+    h *= 1000003;
+    h ^= factoryClass.hashCode();
+    h *= 1000003;
+    h ^= ancestors.hashCode();
+    return h;
+  }
+
+  static final class Builder extends RuleDefinition.Metadata.Builder {
+    private String name;
+    private RuleClassType type;
+    private Class<? extends RuleConfiguredTargetFactory> factoryClass;
+    private List<Class<? extends RuleDefinition>> ancestors;
+    Builder() {
+    }
+    Builder(RuleDefinition.Metadata source) {
+      name(source.name());
+      type(source.type());
+      factoryClass(source.factoryClass());
+      ancestors(source.ancestors());
+    }
+    @Override
+    public RuleDefinition.Metadata.Builder name(String name) {
+      this.name = name;
+      return this;
+    }
+    @Override
+    public RuleDefinition.Metadata.Builder type(RuleClassType type) {
+      this.type = type;
+      return this;
+    }
+    @Override
+    public RuleDefinition.Metadata.Builder factoryClass(
+        Class<? extends RuleConfiguredTargetFactory> factoryClass) {
+      this.factoryClass = factoryClass;
+      return this;
+    }
+    @Override
+    public RuleDefinition.Metadata.Builder ancestors(
+        List<Class<? extends RuleDefinition>> ancestors) {
+      this.ancestors = ancestors;
+      return this;
+    }
+    @Override
+    public RuleDefinition.Metadata build() {
+      String missing = "";
+      if (name == null) {
+        missing += " name";
+      }
+      if (type == null) {
+        missing += " type";
+      }
+      if (factoryClass == null) {
+        missing += " factoryClass";
+      }
+      if (ancestors == null) {
+        missing += " ancestors";
+      }
+      if (!missing.isEmpty()) {
+        throw new IllegalStateException("Missing required properties:" + missing);
+      }
+      RuleDefinition.Metadata result = new AutoValueRuleDefinitionMetadata(
+          this.name,
+          this.type,
+          this.factoryClass,
+          this.ancestors);
+      return result;
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
index a14cd53..4b7015f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -123,8 +123,6 @@
   /**
    * A base rule for all test rules.
    */
-  @BlazeRule(name = "$test_base_rule",
-      type = RuleClassType.ABSTRACT)
   public static final class TestBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -169,6 +167,14 @@
           .add(attr(":run_under", LABEL).cfg(DATA).value(RUN_UNDER))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$test_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
@@ -205,8 +211,6 @@
   /**
    * Common parts of rules.
    */
-  @BlazeRule(name = "$base_rule",
-      type = RuleClassType.ABSTRACT)
   public static final class BaseRule implements RuleDefinition {
     @Override
     public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
@@ -234,14 +238,19 @@
           .add(attr(":action_listener", LABEL_LIST).cfg(HOST).value(ACTION_LISTENER))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Common ancestor class for all rules.
    */
-  @BlazeRule(name = "$rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = { BaseRule.class })
   public static final class RuleBase implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -250,6 +259,14 @@
           .add(attr("data", LABEL_LIST).cfg(DATA).allowedFileTypes(FileTypeSet.ANY_FILE))
           .build();
     }
-  }
 
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BaseRule.class)
+          .build();
+    }
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BlazeRule.java b/src/main/java/com/google/devtools/build/lib/analysis/BlazeRule.java
deleted file mode 100644
index c349e65..0000000
--- a/src/main/java/com/google/devtools/build/lib/analysis/BlazeRule.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-//
-// 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.devtools.build.lib.analysis;
-
-import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
-import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * An annotation for rule classes.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface BlazeRule {
-  /**
-   * The name of the rule, as it appears in the BUILD file. If it starts with
-   * '$', the rule will be hidden from users and will only be usable from
-   * inside Blaze.
-   */
-  String name();
-
-  /**
-   * The type of the rule. It can be an abstract rule, a normal rule or a test
-   * rule. If the rule type is abstract, the configured class must not be set.
-   */
-  RuleClassType type() default RuleClassType.NORMAL;
-
-  /**
-   * The {@link RuleConfiguredTargetFactory} class that implements this rule. If the rule is
-   * abstract, this must not be set.
-   */
-  Class<? extends RuleConfiguredTargetFactory> factoryClass()
-      default RuleConfiguredTargetFactory.class;
-
-  /**
-   * The list of other rule classes this rule inherits from.
-   */
-  Class<? extends RuleDefinition>[] ancestors() default {};
-}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 26e0617..ad3cdcd 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -13,10 +13,11 @@
 // limitations under the License.
 package com.google.devtools.build.lib.analysis;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.ABSTRACT;
 import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.TEST;
 
-import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -46,7 +47,6 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -86,6 +86,8 @@
     private final  Map<String, Class<? extends RuleDefinition>> ruleDefinitionMap =
         new HashMap<>();
     private final Map<Class<? extends RuleDefinition>, RuleClass> ruleMap = new HashMap<>();
+    private final Map<Class<? extends RuleDefinition>, RuleDefinition> ruleDefinitionInstanceCache =
+        new HashMap<>();
     private final Digraph<Class<? extends RuleDefinition>> dependencyGraph =
         new Digraph<>();
     private ConfigurationCollectionFactory configurationCollectionFactory;
@@ -106,11 +108,12 @@
       return this;
     }
 
-    public Builder addRuleDefinition(Class<? extends RuleDefinition> ruleDefinition) {
-      dependencyGraph.createNode(ruleDefinition);
-      BlazeRule annotation = ruleDefinition.getAnnotation(BlazeRule.class);
-      for (Class<? extends RuleDefinition> ancestor : annotation.ancestors()) {
-        dependencyGraph.addEdge(ancestor, ruleDefinition);
+    public Builder addRuleDefinition(RuleDefinition ruleDefinition) {
+      Class<? extends RuleDefinition> ruleDefinitionClass = ruleDefinition.getClass();
+      ruleDefinitionInstanceCache.put(ruleDefinitionClass, ruleDefinition);
+      dependencyGraph.createNode(ruleDefinitionClass);
+      for (Class<? extends RuleDefinition> ancestor : ruleDefinition.getMetadata().ancestors()) {
+        dependencyGraph.addEdge(ancestor, ruleDefinitionClass);
       }
 
       return this;
@@ -148,40 +151,38 @@
     }
 
     private RuleClass commitRuleDefinition(Class<? extends RuleDefinition> definitionClass) {
-      BlazeRule annotation = definitionClass.getAnnotation(BlazeRule.class);
-      Preconditions.checkArgument(ruleClassMap.get(annotation.name()) == null, annotation.name());
+      RuleDefinition instance = checkNotNull(ruleDefinitionInstanceCache.get(definitionClass),
+          "addRuleDefinition(new %s()) should be called before build()", definitionClass.getName());
 
-      Preconditions.checkArgument(
-          annotation.type() == ABSTRACT ^
-          annotation.factoryClass() != RuleConfiguredTargetFactory.class);
-      Preconditions.checkArgument(
-          (annotation.type() != TEST) ||
-          Arrays.asList(annotation.ancestors()).contains(
-              BaseRuleClasses.TestBaseRule.class));
+      RuleDefinition.Metadata metadata = instance.getMetadata();
+      checkArgument(ruleClassMap.get(metadata.name()) == null, metadata.name());
 
-      RuleDefinition instance;
-      try {
-        instance = definitionClass.newInstance();
-      } catch (IllegalAccessException | InstantiationException e) {
-        throw new IllegalStateException(e);
-      }
-      RuleClass[] ancestorClasses = new RuleClass[annotation.ancestors().length];
-      for (int i = 0; i < annotation.ancestors().length; i++) {
-        ancestorClasses[i] = ruleMap.get(annotation.ancestors()[i]);
+      List<Class<? extends RuleDefinition>> ancestors = metadata.ancestors();
+
+      checkArgument(
+          metadata.type() == ABSTRACT ^ metadata.factoryClass()
+              != RuleConfiguredTargetFactory.class);
+      checkArgument(
+          (metadata.type() != TEST)
+          || ancestors.contains(BaseRuleClasses.TestBaseRule.class));
+
+      RuleClass[] ancestorClasses = new RuleClass[ancestors.size()];
+      for (int i = 0; i < ancestorClasses.length; i++) {
+        ancestorClasses[i] = ruleMap.get(ancestors.get(i));
         if (ancestorClasses[i] == null) {
           // Ancestors should have been initialized by now
-          throw new IllegalStateException("Ancestor " + annotation.ancestors()[i] + " of "
-              + annotation.name() + " is not initialized");
+          throw new IllegalStateException("Ancestor " + ancestors.get(i) + " of "
+              + metadata.name() + " is not initialized");
         }
       }
 
       RuleConfiguredTargetFactory factory = null;
-      if (annotation.type() != ABSTRACT) {
-        factory = createFactory(annotation.factoryClass());
+      if (metadata.type() != ABSTRACT) {
+        factory = createFactory(metadata.factoryClass());
       }
 
       RuleClass.Builder builder = new RuleClass.Builder(
-          annotation.name(), annotation.type(), false, ancestorClasses);
+          metadata.name(), metadata.type(), false, ancestorClasses);
       builder.factory(factory);
       RuleClass ruleClass = instance.build(builder, this);
       ruleMap.put(definitionClass, ruleClass);
@@ -193,7 +194,7 @@
 
     public ConfiguredRuleClassProvider build() {
       for (Node<Class<? extends RuleDefinition>> ruleDefinition :
-        dependencyGraph.getTopologicalOrder()) {
+          dependencyGraph.getTopologicalOrder()) {
         commitRuleDefinition(ruleDefinition.getLabel());
       }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinition.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinition.java
index c5e32e3..77670d5 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinition.java
@@ -15,6 +15,12 @@
 package com.google.devtools.build.lib.analysis;
 
 import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * This class is a common ancestor for every rule object.
@@ -36,4 +42,64 @@
    * @return the {@link RuleClass} representing the rule.
    */
   RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment);
+
+  /**
+   * Returns metadata for this rule.
+   */
+  Metadata getMetadata();
+
+  /**
+   * Value class that contains the name, type, ancestors of a rule, as well as a reference to the
+   * configured target factory.
+   */
+  public abstract static class Metadata {
+    /**
+     * The name of the rule, as it appears in the BUILD file. If it starts with
+     * '$', the rule will be hidden from users and will only be usable from
+     * inside Blaze.
+     */
+    public abstract String name();
+
+    /**
+     * The type of the rule. It can be an abstract rule, a normal rule or a test
+     * rule. If the rule type is abstract, the configured class must not be set.
+     */
+    public abstract RuleClassType type();
+
+    /**
+     * The {@link RuleConfiguredTargetFactory} class that implements this rule. If the rule is
+     * abstract, this must not be set.
+     */
+    public abstract Class<? extends RuleConfiguredTargetFactory> factoryClass();
+
+    /**
+     * The list of other rule classes this rule inherits from.
+     */
+    public abstract List<Class<? extends RuleDefinition>> ancestors();
+
+    public static Builder builder() {
+      return new AutoValueRuleDefinitionMetadata.Builder()
+          .type(RuleClassType.NORMAL)
+          .factoryClass(RuleConfiguredTargetFactory.class)
+          .ancestors(Collections.<Class<? extends RuleDefinition>>emptyList());
+    }
+
+    public static Metadata empty() {
+      return builder().build();
+    }
+
+    /**
+     * Builder class for the Metadata class.
+     */
+    public abstract static class Builder {
+      public abstract Builder name(String s);
+      public abstract Builder type(RuleClassType type);
+      public abstract Builder factoryClass(Class<? extends RuleConfiguredTargetFactory> factory);
+      public abstract Builder ancestors(List<Class<? extends RuleDefinition>> ancestors);
+      public Builder ancestors(Class<? extends RuleDefinition>... ancstrs) {
+        return ancestors(Arrays.asList(ancstrs));
+      }
+      public abstract Metadata build();
+    }
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigRuleClasses.java
index dd0ba5b..44bb5e7 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigRuleClasses.java
@@ -19,7 +19,6 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -40,9 +39,6 @@
   /**
    * Common settings for all configurability rules.
    */
-  @BlazeRule(name = "$config_base_rule",
-               type = RuleClass.Builder.RuleClassType.ABSTRACT,
-               ancestors = { BaseRuleClasses.BaseRule.class })
   public static final class ConfigBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
@@ -55,6 +51,15 @@
               "these rules don't include content that gets built into their dependers")
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$config_base_rule")
+          .type(RuleClass.Builder.RuleClassType.ABSTRACT)
+          .ancestors(BaseRuleClasses.BaseRule.class)
+          .build();
+    }
   }
 
   /**
@@ -85,10 +90,6 @@
    * themselves inputs to that map. So Bazel has special logic to read and properly apply
    * config_setting instances. See {@link ConfiguredTargetFunction#getConfigConditions} for details.
    */
-  @BlazeRule(name = "config_setting",
-               type = RuleClass.Builder.RuleClassType.NORMAL,
-               ancestors = { ConfigBaseRule.class },
-               factoryClass = ConfigSetting.class)
   public static final class ConfigSettingRule implements RuleDefinition {
     /**
      * The name of the attribute that declares flag bindings.
@@ -137,6 +138,16 @@
               .nonconfigurable(NONCONFIGURABLE_ATTRIBUTE_REASON))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("config_setting")
+          .type(RuleClass.Builder.RuleClassType.NORMAL)
+          .ancestors(ConfigBaseRule.class)
+          .factoryClass(ConfigSetting.class)
+          .build();
+    }
   }
 
 /*<!-- #BLAZE_RULE (NAME = config_setting, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentRule.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentRule.java
index 58116e8..8330dba 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentRule.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentRule.java
@@ -18,7 +18,6 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,9 +27,6 @@
 /**
  * Rule definition for environment rules (for Bazel's constraint enforcement system).
  */
-@BlazeRule(name = EnvironmentRule.RULE_NAME,
-    ancestors = { BaseRuleClasses.BaseRule.class },
-    factoryClass = Environment.class)
 public final class EnvironmentRule implements RuleDefinition {
   public static final String RULE_NAME = "environment";
 
@@ -67,4 +63,13 @@
         .setUndocumented()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(EnvironmentRule.RULE_NAME)
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .factoryClass(Environment.class)
+        .build();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 988afec..b3f5099 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -19,6 +19,7 @@
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.bazel.repository.HttpArchiveFunction;
 import com.google.devtools.build.lib.bazel.repository.HttpDownloadFunction;
 import com.google.devtools.build.lib.bazel.repository.HttpJarFunction;
@@ -84,7 +85,14 @@
   @Override
   public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) {
     for (Entry<String, RepositoryFunction> handler : repositoryHandlers.entrySet()) {
-      builder.addRuleDefinition(handler.getValue().getRuleDefinition());
+      // TODO(bazel-team): Migrate away from Class<?>
+      RuleDefinition ruleDefinition;
+      try {
+        ruleDefinition = handler.getValue().getRuleDefinition().newInstance();
+      } catch (IllegalAccessException | InstantiationException e) {
+        throw new IllegalStateException(e);
+      }
+      builder.addRuleDefinition(ruleDefinition);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java
index a1b27fe..669431b 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java
@@ -21,7 +21,6 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -41,8 +40,6 @@
   /**
    * A base rule for all binary rules.
    */
-  @BlazeRule(name = "$binary_base_rule",
-               type = RuleClassType.ABSTRACT)
   public static final class BinaryBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -54,14 +51,19 @@
               .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$binary_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Rule class for rules in error.
    */
-  @BlazeRule(name = "$error_rule",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { BaseRuleClasses.BaseRule.class })
   public static final class ErrorRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -69,5 +71,14 @@
           .publicByDefault()
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$error_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BaseRuleClasses.BaseRule.class)
+          .build();
+    }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 0a43d80..909eec8 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -54,6 +54,7 @@
 import com.google.devtools.build.lib.bazel.rules.workspace.MavenJarRule;
 import com.google.devtools.build.lib.bazel.rules.workspace.NewHttpArchiveRule;
 import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceBaseRule;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.PackageGroup;
 import com.google.devtools.build.lib.packages.Rule;
@@ -193,90 +194,94 @@
       builder.addConfigurationOptions(fragmentOptions);
     }
 
-    builder.addRuleDefinition(BaseRuleClasses.BaseRule.class);
-    builder.addRuleDefinition(BaseRuleClasses.RuleBase.class);
-    builder.addRuleDefinition(BazelBaseRuleClasses.BinaryBaseRule.class);
-    builder.addRuleDefinition(BaseRuleClasses.TestBaseRule.class);
-    builder.addRuleDefinition(BazelBaseRuleClasses.ErrorRule.class);
+    builder.addRuleDefinition(new WorkspaceBaseRule());
 
-    builder.addRuleDefinition(EnvironmentRule.class);
+    builder.addRuleDefinition(new BaseRuleClasses.BaseRule());
+    builder.addRuleDefinition(new BaseRuleClasses.RuleBase());
+    builder.addRuleDefinition(new BazelBaseRuleClasses.BinaryBaseRule());
+    builder.addRuleDefinition(new BaseRuleClasses.TestBaseRule());
+    builder.addRuleDefinition(new BazelBaseRuleClasses.ErrorRule());
 
-    builder.addRuleDefinition(ConfigRuleClasses.ConfigBaseRule.class);
-    builder.addRuleDefinition(ConfigRuleClasses.ConfigSettingRule.class);
+    builder.addRuleDefinition(new EnvironmentRule());
 
-    builder.addRuleDefinition(BazelFilegroupRule.class);
-    builder.addRuleDefinition(BazelTestSuiteRule.class);
-    builder.addRuleDefinition(BazelGenRuleRule.class);
-    builder.addRuleDefinition(GenQueryRule.class);
+    builder.addRuleDefinition(new ConfigRuleClasses.ConfigBaseRule());
+    builder.addRuleDefinition(new ConfigRuleClasses.ConfigSettingRule());
 
-    builder.addRuleDefinition(BazelShRuleClasses.ShRule.class);
-    builder.addRuleDefinition(BazelShLibraryRule.class);
-    builder.addRuleDefinition(BazelShBinaryRule.class);
-    builder.addRuleDefinition(BazelShTestRule.class);
+    builder.addRuleDefinition(new BazelFilegroupRule());
+    builder.addRuleDefinition(new BazelTestSuiteRule());
+    builder.addRuleDefinition(new BazelGenRuleRule());
+    builder.addRuleDefinition(new GenQueryRule());
 
-    builder.addRuleDefinition(CcToolchainRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcLinkingRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcDeclRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcBaseRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcBinaryBaseRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcBinaryRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcTestRule.class);
+    builder.addRuleDefinition(new BazelShRuleClasses.ShRule());
+    builder.addRuleDefinition(new BazelShLibraryRule());
+    builder.addRuleDefinition(new BazelShBinaryRule());
+    builder.addRuleDefinition(new BazelShTestRule());
 
-    builder.addRuleDefinition(BazelCppRuleClasses.CcLibraryBaseRule.class);
-    builder.addRuleDefinition(BazelCppRuleClasses.CcLibraryRule.class);
+    builder.addRuleDefinition(new CcToolchainRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcLinkingRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcDeclRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcBaseRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryBaseRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcBinaryRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcTestRule());
+
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule());
+    builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryRule());
 
     builder.addWorkspaceFile(BazelJavaRuleClasses.getDefaultWorkspace());
-    builder.addRuleDefinition(BazelJavaRuleClasses.BaseJavaBinaryRule.class);
-    builder.addRuleDefinition(BazelJavaRuleClasses.IjarBaseRule.class);
-    builder.addRuleDefinition(BazelJavaRuleClasses.JavaBaseRule.class);
-    builder.addRuleDefinition(JavaImportBaseRule.class);
-    builder.addRuleDefinition(BazelJavaRuleClasses.JavaRule.class);
-    builder.addRuleDefinition(BazelJavaBinaryRule.class);
-    builder.addRuleDefinition(BazelJavaLibraryRule.class);
-    builder.addRuleDefinition(BazelJavaImportRule.class);
-    builder.addRuleDefinition(BazelJavaTestRule.class);
-    builder.addRuleDefinition(BazelJavaPluginRule.class);
-    builder.addRuleDefinition(JavaToolchainRule.class);
+    builder.addRuleDefinition(new BazelJavaRuleClasses.BaseJavaBinaryRule());
+    builder.addRuleDefinition(new BazelJavaRuleClasses.IjarBaseRule());
+    builder.addRuleDefinition(new BazelJavaRuleClasses.JavaBaseRule());
+    builder.addRuleDefinition(new JavaImportBaseRule());
+    builder.addRuleDefinition(new BazelJavaRuleClasses.JavaRule());
+    builder.addRuleDefinition(new BazelJavaBinaryRule());
+    builder.addRuleDefinition(new BazelJavaLibraryRule());
+    builder.addRuleDefinition(new BazelJavaImportRule());
+    builder.addRuleDefinition(new BazelJavaTestRule());
+    builder.addRuleDefinition(new BazelJavaPluginRule());
+    builder.addRuleDefinition(new JavaToolchainRule());
 
-    builder.addRuleDefinition(BazelIosTestRule.class);
-    builder.addRuleDefinition(IosDeviceRule.class);
-    builder.addRuleDefinition(ObjcBinaryRule.class);
-    builder.addRuleDefinition(ObjcBundleRule.class);
-    builder.addRuleDefinition(ObjcBundleLibraryRule.class);
-    builder.addRuleDefinition(ObjcFrameworkRule.class);
-    builder.addRuleDefinition(ObjcImportRule.class);
-    builder.addRuleDefinition(ObjcLibraryRule.class);
-    builder.addRuleDefinition(ObjcOptionsRule.class);
-    builder.addRuleDefinition(ObjcProtoLibraryRule.class);
-    builder.addRuleDefinition(ObjcXcodeprojRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.IosTestBaseRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.BundlingRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.ReleaseBundlingRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.SimulatorRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.CompilingRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.LinkingRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.ResourcesRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.XcodegenRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.AlwaysLinkRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.OptionsRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.SdkFrameworksDependerRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.CompileDependencyRule.class);
-    builder.addRuleDefinition(ObjcRuleClasses.ResourceToolsRule.class);
-    builder.addRuleDefinition(IosApplicationRule.class);
-    builder.addRuleDefinition(IosExtensionBinaryRule.class);
-    builder.addRuleDefinition(IosExtensionRule.class);
+    builder.addRuleDefinition(new BazelIosTestRule());
+    builder.addRuleDefinition(new IosDeviceRule());
+    builder.addRuleDefinition(new ObjcBinaryRule());
+    builder.addRuleDefinition(new ObjcBundleRule());
+    builder.addRuleDefinition(new ObjcBundleLibraryRule());
+    builder.addRuleDefinition(new ObjcFrameworkRule());
+    builder.addRuleDefinition(new ObjcImportRule());
+    builder.addRuleDefinition(new ObjcLibraryRule());
+    builder.addRuleDefinition(new ObjcOptionsRule());
+    builder.addRuleDefinition(new ObjcProtoLibraryRule());
+    builder.addRuleDefinition(new ObjcXcodeprojRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.CoptsRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.ObjcProtoRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.IosTestBaseRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.BundlingRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.ReleaseBundlingRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.SimulatorRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.CompilingRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.LinkingRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.ResourcesRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.XcodegenRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.AlwaysLinkRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.OptionsRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.SdkFrameworksDependerRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.CompileDependencyRule());
+    builder.addRuleDefinition(new ObjcRuleClasses.ResourceToolsRule());
+    builder.addRuleDefinition(new IosApplicationRule());
+    builder.addRuleDefinition(new IosExtensionBinaryRule());
+    builder.addRuleDefinition(new IosExtensionRule());
 
-    builder.addRuleDefinition(BazelExtraActionRule.class);
-    builder.addRuleDefinition(BazelActionListenerRule.class);
+    builder.addRuleDefinition(new BazelExtraActionRule());
+    builder.addRuleDefinition(new BazelActionListenerRule());
 
-    builder.addRuleDefinition(BindRule.class);
-    builder.addRuleDefinition(HttpArchiveRule.class);
-    builder.addRuleDefinition(HttpJarRule.class);
-    builder.addRuleDefinition(LocalRepositoryRule.class);
-    builder.addRuleDefinition(MavenJarRule.class);
-    builder.addRuleDefinition(NewHttpArchiveRule.class);
-    builder.addRuleDefinition(NewLocalRepositoryRule.class);
+    builder.addRuleDefinition(new BindRule());
+    builder.addRuleDefinition(new HttpArchiveRule());
+    builder.addRuleDefinition(new HttpJarRule());
+    builder.addRuleDefinition(new LocalRepositoryRule());
+    builder.addRuleDefinition(new MavenJarRule());
+    builder.addRuleDefinition(new NewHttpArchiveRule());
+    builder.addRuleDefinition(new NewLocalRepositoryRule());
 
     builder.addConfigurationFragment(new BazelConfiguration.Loader());
     builder.addConfigurationFragment(new CppConfigurationLoader(
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java
index 0865c34..26b3745 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,9 +27,6 @@
 /**
  * Rule definition for action_listener rule.
  */
-@BlazeRule(name = "action_listener",
-             ancestors = { BaseRuleClasses.RuleBase.class },
-             factoryClass = ActionListener.class)
 public final class BazelActionListenerRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -59,6 +55,15 @@
         .removeAttribute(":action_listener")
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("action_listener")
+        .ancestors(BaseRuleClasses.RuleBase.class)
+        .factoryClass(ActionListener.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = action_listener, TYPE = BINARY, FAMILY = Extra Actions)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java
index efc4e46..94aac28 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java
@@ -21,7 +21,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -31,9 +30,6 @@
 /**
  * Rule definition for extra_action rule.
  */
-@BlazeRule(name = "extra_action",
-             ancestors = { BaseRuleClasses.RuleBase.class },
-             factoryClass = ExtraActionFactory.class)
 public final class BazelExtraActionRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -122,6 +118,15 @@
         .removeAttribute(":action_listener")
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("extra_action")
+        .ancestors(BaseRuleClasses.RuleBase.class)
+        .factoryClass(ExtraActionFactory.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = extra_action, TYPE = LIBRARY, FAMILY = Extra Actions)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java
index 23d7c9c..9884200 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java
@@ -20,7 +20,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -31,9 +30,6 @@
 /**
  * Rule object implementing "filegroup".
  */
-@BlazeRule(name = "filegroup",
-             ancestors = { BaseRuleClasses.BaseRule.class },
-             factoryClass = Filegroup.class)
 public final class BazelFilegroupRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -76,6 +72,15 @@
         .add(attr("path", STRING))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("filegroup")
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .factoryClass(Filegroup.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = filegroup, TYPE = BINARY, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java
index 9dad80e..348eb30 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,9 +27,6 @@
 /**
  * Rule object implementing "test_suite".
  */
-@BlazeRule(name = "test_suite",
-             ancestors = { BaseRuleClasses.BaseRule.class },
-             factoryClass = TestSuite.class)
 public final class BazelTestSuiteRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -103,6 +99,15 @@
             .nonconfigurable("Accessed in TestTargetUtils without config context"))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("test_suite")
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .factoryClass(TestSuite.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = test_suite, TYPE = TEST, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index 7272555..7e92d2e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -39,7 +39,6 @@
 
 import com.google.common.base.Predicates;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
@@ -208,8 +207,6 @@
    * Common attributes for all rules that create C++ links. This may
    * include non-cc_* rules (e.g. py_binary).
    */
-  @BlazeRule(name = "$cc_linking_rule",
-               type = RuleClassType.ABSTRACT)
   public static final class CcLinkingRule implements RuleDefinition {
     @Override
     @SuppressWarnings("unchecked")
@@ -219,14 +216,19 @@
           .setPreferredDependencyPredicate(Predicates.<String>or(CPP_SOURCE, C_SOURCE, CPP_HEADER))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_linking_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Common attributes for C++ rules.
    */
-  @BlazeRule(name = "$cc_base_rule",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { CcLinkingRule.class })
   public static final class CcBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -246,14 +248,20 @@
           .add(attr(":stl", LABEL).value(STL))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CcLinkingRule.class)
+          .build();
+    }
   }
 
   /**
    * Helper rule class.
    */
-  @BlazeRule(name = "$cc_decl_rule",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { BaseRuleClasses.RuleBase.class })
   public static final class CcDeclRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -355,14 +363,20 @@
               .value(LIPO_CONTEXT_COLLECTOR))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_decl_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BaseRuleClasses.RuleBase.class)
+          .build();
+    }
   }
 
   /**
    * Helper rule class.
    */
-  @BlazeRule(name = "$cc_rule",
-             type = RuleClassType.ABSTRACT,
-             ancestors = { CcDeclRule.class, CcBaseRule.class })
   public static final class CcRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
@@ -546,14 +560,19 @@
           }))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CcDeclRule.class, CcBaseRule.class)
+          .build();
+    }
   }
 
   /**
    * Helper rule class.
    */
-  @BlazeRule(name = "$cc_binary_base",
-             type = RuleClassType.ABSTRACT,
-             ancestors = CcRule.class)
   public static final class CcBinaryBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -594,15 +613,19 @@
           .add(attr("stamp", TRISTATE).value(TriState.AUTO))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_binary_base")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CcRule.class)
+          .build();
+    }
   }
 
   /**
    * Rule definition for cc_binary rules.
    */
-  @BlazeRule(name = "cc_binary",
-               ancestors = { CcBinaryBaseRule.class,
-                             BazelBaseRuleClasses.BinaryBaseRule.class },
-               factoryClass = BazelCcBinary.class)
   public static final class CcBinaryRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -650,6 +673,14 @@
           .cfg(LIPO_ON_DEMAND)
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("cc_binary")
+          .ancestors(CcBinaryBaseRule.class, BazelBaseRuleClasses.BinaryBaseRule.class)
+          .factoryClass(BazelCcBinary.class)
+          .build();
+    }
   }
 
   /**
@@ -667,10 +698,6 @@
   /**
    * Rule definition for cc_test rules.
    */
-  @BlazeRule(name = "cc_test",
-      type = RuleClassType.TEST,
-      ancestors = { CcBinaryBaseRule.class, BaseRuleClasses.TestBaseRule.class },
-      factoryClass = BazelCcTest.class)
   public static final class CcTestRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -681,14 +708,20 @@
           .add(attr(":lipo_context", LABEL).value(LIPO_CONTEXT))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("cc_test")
+          .type(RuleClassType.TEST)
+          .ancestors(CcBinaryBaseRule.class, BaseRuleClasses.TestBaseRule.class)
+          .factoryClass(BazelCcTest.class)
+          .build();
+    }
   }
 
   /**
    * Helper rule class.
    */
-  @BlazeRule(name = "$cc_library",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { CcRule.class })
   public static final class CcLibraryBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -717,14 +750,19 @@
           .add(attr("linkstamp", LABEL).allowedFileTypes(CPP_SOURCE, C_SOURCE))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_library")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CcRule.class)
+          .build();
+    }
   }
 
   /**
    * Rule definition for the cc_library rule.
    */
-  @BlazeRule(name = "cc_library",
-               ancestors = { CcLibraryBaseRule.class},
-               factoryClass = BazelCcLibrary.class)
   public static final class CcLibraryRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -769,6 +807,14 @@
               .nonconfigurable("value is referenced in an ImplicitOutputsFunction"))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("cc_library")
+          .ancestors(CcLibraryBaseRule.class)
+          .factoryClass(BazelCcLibrary.class)
+          .build();
+    }
   }
 }
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java
index f5ceed6..193dfb3 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java
@@ -23,7 +23,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -35,9 +34,6 @@
 /**
  * Rule definition for the genrule rule.
  */
-@BlazeRule(name = "genrule",
-           ancestors = { BaseRuleClasses.RuleBase.class },
-           factoryClass = GenRule.class)
 public final class BazelGenRuleRule implements RuleDefinition {
   public static final String GENRULE_SETUP_LABEL = "//tools/genrule:genrule-setup.sh";
 
@@ -232,6 +228,15 @@
         .removeAttribute("deps")
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("genrule")
+        .ancestors(BaseRuleClasses.RuleBase.class)
+        .factoryClass(GenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = genrule, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java
index 63fb47b..80e3e37 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses;
@@ -30,10 +29,6 @@
 /**
  * Rule definition for the java_binary rule.
  */
-@BlazeRule(name = "java_binary",
-           ancestors = { BaseJavaBinaryRule.class,
-                         BazelBaseRuleClasses.BinaryBaseRule.class },
-           factoryClass = BazelJavaBinary.class)
 public final class BazelJavaBinaryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -81,6 +76,15 @@
             }))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_binary")
+        .ancestors(BaseJavaBinaryRule.class, BazelBaseRuleClasses.BinaryBaseRule.class)
+        .factoryClass(BazelJavaBinary.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = java_binary, TYPE = BINARY, FAMILY = Java) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java
index 4f6a585..e1ebaec 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java
@@ -19,7 +19,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.IjarBaseRule;
@@ -30,9 +29,6 @@
 /**
  * Rule definition for the java_import rule.
  */
-@BlazeRule(name = "java_import",
-             ancestors = { JavaImportBaseRule.class, IjarBaseRule.class },
-             factoryClass = BazelJavaImport.class)
 public final class BazelJavaImportRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -50,6 +46,15 @@
         .build();
 
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_import")
+        .ancestors(JavaImportBaseRule.class, IjarBaseRule.class)
+        .factoryClass(BazelJavaImport.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = java_import, TYPE = LIBRARY, FAMILY = Java) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java
index 0c340de..eef56df 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java
@@ -20,7 +20,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.JavaRule;
@@ -30,9 +29,6 @@
 /**
  * Common attributes for Java rules.
  */
-@BlazeRule(name = "java_library",
-             ancestors = { JavaRule.class },
-             factoryClass = BazelJavaLibrary.class)
 public final class BazelJavaLibraryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
@@ -148,6 +144,15 @@
             .legacyAllowAnyFileType())
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_library")
+        .ancestors(JavaRule.class)
+        .factoryClass(BazelJavaLibrary.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = java_library, TYPE = LIBRARY, FAMILY = Java) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
index cef463b..834f683 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -27,9 +26,6 @@
 /**
  * Rule definition for the java_plugin rule.
  */
-@BlazeRule(name = "java_plugin",
-             ancestors = { BazelJavaLibraryRule.class },
-             factoryClass = BazelJavaPlugin.class)
 public final class BazelJavaPluginRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -58,6 +54,15 @@
         .removeAttribute("exported_plugins")
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_plugin")
+        .ancestors(BazelJavaLibraryRule.class)
+        .factoryClass(BazelJavaPlugin.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = java_plugin, TYPE = OTHER, FAMILY = Java) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index 1f36158..f11a3ca 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -26,7 +26,6 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
@@ -62,8 +61,6 @@
   /**
    * Common attributes for rules that depend on ijar.
    */
-  @BlazeRule(name = "$ijar_base_rule",
-               type = RuleClassType.ABSTRACT)
   public static final class IjarBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -72,15 +69,20 @@
           .setPreferredDependencyPredicate(JavaSemantics.JAVA_SOURCE)
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$ijar_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
 
   /**
    * Common attributes for Java rules.
    */
-  @BlazeRule(name = "$java_base_rule",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { IjarBaseRule.class })
   public static final class JavaBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -98,6 +100,15 @@
               .value(env.getLabel(JavaSemantics.SINGLEJAR_LABEL)))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$java_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(IjarBaseRule.class)
+          .build();
+    }
   }
 
   static final Set<String> ALLOWED_RULES_IN_DEPS = ImmutableSet.of(
@@ -113,9 +124,6 @@
   /**
    * Common attributes for Java rules.
    */
-  @BlazeRule(name = "$java_rule",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { BaseRuleClasses.RuleBase.class, JavaBaseRule.class })
   public static final class JavaRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -219,18 +227,20 @@
           .add(attr("javacopts", STRING_LIST))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$java_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BaseRuleClasses.RuleBase.class, JavaBaseRule.class)
+          .build();
+    }
   }
 
   /**
    * Base class for rule definitions producing Java binaries.
    */
-  @BlazeRule(name = "$base_java_binary",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { JavaRule.class,
-                             // java_binary and java_test require the crosstool C++ runtime
-                             // libraries (libstdc++.so, libgcc_s.so).
-                             // TODO(bazel-team): Add tests for Java+dynamic runtime.
-                             BazelCppRuleClasses.CcLinkingRule.class })
   public static final class BaseJavaBinaryRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
@@ -312,6 +322,18 @@
           .add(attr(":java_launcher", LABEL).value(JavaSemantics.JAVA_LAUNCHER))  // blaze flag
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$base_java_binary")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(JavaRule.class,
+              // java_binary and java_test require the crosstool C++ runtime
+              // libraries (libstdc++.so, libgcc_s.so).
+              // TODO(bazel-team): Add tests for Java+dynamic runtime.
+              BazelCppRuleClasses.CcLinkingRule.class)
+          .build();
+    }
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
index 24eb6a8..1921d18 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
@@ -20,7 +20,6 @@
 import static com.google.devtools.build.lib.packages.Type.TRISTATE;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.BaseJavaBinaryRule;
@@ -33,11 +32,6 @@
 /**
  * Rule definition for the java_test rule.
  */
-@BlazeRule(name = "java_test",
-           type = RuleClassType.TEST,
-           ancestors = { BaseJavaBinaryRule.class,
-                         BaseRuleClasses.TestBaseRule.class },
-           factoryClass = BazelJavaTest.class)
 public final class BazelJavaTestRule implements RuleDefinition {
 
   private static final String JUNIT4_RUNNER = "org.junit.runner.JUnitCore";
@@ -58,6 +52,16 @@
         .override(attr(":java_launcher", LABEL).value(JavaSemantics.JAVA_LAUNCHER))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_test")
+        .type(RuleClassType.TEST)
+        .ancestors(BaseJavaBinaryRule.class, BaseRuleClasses.TestBaseRule.class)
+        .factoryClass(BazelJavaTest.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = java_test, TYPE = TEST, FAMILY = Java) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java
index d2454a3..40c254e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
@@ -31,13 +30,6 @@
 /**
  * Rule definition for the ios_test rule.
  */
-@BlazeRule(name = "ios_test",
-    type = RuleClassType.TEST,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        BaseRuleClasses.TestBaseRule.class,
-        ObjcRuleClasses.IosTestBaseRule.class, },
-    factoryClass = BazelIosTest.class)
 public final class BazelIosTestRule implements RuleDefinition {
   @Override
   public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) {
@@ -56,6 +48,17 @@
             .value(env.getLabel("//tools/objc:ios_test_on_bazel")).exec())
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("ios_test")
+        .type(RuleClassType.TEST)
+        .ancestors(BaseRuleClasses.BaseRule.class, BaseRuleClasses.TestBaseRule.class,
+            ObjcRuleClasses.IosTestBaseRule.class)
+        .factoryClass(BazelIosTest.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = ios_test, TYPE = TEST, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
index 1a2a232..7ea0f0a 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
@@ -13,7 +13,6 @@
 // limitations under the License.
 package com.google.devtools.build.lib.bazel.rules.sh;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses;
@@ -24,14 +23,20 @@
 /**
  * Rule definition for the sh_binary rule.
  */
-@BlazeRule(name = "sh_binary",
-             ancestors = { ShRule.class, BazelBaseRuleClasses.BinaryBaseRule.class },
-             factoryClass = ShBinary.class)
 public final class BazelShBinaryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
     return builder.build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("sh_binary")
+        .ancestors(ShRule.class, BazelBaseRuleClasses.BinaryBaseRule.class)
+        .factoryClass(ShBinary.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = sh_binary, TYPE = BINARY, FAMILY = Shell) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java
index 552d99a..6f41efa 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java
@@ -16,7 +16,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses.ShRule;
@@ -26,9 +25,6 @@
 /**
  * Rule definition for the sh_library rule.
  */
-@BlazeRule(name = "sh_library",
-             ancestors = { ShRule.class },
-             factoryClass = ShLibrary.class)
 public final class BazelShLibraryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -45,6 +41,15 @@
         .override(attr("srcs", LABEL_LIST).allowedFileTypes(BazelShRuleClasses.SH_FILES))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("sh_library")
+        .ancestors(ShRule.class)
+        .factoryClass(ShLibrary.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = sh_library, TYPE = LIBRARY, FAMILY = Shell) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java
index 616ff64..5414530 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java
@@ -19,9 +19,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
@@ -50,9 +48,6 @@
   /**
    * Common attributes for shell rules.
    */
-  @BlazeRule(name = "$sh_target",
-               type = RuleClassType.ABSTRACT,
-               ancestors = { BaseRuleClasses.RuleBase.class })
   public static final class ShRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -87,6 +82,15 @@
               .allowedFileTypes())
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$sh_target")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BaseRuleClasses.RuleBase.class)
+          .build();
+    }
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
index 23e2be0..580f961 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
@@ -14,7 +14,6 @@
 package com.google.devtools.build.lib.bazel.rules.sh;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses.ShRule;
@@ -25,15 +24,21 @@
 /**
  * Rule definition for the sh_test rule.
  */
-@BlazeRule(name = "sh_test",
-             type = RuleClassType.TEST,
-             ancestors = { ShRule.class, BaseRuleClasses.TestBaseRule.class },
-             factoryClass = ShBinary.class)
 public final class BazelShTestRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
     return builder.build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("sh_test")
+        .type(RuleClassType.TEST)
+        .ancestors(ShRule.class, BaseRuleClasses.TestBaseRule.class)
+        .factoryClass(ShBinary.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = sh_test, TYPE = TEST, FAMILY = Shell) -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java
index 5da1ae9..2550d8e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Rule definition for the http_archive rule.
  */
-@BlazeRule(name = HttpArchiveRule.NAME,
-  type = RuleClassType.WORKSPACE,
-  ancestors = { WorkspaceBaseRule.class },
-  factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class HttpArchiveRule implements RuleDefinition {
 
   public static final String NAME = "http_archive";
@@ -56,6 +51,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(HttpArchiveRule.NAME)
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = http_archive, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java
index 8c7d4ce..5d5d0e5 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Rule definition for the http_jar rule.
  */
-@BlazeRule(name = HttpJarRule.NAME,
-  type = RuleClassType.WORKSPACE,
-  ancestors = { WorkspaceBaseRule.class },
-  factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class HttpJarRule implements RuleDefinition {
 
   public static final String NAME = "http_jar";
@@ -55,6 +50,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(HttpJarRule.NAME)
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = http_jar, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java
index d03ef39..b283ced 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Rule definition for the local_repository rule.
  */
-@BlazeRule(name = LocalRepositoryRule.NAME,
-  type = RuleClassType.WORKSPACE,
-  ancestors = { WorkspaceBaseRule.class },
-  factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class LocalRepositoryRule implements RuleDefinition {
 
   public static final String NAME = "local_repository";
@@ -49,6 +44,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(LocalRepositoryRule.NAME)
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = local_repository, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java
index a897e3e..056e946 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java
@@ -16,7 +16,6 @@
 
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Rule definition for the maven_jar rule.
  */
-@BlazeRule(name = MavenJarRule.NAME,
-           type = RuleClassType.WORKSPACE,
-           ancestors = { WorkspaceBaseRule.class },
-           factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class MavenJarRule implements RuleDefinition {
 
   public static final String NAME = "maven_jar";
@@ -81,6 +76,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(MavenJarRule.NAME)
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = maven_jar, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewHttpArchiveRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewHttpArchiveRule.java
index 131bbac..a0cb2ba 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewHttpArchiveRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewHttpArchiveRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -25,10 +24,6 @@
 /**
  * Rule definition for the new_http_archive rule.
  */
-@BlazeRule(name = NewHttpArchiveRule.NAME,
-    type = RuleClass.Builder.RuleClassType.WORKSPACE,
-    ancestors = { WorkspaceBaseRule.class },
-    factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class NewHttpArchiveRule implements RuleDefinition {
   public static final String NAME = "new_http_archive";
 
@@ -62,6 +57,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(NewHttpArchiveRule.NAME)
+        .type(RuleClass.Builder.RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = new_http_archive, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java
index f8f8b85..67aa27f 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java
@@ -17,7 +17,6 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Rule definition for the new_repository rule.
  */
-@BlazeRule(name = NewLocalRepositoryRule.NAME,
-           type = RuleClassType.WORKSPACE,
-           ancestors = { WorkspaceBaseRule.class },
-           factoryClass = WorkspaceConfiguredTargetFactory.class)
 public class NewLocalRepositoryRule implements RuleDefinition {
   public static final String NAME = "new_local_repository";
 
@@ -56,6 +51,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name(NewLocalRepositoryRule.NAME)
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(WorkspaceBaseRule.class)
+        .factoryClass(WorkspaceConfiguredTargetFactory.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = new_local_repository, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java
index 82a5270..d7e0999 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java
@@ -14,7 +14,6 @@
 
 package com.google.devtools.build.lib.bazel.rules.workspace;
 
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -24,8 +23,6 @@
 /**
  * Base rule for rules in the WORKSPACE file.
  */
-@BlazeRule(name = "$workspace_base_rule",
-           type = RuleClassType.ABSTRACT)
 public class WorkspaceBaseRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -33,4 +30,12 @@
         .exemptFromConstraintChecking("workspace rules aren't built for target environments")
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("$workspace_base_rule")
+        .type(RuleClassType.ABSTRACT)
+        .build();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
index 6c68f00..3069037 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
@@ -22,7 +22,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
@@ -35,9 +34,6 @@
 /**
  * Rule definition for compiler definition.
  */
-@BlazeRule(name = "cc_toolchain",
-             ancestors = { BaseRuleClasses.BaseRule.class },
-             factoryClass = CcToolchain.class)
 public final class CcToolchainRule implements RuleDefinition {
   private static final LateBoundLabel<BuildConfiguration> LIBC_LINK =
       new LateBoundLabel<BuildConfiguration>() {
@@ -68,4 +64,13 @@
         .add(attr(":libc_link", LABEL).cfg(HOST).value(LIBC_LINK))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("cc_toolchain")
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .factoryClass(CcToolchain.class)
+        .build();
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQueryRule.java b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQueryRule.java
index f3186af..40647fb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQueryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQueryRule.java
@@ -21,7 +21,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -30,9 +29,6 @@
 /**
  * Rule definition for genquery the rule.
  */
-@BlazeRule(name = "genquery",
-             ancestors = { BaseRuleClasses.RuleBase.class },
-             factoryClass = GenQuery.class)
 public final class GenQueryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -66,6 +62,15 @@
         .add(attr("opts", STRING_LIST))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("genquery")
+        .ancestors(BaseRuleClasses.RuleBase.class)
+        .factoryClass(GenQuery.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = genquery, TYPE = LIBRARY, FAMILY = General)[GENERIC_RULE] -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java
index b153b58..676e933 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImportBaseRule.java
@@ -22,7 +22,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -32,9 +31,6 @@
 /**
  * A base rule for building the java_import rule.
  */
-@BlazeRule(name = "$java_import_base",
-           type = RuleClassType.ABSTRACT,
-           ancestors = { BaseRuleClasses.RuleBase.class })
 public class JavaImportBaseRule implements RuleDefinition {
 
   @Override
@@ -78,6 +74,15 @@
             .nonconfigurable("used in Attribute.validityPredicate implementations (loading time)"))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("$java_import_base")
+        .type(RuleClassType.ABSTRACT)
+        .ancestors(BaseRuleClasses.RuleBase.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = java_import, TYPE = LIBRARY, FAMILY = Java) -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
index 16801ee..5da931d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
@@ -19,7 +19,6 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,8 +27,6 @@
 /**
  * Rule definition for {@code java_toolchain}
  */
-@BlazeRule(name = "java_toolchain", ancestors = {BaseRuleClasses.BaseRule.class},
-    factoryClass = JavaToolchain.class)
 public final class JavaToolchainRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -60,6 +57,15 @@
         .add(attr("misc", STRING_LIST).value(ImmutableList.<String>of()))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("java_toolchain")
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .factoryClass(JavaToolchain.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = java_toolchain, TYPE = OTHER, FAMILY = Java) -->
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
index 040a81f..898150b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosApplicationRule.java
@@ -21,7 +21,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
@@ -31,13 +30,6 @@
 /**
  * Rule definition for ios_application.
  */
-@BlazeRule(name = "ios_application",
-    factoryClass = IosApplication.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.ReleaseBundlingRule.class,
-        ObjcRuleClasses.XcodegenRule.class,
-        ObjcRuleClasses.SimulatorRule.class })
 public class IosApplicationRule implements RuleDefinition {
 
   @Override
@@ -77,6 +69,16 @@
             .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("ios_application")
+        .factoryClass(IosApplication.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.ReleaseBundlingRule.class,
+            ObjcRuleClasses.XcodegenRule.class, ObjcRuleClasses.SimulatorRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = ios_application, TYPE = BINARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceRule.java
index ca74722..b467be4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDeviceRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,9 +26,6 @@
 /**
  * Rule definition for ios_device.
  */
-@BlazeRule(name = "ios_device",
-    factoryClass = IosDevice.class,
-    ancestors = { BaseRuleClasses.BaseRule.class })
 public final class IosDeviceRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -53,6 +49,15 @@
             .value("en"))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("ios_device")
+        .factoryClass(IosDevice.class)
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = ios_device, TYPE = BINARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java
index 5233f3d..f5bbdee 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.rules.objc;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -24,12 +23,6 @@
 /**
  * Rule definition for ios_extension_binary.
  */
-@BlazeRule(name = "ios_extension_binary",
-    factoryClass = IosExtensionBinary.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.LinkingRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class IosExtensionBinaryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -43,6 +36,16 @@
         .setImplicitOutputsFunction(XcodeSupport.PBXPROJ)
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("ios_extension_binary")
+        .factoryClass(IosExtensionBinary.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.LinkingRule.class,
+            ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = ios_extension_binary, TYPE = BINARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionRule.java
index ca35f47..eaf0f0a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
@@ -28,12 +27,6 @@
 /**
  * Rule definition for ios_extension.
  */
-@BlazeRule(name = "ios_extension",
-    factoryClass = IosExtension.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.ReleaseBundlingRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class IosExtensionRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -60,6 +53,16 @@
             .cfg(ReleaseBundlingSupport.SPLIT_ARCH_TRANSITION))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("ios_extension")
+        .factoryClass(IosExtension.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.ReleaseBundlingRule.class,
+            ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = ios_extension, TYPE = BINARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryRule.java
index fb887c5..23e85ae 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinaryRule.java
@@ -20,7 +20,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
@@ -31,14 +30,6 @@
  * Rule definition for objc_binary.
  */
 // TODO(bazel-team): Remove bundling functionality (dependency on ApplicationRule, IPA output).
-@BlazeRule(name = "objc_binary",
-    factoryClass = ObjcBinary.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.LinkingRule.class,
-        ObjcRuleClasses.XcodegenRule.class,
-        ObjcRuleClasses.ReleaseBundlingRule.class,
-        ObjcRuleClasses.SimulatorRule.class })
 public class ObjcBinaryRule implements RuleDefinition {
 
   @Override
@@ -61,6 +52,17 @@
             .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_binary")
+        .factoryClass(ObjcBinary.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.LinkingRule.class,
+            ObjcRuleClasses.XcodegenRule.class, ObjcRuleClasses.ReleaseBundlingRule.class,
+            ObjcRuleClasses.SimulatorRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_binary, TYPE = BINARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibraryRule.java
index 19180fa..48df49c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibraryRule.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.rules.objc;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -24,13 +23,6 @@
 /**
  * Rule definition for objc_bundle_library.
  */
-@BlazeRule(name = "objc_bundle_library",
-    factoryClass = ObjcBundleLibrary.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.ResourcesRule.class,
-        ObjcRuleClasses.BundlingRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class ObjcBundleLibraryRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -44,6 +36,16 @@
         .setImplicitOutputsFunction(XcodeSupport.PBXPROJ)
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_bundle_library")
+        .factoryClass(ObjcBundleLibrary.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.ResourcesRule.class,
+            ObjcRuleClasses.BundlingRule.class, ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_bundle_library, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleRule.java
index 9be0d04..fffa2d8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,9 +27,6 @@
 /**
  * Rule definition for objc_bundle.
  */
-@BlazeRule(name = "objc_bundle",
-    factoryClass = ObjcBundle.class,
-    ancestors = { BaseRuleClasses.BaseRule.class })
 public class ObjcBundleRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -45,6 +41,15 @@
             .nonEmpty())
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_bundle")
+        .factoryClass(ObjcBundle.class)
+        .ancestors(BaseRuleClasses.BaseRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_bundle, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFrameworkRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFrameworkRule.java
index d160c1b..e3bc19a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFrameworkRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFrameworkRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,11 +27,6 @@
 /**
  * Rule definition for objc_framework.
  */
-@BlazeRule(name = "objc_framework",
-    factoryClass = ObjcFramework.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.SdkFrameworksDependerRule.class })
 public class ObjcFrameworkRule implements RuleDefinition {
 
   @Override
@@ -49,6 +43,15 @@
             .nonEmpty())
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_framework")
+        .factoryClass(ObjcFramework.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.SdkFrameworksDependerRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_framework, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
index 5773a77..43cdb23 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImportRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,12 +27,6 @@
 /**
  * Rule definition for {@code objc_import}.
  */
-@BlazeRule(name = "objc_import",
-    factoryClass = ObjcImport.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.AlwaysLinkRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class ObjcImportRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -56,6 +49,16 @@
             .allowedFileTypes(FileType.of(".a")))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_import")
+        .factoryClass(ObjcImport.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.AlwaysLinkRule.class,
+            ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_import, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryRule.java
index 36197ae..56f235b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryRule.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.rules.objc;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -24,13 +23,6 @@
 /**
  * Rule definition for objc_library.
  */
-@BlazeRule(name = "objc_library",
-    factoryClass = ObjcLibrary.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.CompilingRule.class,
-        ObjcRuleClasses.AlwaysLinkRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class ObjcLibraryRule implements RuleDefinition {
 
   @Override
@@ -45,6 +37,16 @@
         .setImplicitOutputsFunction(XcodeSupport.PBXPROJ)
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_library")
+        .factoryClass(ObjcLibrary.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.CompilingRule.class,
+            ObjcRuleClasses.AlwaysLinkRule.class, ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_library, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcOptionsRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcOptionsRule.java
index c7d1e18..7f7fbb3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcOptionsRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcOptionsRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.PLIST_TYPE;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,11 +27,6 @@
 /**
  * Rule definition for {@code objc_options}.
  */
-@BlazeRule(name = "objc_options",
-    factoryClass = ObjcOptions.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.CoptsRule.class })
 public class ObjcOptionsRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -53,6 +47,15 @@
             .allowedFileTypes(PLIST_TYPE))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_options")
+        .factoryClass(ObjcOptions.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.CoptsRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_options, TYPE = OTHER, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
index 9762b8b..95fb906 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibraryRule.java
@@ -21,7 +21,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -32,11 +31,6 @@
  *
  * This is a temporary rule until it is better known how to support proto_library rules.
  */
-@BlazeRule(name = "objc_proto_library",
-    factoryClass = ObjcProtoLibrary.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.ObjcProtoRule.class })
 public class ObjcProtoLibraryRule implements RuleDefinition {
   static final String OPTIONS_FILE_ATTR = "options_file";
   static final String OUTPUT_CPP_ATTR = "output_cpp";
@@ -70,6 +64,15 @@
             .value(env.getLabel("//tools/objc:xcodegen")))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_proto_library")
+        .factoryClass(ObjcProtoLibrary.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.ObjcProtoRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_proto_library, TYPE = LIBRARY, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
index 4bcaf3a..c223a73 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
@@ -29,7 +29,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -94,8 +93,8 @@
   /**
    * Returns an {@link Iterable} of {@link Artifact}s containing all the j2objc archives from the
    * transitive closure of the rule through the "deps" attribute. This is useful for ensuring that
-   * the j2objc archives are present for linking. 
-   * 
+   * the j2objc archives are present for linking.
+   *
    * @param ruleContext the {@link RuleContext} of the current rule
    * @return an {@link Iterable} of j2objc library archive artifacts.
    */
@@ -177,7 +176,6 @@
   /**
    * Attributes for {@code objc_*} rules that have compiler options.
    */
-  @BlazeRule(name = "$objc_opts_rule", type = RuleClassType.ABSTRACT)
   public static class CoptsRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -193,12 +191,19 @@
           .add(attr("copts", STRING_LIST))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_opts_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that use plists or copts.
    */
-  @BlazeRule(name = "$objc_options_rule", type = RuleClassType.ABSTRACT)
   public static class OptionsRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -217,12 +222,19 @@
               .allowedRuleClasses("objc_options"))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_options_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Attributes for {@code objc_*} rules that can link in SDK frameworks.
    */
-  @BlazeRule(name = "$objc_sdk_frameworks_depender_rule", type = RuleClassType.ABSTRACT)
   public static class SdkFrameworksDependerRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
@@ -262,6 +274,14 @@
           .add(attr("sdk_dylibs", STRING_LIST))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_sdk_frameworks_depender_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
@@ -286,9 +306,6 @@
    * storyboards. These resources are used during compilation of the declaring rule as well as when
    * bundling a dependent bundle (application, extension, etc.).
    */
-  @BlazeRule(name = "$objc_resources_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = { ResourceToolsRule.class, })
   public static class ResourcesRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -390,13 +407,20 @@
               .value(env.getLabel("//tools/objc:momczip_deploy.jar")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_resources_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(ResourceToolsRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that process resources (by defining or consuming
    * them).
    */
-  @BlazeRule(name = "$objc_resource_tools_rule", type = RuleClassType.ABSTRACT)
   public static class ResourceToolsRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -409,12 +433,18 @@
               .value(env.getLabel("//tools/objc:ibtoolzip_deploy.jar")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_resource_tools_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that export an xcode project.
    */
-  @BlazeRule(name = "$objc_xcodegen_rule", type = RuleClassType.ABSTRACT)
   public static class XcodegenRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -425,17 +455,19 @@
               .value(env.getLabel("//tools/objc:dummy.c")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_xcodegen_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that can be input to compilation (i.e. can be
    * dependencies of other compiling rules).
    */
-  @BlazeRule(name = "$objc_compile_dependency_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = {
-          ResourcesRule.class,
-          SdkFrameworksDependerRule.class })
   public static class CompileDependencyRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -472,26 +504,27 @@
           .add(attr("sdk_includes", Type.STRING_LIST))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_compile_dependency_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(ResourcesRule.class, SdkFrameworksDependerRule.class)
+          .build();
+    }
   }
-  
+
   /**
    * Common attributes for {@code objc_*} rules that contain compilable content.
    */
-  @BlazeRule(name = "$objc_compiling_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = {
-          CompileDependencyRule.class,
-          OptionsRule.class,
-          CoptsRule.class })
   public static class CompilingRule implements RuleDefinition {
-
     private static final Iterable<String> ALLOWED_DEPS_RULE_CLASSES = ImmutableSet.of(
         "objc_library",
         "objc_import",
         "objc_framework",
         "objc_proto_library",
         "j2objc_library");
-    
+
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
       return builder
@@ -558,14 +591,19 @@
           .add(attr("defines", STRING_LIST))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_compiling_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CompileDependencyRule.class, OptionsRule.class, CoptsRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that can optionally be set to {@code alwayslink}.
    */
-  @BlazeRule(name = "$objc_alwayslink_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = { CompileDependencyRule.class, })
   public static class AlwaysLinkRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -583,14 +621,19 @@
           .add(attr("alwayslink", BOOLEAN))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_alwayslink_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CompileDependencyRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that link sources and dependencies.
    */
-  @BlazeRule(name = "$objc_linking_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = { CompilingRule.class, })
   public static class LinkingRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -599,14 +642,20 @@
               .value(env.getLabel("//tools/objc:dump_syms")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_linking_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(CompilingRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for rules that uses ObjC proto compiler.
    */
-  @BlazeRule(name = "$objc_proto_rule", type = RuleClassType.ABSTRACT)
   public static class ObjcProtoRule implements RuleDefinition {
-
     /**
      * A Predicate that returns true if the ObjC proto compiler and its support deps are needed by
      * the current rule.
@@ -641,18 +690,18 @@
               .value(env.getLabel("//tools/objc:proto_support")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_proto_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
    * Base rule definition for iOS test rules.
    */
-  @BlazeRule(name = "$ios_test_base_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = {
-          ReleaseBundlingRule.class,
-          LinkingRule.class,
-          XcodegenRule.class,
-          SimulatorRule.class })
   public static class IosTestBaseRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
@@ -698,16 +747,20 @@
               .allowedFileTypes(PLIST_TYPE))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$ios_test_base_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(
+              ReleaseBundlingRule.class, LinkingRule.class, XcodegenRule.class, SimulatorRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that create a bundle.
    */
-  @BlazeRule(name = "$objc_bundling_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = {
-          OptionsRule.class,
-          ResourceToolsRule.class, })
   public static class BundlingRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -729,15 +782,20 @@
             .allowedFileTypes(PLIST_TYPE))
         .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_bundling_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(OptionsRule.class, ResourceToolsRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that create a bundle meant for release (e.g.
    * application or extension).
    */
-  @BlazeRule(name = "$objc_release_bundling_rule",
-      type = RuleClassType.ABSTRACT,
-      ancestors = { BundlingRule.class, })
   public static class ReleaseBundlingRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -823,13 +881,19 @@
               .value(env.getLabel("//tools/objc:bundlemerge")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_release_bundling_rule")
+          .type(RuleClassType.ABSTRACT)
+          .ancestors(BundlingRule.class)
+          .build();
+    }
   }
 
   /**
    * Common attributes for {@code objc_*} rules that use the iOS simulator.
    */
-  @BlazeRule(name = "$objc_simulator_rule",
-      type = RuleClassType.ABSTRACT)
   public static class SimulatorRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -839,6 +903,13 @@
               .value(env.getLabel("//third_party/iossim:iossim")))
           .build();
     }
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$objc_simulator_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
   }
 
   /**
@@ -847,11 +918,11 @@
    */
   static final class Tools {
     private final RuleContext ruleContext;
-  
+
     Tools(RuleContext ruleContext) {
       this.ruleContext = Preconditions.checkNotNull(ruleContext);
     }
-  
+
     Artifact actoolzipDeployJar() {
       return ruleContext.getPrerequisiteArtifact("$actoolzip_deploy", Mode.HOST);
     }
@@ -859,15 +930,15 @@
     Artifact ibtoolzipDeployJar() {
       return ruleContext.getPrerequisiteArtifact("$ibtoolzip_deploy", Mode.HOST);
     }
-  
+
     Artifact momczipDeployJar() {
       return ruleContext.getPrerequisiteArtifact("$momczip_deploy", Mode.HOST);
     }
-  
+
     FilesToRunProvider xcodegen() {
       return ruleContext.getExecutablePrerequisite("$xcodegen", Mode.HOST);
     }
-  
+
     FilesToRunProvider plmerge() {
       return ruleContext.getExecutablePrerequisite("$plmerge", Mode.HOST);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java
index c523f3b..8814b23 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java
@@ -19,7 +19,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,11 +27,6 @@
 /**
  * Rule definition for {@code objc_xcodeproj}.
  */
-@BlazeRule(name = "objc_xcodeproj",
-    factoryClass = ObjcXcodeproj.class,
-    ancestors = {
-        BaseRuleClasses.BaseRule.class,
-        ObjcRuleClasses.XcodegenRule.class })
 public class ObjcXcodeprojRule implements RuleDefinition {
   @Override
   public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -65,6 +59,15 @@
             .value(true))
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("objc_xcodeproj")
+        .factoryClass(ObjcXcodeproj.class)
+        .ancestors(BaseRuleClasses.BaseRule.class, ObjcRuleClasses.XcodegenRule.class)
+        .build();
+  }
 }
 
 /*<!-- #BLAZE_RULE (NAME = objc_xcodeproj, TYPE = OTHER, FAMILY = Objective-C) -->
diff --git a/src/main/java/com/google/devtools/build/lib/rules/workspace/BindRule.java b/src/main/java/com/google/devtools/build/lib/rules/workspace/BindRule.java
index bfdb632..e6eb084 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/workspace/BindRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/workspace/BindRule.java
@@ -18,7 +18,6 @@
 import static com.google.devtools.build.lib.packages.Type.LABEL;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses.BaseRule;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
 import com.google.devtools.build.lib.packages.RuleClass;
@@ -27,10 +26,6 @@
 /**
  * Binds an existing target to a target in the virtual //external package.
  */
-@BlazeRule(name = "bind",
-  type = RuleClassType.WORKSPACE,
-  ancestors = {BaseRule.class},
-  factoryClass = Bind.class)
 public final class BindRule implements RuleDefinition {
 
   @Override
@@ -46,6 +41,16 @@
         .setWorkspaceOnly()
         .build();
   }
+
+  @Override
+  public Metadata getMetadata() {
+    return RuleDefinition.Metadata.builder()
+        .name("bind")
+        .type(RuleClassType.WORKSPACE)
+        .ancestors(BaseRule.class)
+        .factoryClass(Bind.class)
+        .build();
+  }
 }
 /*<!-- #BLAZE_RULE (NAME = bind, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
 
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
index 752605c..9681475 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
@@ -21,7 +21,6 @@
 import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
-import com.google.devtools.build.lib.analysis.BlazeRule;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
@@ -59,16 +58,12 @@
       ConfiguredRuleClassProvider.Builder builder =
           new ConfiguredRuleClassProvider.Builder();
       addStandardRules(builder);
-      builder.addRuleDefinition(TestingDummyRule.class);
+      builder.addRuleDefinition(new TestingDummyRule());
       ruleProvider = builder.build();
     }
     return ruleProvider;
   }
 
-  @BlazeRule(name = "testing_dummy_rule",
-               ancestors = { BaseRuleClasses.RuleBase.class },
-               // Instantiated only in tests
-               factoryClass = UnknownRuleConfiguredTarget.class)
   public static final class TestingDummyRule implements RuleDefinition {
     @Override
     public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
@@ -80,5 +75,14 @@
           .add(attr("dummyinteger", INTEGER))
           .build();
     }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("testing_dummy_rule")
+          .ancestors(BaseRuleClasses.RuleBase.class)
+          .factoryClass(UnknownRuleConfiguredTarget.class)
+          .build();
+    }
   }
 }