[CALCITE-4825] Move remaining core/main off of ImmutableBeans

This is a follow up to CALCITE-4787 to move the rest of the core/main off ImmutableBeans
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoinRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoinRule.java
index 7e0f3cc..f7fa440 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBatchNestedLoopJoinRule.java
@@ -34,6 +34,8 @@
 import org.apache.calcite.util.ImmutableBeans;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import org.immutables.value.Value;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -44,6 +46,7 @@
  *
  * @see EnumerableRules#ENUMERABLE_BATCH_NESTED_LOOP_JOIN_RULE
  */
+@Value.Enclosing
 public class EnumerableBatchNestedLoopJoinRule
     extends RelRule<EnumerableBatchNestedLoopJoinRule.Config> {
   /** Creates an EnumerableBatchNestedLoopJoinRule. */
@@ -149,11 +152,11 @@
   }
 
   /** Rule configuration. */
+  @Value.Immutable
   public interface Config extends RelRule.Config {
-    Config DEFAULT = EMPTY
+    Config DEFAULT = ImmutableEnumerableBatchNestedLoopJoinRule.Config.of()
         .withOperandSupplier(b -> b.operand(LogicalJoin.class).anyInputs())
-        .withDescription("EnumerableBatchNestedLoopJoinRule")
-        .as(Config.class);
+        .withDescription("EnumerableBatchNestedLoopJoinRule");
 
     @Override default EnumerableBatchNestedLoopJoinRule toRule() {
       return new EnumerableBatchNestedLoopJoinRule(this);
@@ -165,7 +168,9 @@
      * can be an error because the generated code exceeds the size limit. */
     @ImmutableBeans.Property
     @ImmutableBeans.IntDefault(100)
-    int batchSize();
+    @Value.Default default int batchSize() {
+      return 100;
+    }
 
     /** Sets {@link #batchSize()}. */
     Config withBatchSize(int batchSize);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
index e4be772..ded1657 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalcRule.java
@@ -23,16 +23,18 @@
 import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.logical.LogicalCalc;
 
+import org.immutables.value.Value;
+
 /**
  * Rule to convert a {@link LogicalCalc} to an {@link EnumerableCalc}.
  * You may provide a custom config to convert other nodes that extend {@link Calc}.
  *
  * @see EnumerableRules#ENUMERABLE_CALC_RULE
  */
+@Value.Enclosing
 class EnumerableCalcRule extends ConverterRule {
   /** Default configuration. */
-  public static final Config DEFAULT_CONFIG = Config.EMPTY
-      .as(Config.class)
+  public static final Config DEFAULT_CONFIG = Config.INSTANCE
       // The predicate ensures that if there's a multiset,
       // FarragoMultisetSplitter will work on it first.
       .withConversion(LogicalCalc.class, RelOptUtil::notContainsWindowedAgg,
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelateRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelateRule.java
index a7224fd..7863583 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelateRule.java
@@ -22,15 +22,17 @@
 import org.apache.calcite.rel.core.Correlate;
 import org.apache.calcite.rel.logical.LogicalCorrelate;
 
+import org.immutables.value.Value;
+
 /**
  * Implementation of nested loops over enumerable inputs.
  *
  * @see EnumerableRules#ENUMERABLE_CORRELATE_RULE
  */
+@Value.Enclosing
 public class EnumerableCorrelateRule extends ConverterRule {
   /** Default configuration. */
-  public static final Config DEFAULT_CONFIG = Config.EMPTY
-      .as(Config.class)
+  public static final Config DEFAULT_CONFIG = Config.INSTANCE
       .withConversion(LogicalCorrelate.class, r -> true, Convention.NONE,
           EnumerableConvention.INSTANCE, "EnumerableCorrelateRule")
       .withRuleFactory(EnumerableCorrelateRule::new);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
index 760d2f1..7bae121 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterRule.java
@@ -30,8 +30,7 @@
  */
 class EnumerableFilterRule extends ConverterRule {
   /** Default configuration. */
-  public static final Config DEFAULT_CONFIG = Config.EMPTY
-      .as(Config.class)
+  public static final Config DEFAULT_CONFIG = Config.INSTANCE
       .withConversion(LogicalFilter.class, f -> !f.containsOver(),
           Convention.NONE, EnumerableConvention.INSTANCE,
           "EnumerableFilterRule")
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
index db260a0..a9c3e8e 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableFilterToCalcRule.java
@@ -25,10 +25,13 @@
 import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 
+import org.immutables.value.Value;
+
 /** Variant of {@link org.apache.calcite.rel.rules.FilterToCalcRule} for
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}.
  *
  * @see EnumerableRules#ENUMERABLE_FILTER_TO_CALC_RULE */
+@Value.Enclosing
 public class EnumerableFilterToCalcRule
     extends RelRule<EnumerableFilterToCalcRule.Config> {
   /** Creates an EnumerableFilterToCalcRule. */
@@ -60,11 +63,11 @@
   }
 
   /** Rule configuration. */
+  @Value.Immutable
   public interface Config extends RelRule.Config {
-    Config DEFAULT = EMPTY
+    Config DEFAULT = ImmutableEnumerableFilterToCalcRule.Config.of()
         .withOperandSupplier(b ->
-            b.operand(EnumerableFilter.class).anyInputs())
-        .as(Config.class);
+            b.operand(EnumerableFilter.class).anyInputs());
 
     @Override default EnumerableFilterToCalcRule toRule() {
       return new EnumerableFilterToCalcRule(this);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitRule.java
index 1a5292c..78e66d5 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitRule.java
@@ -21,6 +21,8 @@
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Sort;
 
+import org.immutables.value.Value;
+
 /**
  * Rule to convert an {@link org.apache.calcite.rel.core.Sort} that has
  * {@code offset} or {@code fetch} set to an
@@ -29,6 +31,7 @@
  *
  * @see EnumerableRules#ENUMERABLE_LIMIT_RULE
  */
+@Value.Enclosing
 public class EnumerableLimitRule
     extends RelRule<EnumerableLimitRule.Config> {
   /** Creates an EnumerableLimitRule. */
@@ -64,10 +67,10 @@
   }
 
   /** Rule configuration. */
+  @Value.Immutable
   public interface Config extends RelRule.Config {
-    Config DEFAULT = EMPTY
-        .withOperandSupplier(b -> b.operand(Sort.class).anyInputs())
-        .as(Config.class);
+    Config DEFAULT = ImmutableEnumerableLimitRule.Config.of()
+        .withOperandSupplier(b -> b.operand(Sort.class).anyInputs());
 
     @Override default EnumerableLimitRule toRule() {
       return new EnumerableLimitRule(this);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitSortRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitSortRule.java
index 9373f5e..14e6e65 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitSortRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimitSortRule.java
@@ -22,10 +22,13 @@
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.logical.LogicalSort;
 
+import org.immutables.value.Value;
+
 /**
  * Rule to convert an {@link EnumerableLimit} of on
  * {@link EnumerableSort} into an {@link EnumerableLimitSort}.
  */
+@Value.Enclosing
 public class EnumerableLimitSortRule extends RelRule<EnumerableLimitSortRule.Config> {
 
   /**
@@ -48,10 +51,10 @@
   }
 
   /** Rule configuration. */
+  @Value.Immutable
   public interface Config extends RelRule.Config {
-    Config DEFAULT = EMPTY.withOperandSupplier(
-        b0 -> b0.operand(LogicalSort.class).predicate(sort -> sort.fetch != null).anyInputs())
-        .as(Config.class);
+    Config DEFAULT = ImmutableEnumerableLimitSortRule.Config.of().withOperandSupplier(
+        b0 -> b0.operand(LogicalSort.class).predicate(sort -> sort.fetch != null).anyInputs());
 
     @Override default EnumerableLimitSortRule toRule() {
       return new EnumerableLimitSortRule(this);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeUnionRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeUnionRule.java
index be19d1f..e72d9c6 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeUnionRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeUnionRule.java
@@ -27,6 +27,8 @@
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 
+import org.immutables.value.Value;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -36,13 +38,16 @@
  *
  * @see EnumerableRules#ENUMERABLE_MERGE_UNION_RULE
  */
+@Value.Enclosing
 public class EnumerableMergeUnionRule extends RelRule<EnumerableMergeUnionRule.Config> {
 
   /** Rule configuration. */
+  @Value.Immutable
   public interface Config extends RelRule.Config {
-    Config DEFAULT_CONFIG = EMPTY.withDescription("EnumerableMergeUnionRule").withOperandSupplier(
-        b0 -> b0.operand(LogicalSort.class).oneInput(
-            b1 -> b1.operand(LogicalUnion.class).anyInputs())).as(Config.class);
+    Config DEFAULT_CONFIG = ImmutableEnumerableMergeUnionRule.Config.of()
+        .withDescription("EnumerableMergeUnionRule").withOperandSupplier(
+            b0 -> b0.operand(LogicalSort.class).oneInput(
+                b1 -> b1.operand(LogicalUnion.class).anyInputs()));
 
     @Override default EnumerableMergeUnionRule toRule() {
       return new EnumerableMergeUnionRule(this);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index 249dca7..b1b6922 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -30,7 +30,7 @@
  */
 class EnumerableProjectRule extends ConverterRule {
   /** Default configuration. */
-  static final Config DEFAULT_CONFIG = Config.EMPTY
+  static final Config DEFAULT_CONFIG = Config.INSTANCE
       .as(Config.class)
       .withConversion(LogicalProject.class, p -> !p.containsOver(),
           Convention.NONE, EnumerableConvention.INSTANCE,
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
index c2dd117..a5b5613 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectToCalcRule.java
@@ -17,16 +17,18 @@
 package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelRule;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.rules.ProjectToCalcRule;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.tools.RelBuilderFactory;
 
+import org.immutables.value.Value;
+
 /** Variant of {@link org.apache.calcite.rel.rules.ProjectToCalcRule} for
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}.
  *
  * @see EnumerableRules#ENUMERABLE_PROJECT_TO_CALC_RULE */
+@Value.Enclosing
 public class EnumerableProjectToCalcRule extends ProjectToCalcRule {
   /** Creates an EnumerableProjectToCalcRule. */
   protected EnumerableProjectToCalcRule(Config config) {
@@ -53,11 +55,12 @@
   }
 
   /** Rule configuration. */
+  @Value.Immutable
+  @SuppressWarnings("immutables")
   public interface Config extends ProjectToCalcRule.Config {
-    Config DEFAULT = RelRule.Config.EMPTY
+    Config DEFAULT = ImmutableEnumerableProjectToCalcRule.Config.of()
         .withOperandSupplier(b ->
-            b.operand(EnumerableProject.class).anyInputs())
-        .as(Config.class);
+            b.operand(EnumerableProject.class).anyInputs());
 
     @Override default EnumerableProjectToCalcRule toRule() {
       return new EnumerableProjectToCalcRule(this);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScanRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScanRule.java
index 469c784..3c08d0a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScanRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScanRule.java
@@ -29,8 +29,7 @@
  * @see EnumerableRules#ENUMERABLE_TABLE_FUNCTION_SCAN_RULE */
 public class EnumerableTableFunctionScanRule extends ConverterRule {
   /** Default configuration. */
-  public static final Config DEFAULT_CONFIG = Config.EMPTY
-      .as(Config.class)
+  public static final Config DEFAULT_CONFIG = Config.INSTANCE
       .withConversion(LogicalTableFunctionScan.class, Convention.NONE,
           EnumerableConvention.INSTANCE, "EnumerableTableFunctionScanRule")
       .withRuleFactory(EnumerableTableFunctionScanRule::new);
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java
index 635879d..c89e803 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java
@@ -33,8 +33,7 @@
  * @see EnumerableRules#ENUMERABLE_TABLE_SCAN_RULE */
 public class EnumerableTableScanRule extends ConverterRule {
   /** Default configuration. */
-  public static final Config DEFAULT_CONFIG = Config.EMPTY
-      .as(Config.class)
+  public static final Config DEFAULT_CONFIG = Config.INSTANCE
       .withConversion(LogicalTableScan.class,
           r -> EnumerableTableScan.canHandle(r.getTable()),
           Convention.NONE, EnumerableConvention.INSTANCE,
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
index 139d140..77b5287 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java
@@ -80,6 +80,7 @@
 import com.google.common.collect.ImmutableList;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
+import org.immutables.value.Value;
 
 import java.util.List;
 import java.util.Map;
@@ -90,6 +91,7 @@
 /**
  * Utilities pertaining to {@link BindableRel} and {@link BindableConvention}.
  */
+@Value.Enclosing
 public class Bindables {
   private Bindables() {}
 
@@ -188,11 +190,11 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableBindables.Config.of()
           .withOperandSupplier(b ->
-              b.operand(LogicalTableScan.class).noInputs())
-          .as(Config.class);
+              b.operand(LogicalTableScan.class).noInputs());
 
       @Override default BindableTableScanRule toRule() {
         return new BindableTableScanRule(this);
diff --git a/core/src/main/java/org/apache/calcite/plan/CommonRelSubExprRule.java b/core/src/main/java/org/apache/calcite/plan/CommonRelSubExprRule.java
index e39f7e0..434ee43 100644
--- a/core/src/main/java/org/apache/calcite/plan/CommonRelSubExprRule.java
+++ b/core/src/main/java/org/apache/calcite/plan/CommonRelSubExprRule.java
@@ -32,12 +32,6 @@
     super(config);
   }
 
-  @Deprecated // to be removed before 2.0
-  protected CommonRelSubExprRule(RelOptRuleOperand operand) {
-    this(Config.EMPTY.withOperandSupplier(b -> b.exactly(operand))
-        .as(Config.class));
-  }
-
   /** Rule configuration. */
   public interface Config extends RelRule.Config {
   }
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
index 0b56bda..3192f09 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java
@@ -31,6 +31,7 @@
 import org.apache.calcite.tools.RelBuilderFactory;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
+import org.immutables.value.Value;
 
 import java.util.List;
 
@@ -47,6 +48,7 @@
  * source subset is abstract), the set is flagged, so this converter will be
  * expanded as soon as a non-abstract relexp is added to the set.</p>
  */
+@Value.Enclosing
 public class AbstractConverter extends ConverterImpl {
   //~ Constructors -----------------------------------------------------------
 
@@ -136,11 +138,11 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableConverter.Config.of()
           .withOperandSupplier(b ->
-              b.operand(AbstractConverter.class).anyInputs())
-          .as(Config.class);
+              b.operand(AbstractConverter.class).anyInputs());
 
       @Override default ExpandConversionRule toRule() {
         return new ExpandConversionRule(this);
diff --git a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
index 7a289df..801f974 100644
--- a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java
@@ -109,9 +109,9 @@
   protected <R extends RelNode> ConverterRule(Class<R> clazz,
       Predicate<? super R> predicate, RelTrait in, RelTrait out,
       RelBuilderFactory relBuilderFactory, String descriptionPrefix) {
-    this(Config.EMPTY
+    this(ImmutableConverterRule.Config.builder()
         .withRelBuilderFactory(relBuilderFactory)
-        .as(Config.class)
+        .build()
         .withConversion(clazz, predicate, in, out, descriptionPrefix));
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
index 3a67d07..72f346e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
@@ -306,7 +306,7 @@
     @Deprecated // to be removed before 2.0
     public <R extends SingleRel> RemoveEmptySingleRule(Class<R> clazz,
         String description) {
-      this(Config.EMPTY.withDescription(description)
+      this(ImmutablePruneEmptyRuleConfig.of().withDescription(description)
           .as(Config.class)
           .withOperandFor(clazz, singleRel -> true));
     }
@@ -315,7 +315,7 @@
     public <R extends SingleRel> RemoveEmptySingleRule(Class<R> clazz,
         Predicate<R> predicate, RelBuilderFactory relBuilderFactory,
         String description) {
-      this(Config.EMPTY.withRelBuilderFactory(relBuilderFactory)
+      this(ImmutablePruneEmptyRuleConfig.of().withRelBuilderFactory(relBuilderFactory)
           .withDescription(description)
           .as(Config.class)
           .withOperandFor(clazz, predicate));
@@ -326,7 +326,7 @@
     public <R extends SingleRel> RemoveEmptySingleRule(Class<R> clazz,
         com.google.common.base.Predicate<R> predicate,
         RelBuilderFactory relBuilderFactory, String description) {
-      this(Config.EMPTY.withRelBuilderFactory(relBuilderFactory)
+      this(ImmutablePruneEmptyRuleConfig.of().withRelBuilderFactory(relBuilderFactory)
           .withDescription(description)
           .as(Config.class)
           .withOperandFor(clazz, predicate::apply));
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
index bc65f85..1656ce9 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
@@ -87,10 +87,13 @@
   @Deprecated // to be removed before 2.0
   public ValuesReduceRule(RelOptRuleOperand operand,
       RelBuilderFactory relBuilderFactory, String desc) {
-    this(Config.EMPTY.withRelBuilderFactory(relBuilderFactory)
+    this(ImmutableValuesReduceRule.Config.builder().withRelBuilderFactory(relBuilderFactory)
         .withDescription(desc)
         .withOperandSupplier(b -> b.exactly(operand))
-        .as(Config.class));
+        .withMatchHandler((u, v) -> {
+          throw new IllegalArgumentException("Match handler not set.");
+        })
+        .build());
     throw new IllegalArgumentException("cannot guess matchHandler");
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java b/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
index b109dfc..6448e5d 100644
--- a/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/stream/StreamRules.java
@@ -46,6 +46,8 @@
 
 import com.google.common.collect.ImmutableList;
 
+import org.immutables.value.Value;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -89,12 +91,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaProjectTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaProjectTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(Project.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(Project.class).anyInputs()));
 
       @Override default DeltaProjectTransposeRule toRule() {
         return new DeltaProjectTransposeRule(this);
@@ -128,12 +131,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaFilterTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaFilterTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(Filter.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(Filter.class).anyInputs()));
 
       @Override default DeltaFilterTransposeRule toRule() {
         return new DeltaFilterTransposeRule(this);
@@ -169,13 +173,14 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaAggregateTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaAggregateTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
                   b1.operand(Aggregate.class)
-                      .predicate(Aggregate::isSimple).anyInputs()))
-          .as(Config.class);
+                      .predicate(Aggregate::isSimple).anyInputs()));
 
       @Override default DeltaAggregateTransposeRule toRule() {
         return new DeltaAggregateTransposeRule(this);
@@ -210,12 +215,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaSortTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaSortTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(Sort.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(Sort.class).anyInputs()));
 
       @Override default DeltaSortTransposeRule toRule() {
         return new DeltaSortTransposeRule(this);
@@ -247,12 +253,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaUnionTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaUnionTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(Union.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(Union.class).anyInputs()));
 
       @Override default DeltaUnionTransposeRule toRule() {
         return new DeltaUnionTransposeRule(this);
@@ -296,12 +303,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaTableScanRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaTableScanRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(TableScan.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(TableScan.class).anyInputs()));
 
       @Override default DeltaTableScanRule toRule() {
         return new DeltaTableScanRule(this);
@@ -335,12 +343,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaTableScanToEmptyRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaTableScanToEmptyRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(TableScan.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(TableScan.class).anyInputs()));
 
       @Override default DeltaTableScanToEmptyRule toRule() {
         return new DeltaTableScanToEmptyRule(this);
@@ -407,12 +416,13 @@
     }
 
     /** Rule configuration. */
+    @Value.Immutable(singleton = true)
+    @Value.Style(typeImmutable = "ImmutableDeltaJoinTransposeRuleConfig")
     public interface Config extends RelRule.Config {
-      Config DEFAULT = EMPTY
+      Config DEFAULT = ImmutableDeltaJoinTransposeRuleConfig.of()
           .withOperandSupplier(b0 ->
               b0.operand(Delta.class).oneInput(b1 ->
-                  b1.operand(Join.class).anyInputs()))
-          .as(Config.class);
+                  b1.operand(Join.class).anyInputs()));
 
       @Override default DeltaJoinTransposeRule toRule() {
         return new DeltaJoinTransposeRule(this);