Support Human specification as input

Bug: 184026720
Change-Id: I4214b07d74732067afcd7fad10eeb04c7f6b8432
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index 7ef1569..1ae2311 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -4,8 +4,9 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -41,7 +42,7 @@
   private final boolean printVersion;
   private final Reporter reporter;
   private final int minApiLevel;
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+  private final DesugaredLibrarySpecification desugaredLibrarySpecification;
   private final AndroidApp app;
   private final StringConsumer backportedMethodListConsumer;
   private final DexItemFactory factory;
@@ -62,7 +63,7 @@
     return minApiLevel;
   }
 
-  public LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
+  public DesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
     return desugaredLibrarySpecification;
   }
 
@@ -88,7 +89,7 @@
   private BackportedMethodListCommand(
       Reporter reporter,
       int minApiLevel,
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+      DesugaredLibrarySpecification desugaredLibrarySpecification,
       AndroidApp app,
       StringConsumer backportedMethodListConsumer,
       DexItemFactory factory) {
@@ -245,7 +246,7 @@
       return this;
     }
 
-    LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(DexItemFactory factory) {
+    DesugaredLibrarySpecification getDesugaredLibraryConfiguration(DexItemFactory factory) {
       if (desugaredLibrarySpecificationResources.isEmpty()) {
         return LegacyDesugaredLibrarySpecification.empty();
       }
@@ -254,9 +255,8 @@
       }
       StringResource desugaredLibrarySpecificationResource =
           desugaredLibrarySpecificationResources.get(0);
-      LegacyDesugaredLibrarySpecificationParser libraryParser =
-          new LegacyDesugaredLibrarySpecificationParser(factory, null, false, getMinApiLevel());
-      return libraryParser.parse(desugaredLibrarySpecificationResource);
+      return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+          desugaredLibrarySpecificationResource, factory, null, false, getMinApiLevel());
     }
 
     /** Output file for the backported method list */
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 18b7c02..a474a31 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.inspector.Inspector;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -573,7 +574,7 @@
       return self();
     }
 
-    LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(
+    DesugaredLibrarySpecification getDesugaredLibraryConfiguration(
         DexItemFactory factory, boolean libraryCompilation) {
       if (desugaredLibrarySpecificationResources.isEmpty()) {
         return LegacyDesugaredLibrarySpecification.empty();
@@ -583,10 +584,12 @@
       }
       StringResource desugaredLibrarySpecificationResource =
           desugaredLibrarySpecificationResources.get(0);
-      LegacyDesugaredLibrarySpecificationParser libraryParser =
-          new LegacyDesugaredLibrarySpecificationParser(
-              factory, getReporter(), libraryCompilation, getMinApiLevel());
-      return libraryParser.parse(desugaredLibrarySpecificationResource);
+      return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+          desugaredLibrarySpecificationResource,
+          factory,
+          getReporter(),
+          libraryCompilation,
+          getMinApiLevel());
     }
 
     boolean hasDesugaredLibraryConfiguration() {
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 0967f55..c8923f8 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.ProguardConfigurationParser;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -288,7 +288,7 @@
       intermediate |= getProgramConsumer() instanceof DexFilePerClassFileConsumer;
 
       DexItemFactory factory = new DexItemFactory();
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+      DesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, false);
 
       ImmutableList<ProguardConfigurationRule> mainDexKeepRules =
@@ -328,7 +328,7 @@
   private final boolean intermediate;
   private final DesugarGraphConsumer desugarGraphConsumer;
   private final StringConsumer desugaredLibraryKeepRuleConsumer;
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+  private final DesugaredLibrarySpecification desugaredLibrarySpecification;
   private final String synthesizedClassPrefix;
   private final boolean skipDump;
   private final boolean enableMainDexListCheck;
@@ -390,7 +390,7 @@
       BiPredicate<String, Long> dexClassChecksumFilter,
       DesugarGraphConsumer desugarGraphConsumer,
       StringConsumer desugaredLibraryKeepRuleConsumer,
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+      DesugaredLibrarySpecification desugaredLibrarySpecification,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       String synthesizedClassPrefix,
diff --git a/src/main/java/com/android/tools/r8/DumpOptions.java b/src/main/java/com/android/tools/r8/DumpOptions.java
index c7f3345..2726086 100644
--- a/src/main/java/com/android/tools/r8/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/DumpOptions.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.experimental.startup.StartupConfiguration;
 import com.android.tools.r8.features.FeatureSplitConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
@@ -50,7 +50,7 @@
   private final Optional<Boolean> forceProguardCompatibility;
 
   // Dump if present.
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+  private final DesugaredLibrarySpecification desugaredLibrarySpecification;
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final ProguardConfiguration proguardConfiguration;
   private final List<ProguardConfigurationRule> mainDexKeepRules;
@@ -62,7 +62,7 @@
       Tool tool,
       CompilationMode compilationMode,
       int minAPI,
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+      DesugaredLibrarySpecification desugaredLibrarySpecification,
       boolean optimizeMultidexForLinearAlloc,
       int threadCount,
       DesugarState desugarState,
@@ -133,8 +133,7 @@
   }
 
   private boolean hasDesugaredLibraryConfiguration() {
-    return desugaredLibrarySpecification != null
-        && !desugaredLibrarySpecification.isEmptyConfiguration();
+    return desugaredLibrarySpecification != null && !desugaredLibrarySpecification.isEmpty();
   }
 
   public String getDesugaredLibraryJsonSource() {
@@ -186,7 +185,7 @@
     private Optional<Boolean> minification = Optional.empty();
     private Optional<Boolean> forceProguardCompatibility = Optional.empty();
     // Dump if present.
-    private LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+    private DesugaredLibrarySpecification desugaredLibrarySpecification;
     private FeatureSplitConfiguration featureSplitConfiguration;
     private ProguardConfiguration proguardConfiguration;
     private List<ProguardConfigurationRule> mainDexKeepRules;
@@ -209,7 +208,7 @@
     }
 
     public Builder setDesugaredLibraryConfiguration(
-        LegacyDesugaredLibrarySpecification desugaredLibrarySpecification) {
+        DesugaredLibrarySpecification desugaredLibrarySpecification) {
       this.desugaredLibrarySpecification = desugaredLibrarySpecification;
       return this;
     }
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 4c49b47..37c50c4 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -34,8 +34,9 @@
 import com.android.tools.r8.graph.LazyLoadedDexApplication;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.jar.CfApplicationWriter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
@@ -82,8 +83,11 @@
   public GenerateLintFiles(
       String desugarConfigurationPath, String desugarImplementationPath, String outputDirectory)
       throws Exception {
-    this.desugaredLibrarySpecification =
+    DesugaredLibrarySpecification desugaredLibrarySpecification =
         readDesugaredLibraryConfiguration(desugarConfigurationPath);
+    assert desugaredLibrarySpecification.isLegacy();
+    this.desugaredLibrarySpecification =
+        desugaredLibrarySpecification.asLegacyDesugaredLibrarySpecification();
     this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
     this.outputDirectory = Paths.get(outputDirectory);
     if (!Files.isDirectory(this.outputDirectory)) {
@@ -119,11 +123,14 @@
     return Paths.get(jar);
   }
 
-  private LegacyDesugaredLibrarySpecification readDesugaredLibraryConfiguration(
+  private DesugaredLibrarySpecification readDesugaredLibraryConfiguration(
       String desugarConfigurationPath) {
-    return new LegacyDesugaredLibrarySpecificationParser(
-            factory, reporter, false, AndroidApiLevel.B.getLevel())
-        .parse(StringResource.fromFile(Paths.get(desugarConfigurationPath)));
+    return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+        StringResource.fromFile(Paths.get(desugarConfigurationPath)),
+        factory,
+        reporter,
+        false,
+        AndroidApiLevel.B.getLevel());
   }
 
   private CfCode buildEmptyThrowingCfCode(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6da92e2..8678a9d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.Inspector;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
@@ -42,7 +42,7 @@
 
   private final D8Command d8Command;
   private final R8Command r8Command;
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+  private final DesugaredLibrarySpecification desugaredLibrarySpecification;
   private final DexItemFactory factory;
 
   boolean isShrinking() {
@@ -95,7 +95,7 @@
       Reporter diagnosticsHandler,
       boolean encodeChecksum,
       BiPredicate<String, Long> dexClassChecksumFilter,
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+      DesugaredLibrarySpecification desugaredLibrarySpecification,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       int threadCount,
@@ -335,7 +335,7 @@
       }
 
       DexItemFactory factory = new DexItemFactory();
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+      DesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, true);
 
       R8Command r8Command = null;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5bc9ddd..4e72575 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -15,7 +15,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.inspector.Inspector;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.naming.SourceFileRewriter;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
@@ -475,7 +475,7 @@
       List<ProguardConfigurationRule> mainDexKeepRules =
           ProguardConfigurationParser.parse(mainDexRules, factory, reporter);
 
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+      DesugaredLibrarySpecification desugaredLibrarySpecification =
           getDesugaredLibraryConfiguration(factory, false);
 
       ProguardConfigurationParser parser =
@@ -666,7 +666,7 @@
   private final GraphConsumer mainDexKeptGraphConsumer;
   private final Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer;
   private final StringConsumer desugaredLibraryKeepRuleConsumer;
-  private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+  private final DesugaredLibrarySpecification desugaredLibrarySpecification;
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final String synthesizedClassPrefix;
   private final boolean skipDump;
@@ -744,7 +744,7 @@
       boolean encodeChecksum,
       BiPredicate<String, Long> dexClassChecksumFilter,
       StringConsumer desugaredLibraryKeepRuleConsumer,
-      LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+      DesugaredLibrarySpecification desugaredLibrarySpecification,
       FeatureSplitConfiguration featureSplitConfiguration,
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
new file mode 100644
index 0000000..d5740de
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary;
+
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import java.util.List;
+
+public interface DesugaredLibrarySpecification {
+
+  default boolean isHuman() {
+    return false;
+  }
+
+  default boolean isLegacy() {
+    return false;
+  }
+
+  default LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
+    return null;
+  }
+
+  default HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
+    return null;
+  }
+
+  boolean isEmpty();
+
+  String getJsonSource();
+
+  String getSynthesizedLibraryClassesPackagePrefix();
+
+  List<String> getExtraKeepRules();
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
new file mode 100644
index 0000000..c614166
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class DesugaredLibrarySpecificationParser {
+
+  public static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
+  private static final int MIN_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+
+  public static DesugaredLibrarySpecification parseDesugaredLibrarySpecification(
+      StringResource stringResource,
+      DexItemFactory dexItemFactory,
+      Reporter reporter,
+      boolean libraryCompilation,
+      int minAPILevel) {
+    Origin origin = stringResource.getOrigin();
+    assert origin != null;
+    String jsonConfigString;
+    JsonObject jsonConfig;
+    try {
+      jsonConfigString = stringResource.getString();
+      JsonParser parser = new JsonParser();
+      jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
+    } catch (Exception e) {
+      throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
+    }
+    if (!jsonConfig.has(CONFIGURATION_FORMAT_VERSION_KEY)) {
+      throw reporter.fatalError(
+          new StringDiagnostic(
+              "Invalid desugared library configuration. Expected required key '"
+                  + CONFIGURATION_FORMAT_VERSION_KEY
+                  + "'",
+              origin));
+    }
+
+    if (jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt()
+        >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION) {
+      return new HumanDesugaredLibrarySpecificationParser(
+              dexItemFactory, reporter, libraryCompilation, minAPILevel)
+          .parse(origin, jsonConfigString, jsonConfig);
+    }
+    return new LegacyDesugaredLibrarySpecificationParser(
+            dexItemFactory, reporter, libraryCompilation, minAPILevel)
+        .parse(origin, jsonConfigString, jsonConfig);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index faa7e67..15ec7dd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -8,12 +8,13 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-public class HumanDesugaredLibrarySpecification {
+public class HumanDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
 
   private final boolean libraryCompilation;
   private final HumanTopLevelFlags topLevelFlags;
@@ -28,6 +29,21 @@
     this.rewritingFlags = rewritingFlags;
   }
 
+  @Override
+  public boolean isEmpty() {
+    return rewritingFlags.isEmpty();
+  }
+
+  @Override
+  public boolean isHuman() {
+    return true;
+  }
+
+  @Override
+  public HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
+    return this;
+  }
+
   public boolean supportAllCallbacksFromLibrary() {
     return topLevelFlags.supportAllCallbacksFromLibrary();
   }
@@ -40,6 +56,7 @@
     return libraryCompilation;
   }
 
+  @Override
   public String getSynthesizedLibraryClassesPackagePrefix() {
     return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
   }
@@ -111,10 +128,12 @@
     return rewritingFlags.getDontRetarget();
   }
 
+  @Override
   public List<String> getExtraKeepRules() {
     return topLevelFlags.getExtraKeepRules();
   }
 
+  @Override
   public String getJsonSource() {
     return topLevelFlags.getJsonSource();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 85cf948..2aecff0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
 
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
+
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -26,6 +28,8 @@
 
 public class HumanDesugaredLibrarySpecificationParser {
 
+  public static final int CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+
   static final String IDENTIFIER_KEY = "identifier";
   static final String REQUIRED_COMPILATION_API_LEVEL_KEY = "required_compilation_api_level";
   static final String SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY =
@@ -104,7 +108,21 @@
   public HumanDesugaredLibrarySpecification parse(
       StringResource stringResource, Consumer<HumanTopLevelFlags.Builder> topLevelFlagAmender) {
     String jsonConfigString = parseJson(stringResource);
+    return parse(origin, jsonConfigString, jsonConfig, topLevelFlagAmender);
+  }
 
+  public HumanDesugaredLibrarySpecification parse(
+      Origin origin, String jsonConfigString, JsonObject jsonConfig) {
+    return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
+  }
+
+  private HumanDesugaredLibrarySpecification parse(
+      Origin origin,
+      String jsonConfigString,
+      JsonObject jsonConfig,
+      Consumer<HumanTopLevelFlags.Builder> topLevelFlagAmender) {
+    this.origin = origin;
+    this.jsonConfig = jsonConfig;
     HumanTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);
 
     HumanRewritingFlags legacyRewritingFlags = parseRewritingFlags();
@@ -112,7 +130,7 @@
     HumanDesugaredLibrarySpecification config =
         new HumanDesugaredLibrarySpecification(
             topLevelFlags, legacyRewritingFlags, libraryCompilation);
-    origin = null;
+    this.origin = null;
     return config;
   }
 
@@ -152,6 +170,17 @@
 
     builder.setJsonSource(jsonConfigString);
 
+    JsonElement formatVersionElement = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY);
+    int formatVersion = formatVersionElement.getAsInt();
+    if (formatVersion != CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION) {
+      reporter.warning(
+          new StringDiagnostic(
+              "Human desugared library specification version mismatches the parser "
+                  + "expected version. This is allowed and should happen only while extending "
+                  + "the specifications.",
+              origin));
+    }
+
     String identifier = required(jsonConfig, IDENTIFIER_KEY).getAsString();
     builder.setDesugaredLibraryIdentifier(identifier);
     builder.setSynthesizedLibraryClassesPackagePrefix(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index a37f18a..d9dd3bc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -130,6 +130,10 @@
     return amendLibraryMethod;
   }
 
+  public boolean isEmpty() {
+    return rewritePrefix.isEmpty() && emulatedInterfaces.isEmpty() && retargetMethod.isEmpty();
+  }
+
   public static class Builder {
 
     private final Reporter reporter;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
index 9fe9a04..f528446 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
 
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.AMEND_LIBRARY_METHOD_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_BELOW_OR_EQUAL_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.BACKPORT_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.COMMON_FLAGS_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CUSTOM_CONVERSION_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_RETARGET_KEY;
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_REWRITE_KEY;
@@ -54,6 +56,7 @@
       MultiAPILevelHumanDesugaredLibrarySpecification humanSpec, StringConsumer output) {
     HashMap<String, Object> toJson = new LinkedHashMap<>();
     toJson.put(IDENTIFIER_KEY, humanSpec.getTopLevelFlags().getIdentifier());
+    toJson.put(CONFIGURATION_FORMAT_VERSION_KEY, CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION);
     toJson.put(
         REQUIRED_COMPILATION_API_LEVEL_KEY,
         humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel().getLevel());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 9ab05b9..8a7df1c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -9,37 +9,22 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Pair;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-public class LegacyDesugaredLibrarySpecification {
+public class LegacyDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
 
   private final boolean libraryCompilation;
   private final LegacyTopLevelFlags topLevelFlags;
   private final LegacyRewritingFlags rewritingFlags;
 
-  public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
-      Map<String, String> prefix, InternalOptions options) {
-    return new LegacyDesugaredLibrarySpecification(
-        LegacyTopLevelFlags.empty(),
-        LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
-        true);
-  }
-
   public static LegacyDesugaredLibrarySpecification empty() {
     return new LegacyDesugaredLibrarySpecification(
-        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
-
-      @Override
-      public boolean isEmptyConfiguration() {
-        return true;
-      }
-    };
+        LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false);
   }
 
   public LegacyDesugaredLibrarySpecification(
@@ -51,6 +36,21 @@
     this.rewritingFlags = rewritingFlags;
   }
 
+  @Override
+  public boolean isEmpty() {
+    return rewritingFlags.isEmpty();
+  }
+
+  @Override
+  public boolean isLegacy() {
+    return true;
+  }
+
+  @Override
+  public LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
+    return this;
+  }
+
   public LegacyTopLevelFlags getTopLevelFlags() {
     return topLevelFlags;
   }
@@ -71,21 +71,11 @@
     return libraryCompilation;
   }
 
+  @Override
   public String getSynthesizedLibraryClassesPackagePrefix() {
     return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
   }
 
-  // TODO(b/183918843): We are currently computing a new name for the class by replacing the
-  //  initial package prefix by the synthesized library class package prefix, it would be better
-  //  to make the rewriting explicit in the desugared library json file.
-  public String convertJavaNameToDesugaredLibrary(DexType type) {
-    String prefix =
-        DescriptorUtils.getJavaTypeFromBinaryName(getSynthesizedLibraryClassesPackagePrefix());
-    String interfaceType = type.toString();
-    int firstPackage = interfaceType.indexOf('.');
-    return prefix + interfaceType.substring(firstPackage + 1);
-  }
-
   public String getIdentifier() {
     return topLevelFlags.getIdentifier();
   }
@@ -146,15 +136,14 @@
     return rewritingFlags.getDontRetargetLibMember();
   }
 
+  @Override
   public List<String> getExtraKeepRules() {
     return topLevelFlags.getExtraKeepRules();
   }
 
+  @Override
   public String getJsonSource() {
     return topLevelFlags.getJsonSource();
   }
 
-  public boolean isEmptyConfiguration() {
-    return false;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index a3afcd9..e6e2094 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
 
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
+
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.origin.Origin;
@@ -26,7 +28,6 @@
   public static final int MAX_SUPPORTED_VERSION = 4;
   public static final SemanticVersion MIN_SUPPORTED_VERSION = new SemanticVersion(1, 0, 9);
 
-  static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
   static final String VERSION_KEY = "version";
   static final String GROUP_ID_KEY = "group_id";
   static final String ARTIFACT_ID_KEY = "artifact_id";
@@ -103,7 +104,21 @@
   public LegacyDesugaredLibrarySpecification parse(
       StringResource stringResource, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
     String jsonConfigString = parseJson(stringResource);
+    return parse(origin, jsonConfigString, jsonConfig, topLevelFlagAmender);
+  }
 
+  public LegacyDesugaredLibrarySpecification parse(
+      Origin origin, String jsonConfigString, JsonObject jsonConfig) {
+    return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
+  }
+
+  private LegacyDesugaredLibrarySpecification parse(
+      Origin origin,
+      String jsonConfigString,
+      JsonObject jsonConfig,
+      Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
+    this.origin = origin;
+    this.jsonConfig = jsonConfig;
     LegacyTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);
 
     LegacyRewritingFlags legacyRewritingFlags = parseRewritingFlags();
@@ -111,7 +126,7 @@
     LegacyDesugaredLibrarySpecification config =
         new LegacyDesugaredLibrarySpecification(
             topLevelFlags, legacyRewritingFlags, libraryCompilation);
-    origin = null;
+    this.origin = null;
     return config;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
index 61a2eb8..ac9d662 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
@@ -69,13 +68,6 @@
         ImmutableSet.of());
   }
 
-  public static LegacyRewritingFlags withOnlyRewritePrefixForTesting(
-      Map<String, String> prefix, InternalOptions options) {
-    Builder builder = builder(options.dexItemFactory(), options.reporter, Origin.unknown());
-    prefix.forEach(builder::putRewritePrefix);
-    return builder.build();
-  }
-
   public static Builder builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
     return new Builder(dexItemFactory, reporter, origin);
   }
@@ -127,6 +119,12 @@
     return wrapperConversions;
   }
 
+  public boolean isEmpty() {
+    return rewritePrefix.isEmpty()
+        && emulateLibraryInterface.isEmpty()
+        && retargetCoreLibMember.isEmpty();
+  }
+
   public static class Builder {
 
     private final DexItemFactory factory;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index feac7f5..7b17307 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -54,8 +54,8 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.desugar.TypeRewriter;
 import com.android.tools.r8.ir.desugar.TypeRewriter.MachineDesugarPrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
@@ -891,19 +891,24 @@
   public StringConsumer configurationConsumer = null;
 
   public void setDesugaredLibrarySpecification(
-      LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
-    if (specification.isEmptyConfiguration()) {
+      DesugaredLibrarySpecification specification, AndroidApp app) {
+    if (specification.isEmpty()) {
       return;
     }
     try {
       HumanDesugaredLibrarySpecification human =
-          new LegacyToHumanSpecificationConverter()
-              .convert(specification, app.getLibraryResourceProviders(), this);
+          specification.isLegacy()
+              ? new LegacyToHumanSpecificationConverter()
+                  .convert(
+                      specification.asLegacyDesugaredLibrarySpecification(),
+                      app.getLibraryResourceProviders(),
+                      this)
+              : specification.asHumanDesugaredLibrarySpecification();
       machineDesugaredLibrarySpecification =
           new HumanToMachineSpecificationConverter()
               .convert(
                   human,
-                  specification.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
+                  human.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
                   app.getLibraryResourceProviders(),
                   this);
     } catch (IOException e) {
@@ -912,17 +917,19 @@
   }
 
   public void setDesugaredLibrarySpecificationForTesting(
-      LegacyDesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
+      DesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
       throws IOException {
+    if (specification.isEmpty()) {
+      return;
+    }
     HumanDesugaredLibrarySpecification human =
-        new LegacyToHumanSpecificationConverter().convert(specification, library, this);
+        specification.isLegacy()
+            ? new LegacyToHumanSpecificationConverter()
+                .convert(specification.asLegacyDesugaredLibrarySpecification(), library, this)
+            : specification.asHumanDesugaredLibrarySpecification();
     machineDesugaredLibrarySpecification =
         new HumanToMachineSpecificationConverter()
-            .convert(
-                human,
-                specification.isLibraryCompilation() ? desugaredJDKLib : null,
-                library,
-                this);
+            .convert(human, human.isLibraryCompilation() ? desugaredJDKLib : null, library, this);
   }
 
   // Contains flags describing library desugaring.