You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by dw...@apache.org on 2021/11/22 21:19:33 UTC

[iceberg] branch master updated: Core: Add methods to parse TableMetadata from JSON strings (#3592)

This is an automated email from the ASF dual-hosted git repository.

dweeks pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/master by this push:
     new 2338538  Core: Add methods to parse TableMetadata from JSON strings (#3592)
2338538 is described below

commit 23385387e610b54097c9ad4af805fdc13d6005fc
Author: Ryan Blue <bl...@apache.org>
AuthorDate: Mon Nov 22 13:19:24 2021 -0800

    Core: Add methods to parse TableMetadata from JSON strings (#3592)
    
    * Core: Add methods to parse TableMetadata from JSON strings.
    
    * Fix TestTableMetadata.
    
    * Update BaseSnapshot for missing FileIO.
    
    * Fix imports.
---
 .../main/java/org/apache/iceberg/BaseSnapshot.java |  8 ++++
 .../java/org/apache/iceberg/TableMetadata.java     | 44 ++++++++++------------
 .../org/apache/iceberg/TableMetadataParser.java    | 39 ++++++++++++++++++-
 .../java/org/apache/iceberg/TestTableMetadata.java | 43 ++++++++-------------
 4 files changed, 80 insertions(+), 54 deletions(-)

diff --git a/core/src/main/java/org/apache/iceberg/BaseSnapshot.java b/core/src/main/java/org/apache/iceberg/BaseSnapshot.java
index 2641e37..7626d4d 100644
--- a/core/src/main/java/org/apache/iceberg/BaseSnapshot.java
+++ b/core/src/main/java/org/apache/iceberg/BaseSnapshot.java
@@ -132,6 +132,10 @@ class BaseSnapshot implements Snapshot {
   }
 
   private void cacheManifests() {
+    if (io == null) {
+      throw new IllegalStateException("Cannot cache changes: FileIO is null");
+    }
+
     if (allManifests == null) {
       // if manifests isn't set, then the snapshotFile is set and should be read to get the list
       this.allManifests = ManifestLists.read(io.newInputFile(manifestListLocation));
@@ -191,6 +195,10 @@ class BaseSnapshot implements Snapshot {
   }
 
   private void cacheChanges() {
+    if (io == null) {
+      throw new IllegalStateException("Cannot cache changes: FileIO is null");
+    }
+
     ImmutableList.Builder<DataFile> adds = ImmutableList.builder();
     ImmutableList.Builder<DataFile> deletes = ImmutableList.builder();
 
diff --git a/core/src/main/java/org/apache/iceberg/TableMetadata.java b/core/src/main/java/org/apache/iceberg/TableMetadata.java
index 2177207..12e4fc2 100644
--- a/core/src/main/java/org/apache/iceberg/TableMetadata.java
+++ b/core/src/main/java/org/apache/iceberg/TableMetadata.java
@@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import org.apache.iceberg.exceptions.ValidationException;
-import org.apache.iceberg.io.InputFile;
 import org.apache.iceberg.relocated.com.google.common.base.MoreObjects;
 import org.apache.iceberg.relocated.com.google.common.base.Objects;
 import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
@@ -217,8 +216,6 @@ public class TableMetadata implements Serializable {
     }
   }
 
-  private final transient InputFile file;
-
   // stored metadata
   private final String metadataFileLocation;
   private final int formatVersion;
@@ -245,7 +242,7 @@ public class TableMetadata implements Serializable {
   private final List<MetadataLogEntry> previousFiles;
 
   @SuppressWarnings("checkstyle:CyclomaticComplexity")
-  TableMetadata(InputFile file,
+  TableMetadata(String metadataFileLocation,
                 int formatVersion,
                 String uuid,
                 String location,
@@ -273,9 +270,8 @@ public class TableMetadata implements Serializable {
     Preconditions.checkArgument(formatVersion > 1 || lastSequenceNumber == 0,
         "Sequence number must be 0 in v1: %s", lastSequenceNumber);
 
+    this.metadataFileLocation = metadataFileLocation;
     this.formatVersion = formatVersion;
-    this.file = file;
-    this.metadataFileLocation = file != null ? file.location() : null;
     this.uuid = uuid;
     this.location = location;
     this.lastSequenceNumber = lastSequenceNumber;
@@ -478,7 +474,7 @@ public class TableMetadata implements Serializable {
       return new TableMetadata(null, formatVersion, UUID.randomUUID().toString(), location,
           lastSequenceNumber, lastUpdatedMillis, lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
           lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties,
-          currentSnapshotId, snapshots, snapshotLog, addPreviousFile(file, lastUpdatedMillis));
+          currentSnapshotId, snapshots, snapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
     }
   }
 
@@ -504,7 +500,7 @@ public class TableMetadata implements Serializable {
         lastSequenceNumber, System.currentTimeMillis(), newLastColumnId,
         newSchemaId, builder.build(), defaultSpecId, updatedSpecs, lastAssignedPartitionId,
         defaultSortOrderId, updatedSortOrders, properties, currentSnapshotId, snapshots, snapshotLog,
-        addPreviousFile(file, lastUpdatedMillis));
+        addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   // The caller is responsible to pass a newPartitionSpec with correct partition field IDs
@@ -542,7 +538,7 @@ public class TableMetadata implements Serializable {
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, newDefaultSpecId,
         builder.build(), Math.max(lastAssignedPartitionId, newPartitionSpec.lastAssignedFieldId()),
         defaultSortOrderId, sortOrders, properties,
-        currentSnapshotId, snapshots, snapshotLog, addPreviousFile(file, lastUpdatedMillis));
+        currentSnapshotId, snapshots, snapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata replaceSortOrder(SortOrder newOrder) {
@@ -580,7 +576,7 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, formatVersion, uuid, location,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, newOrderId, builder.build(), properties, currentSnapshotId, snapshots, snapshotLog,
-        addPreviousFile(file, lastUpdatedMillis));
+        addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata addStagedSnapshot(Snapshot snapshot) {
@@ -597,7 +593,7 @@ public class TableMetadata implements Serializable {
         snapshot.sequenceNumber(), snapshot.timestampMillis(), lastColumnId,
         currentSchemaId, schemas, defaultSpecId, specs, lastAssignedPartitionId,
         defaultSortOrderId, sortOrders, properties, currentSnapshotId, newSnapshots, snapshotLog,
-        addPreviousFile(file, lastUpdatedMillis));
+        addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata replaceCurrentSnapshot(Snapshot snapshot) {
@@ -623,7 +619,7 @@ public class TableMetadata implements Serializable {
         snapshot.sequenceNumber(), snapshot.timestampMillis(), lastColumnId,
         currentSchemaId, schemas, defaultSpecId, specs, lastAssignedPartitionId,
         defaultSortOrderId, sortOrders, properties, snapshot.snapshotId(), newSnapshots, newSnapshotLog,
-        addPreviousFile(file, lastUpdatedMillis));
+        addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata removeSnapshotsIf(Predicate<Snapshot> removeIf) {
@@ -655,7 +651,7 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, formatVersion, uuid, location,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, currentSnapshotId, filtered,
-        ImmutableList.copyOf(newSnapshotLog), addPreviousFile(file, lastUpdatedMillis));
+        ImmutableList.copyOf(newSnapshotLog), addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   private TableMetadata setCurrentSnapshotTo(Snapshot snapshot) {
@@ -679,7 +675,7 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, formatVersion, uuid, location,
         lastSequenceNumber, nowMillis, lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, snapshot.snapshotId(), snapshots,
-        newSnapshotLog, addPreviousFile(file, lastUpdatedMillis));
+        newSnapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata replaceProperties(Map<String, String> rawProperties) {
@@ -688,7 +684,7 @@ public class TableMetadata implements Serializable {
     TableMetadata metadata = new TableMetadata(null, formatVersion, uuid, location,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, newProperties, currentSnapshotId, snapshots,
-        snapshotLog, addPreviousFile(file, lastUpdatedMillis, newProperties));
+        snapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis, newProperties));
 
     int newFormatVersion = PropertyUtil.propertyAsInt(rawProperties, TableProperties.FORMAT_VERSION, formatVersion);
     if (formatVersion != newFormatVersion) {
@@ -714,7 +710,7 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, formatVersion, uuid, location,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, currentSnapshotId,
-        snapshots, newSnapshotLog, addPreviousFile(file, lastUpdatedMillis));
+        snapshots, newSnapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   private PartitionSpec reassignPartitionIds(PartitionSpec partitionSpec, TypeUtil.NextID nextID) {
@@ -842,7 +838,7 @@ public class TableMetadata implements Serializable {
         lastSequenceNumber, System.currentTimeMillis(), newLastColumnId.get(), freshSchemaId, schemasBuilder.build(),
         specId, specListBuilder.build(), Math.max(lastAssignedPartitionId, newSpec.lastAssignedFieldId()),
         orderId, sortOrdersBuilder.build(), ImmutableMap.copyOf(newProperties),
-        -1, snapshots, ImmutableList.of(), addPreviousFile(file, lastUpdatedMillis, newProperties));
+        -1, snapshots, ImmutableList.of(), addPreviousFile(metadataFileLocation, lastUpdatedMillis, newProperties));
 
     if (formatVersion != newFormatVersion) {
       metadata = metadata.upgradeToFormatVersion(newFormatVersion);
@@ -855,7 +851,7 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, formatVersion, uuid, newLocation,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, currentSnapshotId,
-        snapshots, snapshotLog, addPreviousFile(file, lastUpdatedMillis));
+        snapshots, snapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
   public TableMetadata upgradeToFormatVersion(int newFormatVersion) {
@@ -872,16 +868,16 @@ public class TableMetadata implements Serializable {
     return new TableMetadata(null, newFormatVersion, uuid, location,
         lastSequenceNumber, System.currentTimeMillis(), lastColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, currentSnapshotId,
-        snapshots, snapshotLog, addPreviousFile(file, lastUpdatedMillis));
+        snapshots, snapshotLog, addPreviousFile(metadataFileLocation, lastUpdatedMillis));
   }
 
-  private List<MetadataLogEntry> addPreviousFile(InputFile previousFile, long timestampMillis) {
-    return addPreviousFile(previousFile, timestampMillis, properties);
+  private List<MetadataLogEntry> addPreviousFile(String previousFileLocation, long timestampMillis) {
+    return addPreviousFile(previousFileLocation, timestampMillis, properties);
   }
 
-  private List<MetadataLogEntry> addPreviousFile(InputFile previousFile, long timestampMillis,
+  private List<MetadataLogEntry> addPreviousFile(String previousFileLocation, long timestampMillis,
                                                  Map<String, String> updatedProperties) {
-    if (previousFile == null) {
+    if (previousFileLocation == null) {
       return previousFiles;
     }
 
@@ -895,7 +891,7 @@ public class TableMetadata implements Serializable {
     } else {
       newMetadataLog = Lists.newArrayList(previousFiles);
     }
-    newMetadataLog.add(new MetadataLogEntry(timestampMillis, previousFile.location()));
+    newMetadataLog.add(new MetadataLogEntry(timestampMillis, previousFileLocation));
 
     return newMetadataLog;
   }
diff --git a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
index 655a733..1e26fbb 100644
--- a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
+++ b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
@@ -26,6 +26,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.StringWriter;
+import java.io.UncheckedIOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.List;
@@ -253,8 +254,42 @@ public class TableMetadataParser {
     }
   }
 
-  @SuppressWarnings("checkstyle:CyclomaticComplexity")
+  /**
+   * Read TableMetadata from a JSON string.
+   * <p>
+   * The TableMetadata's metadata file location will be unset.
+   *
+   * @param io a FileIO used by {@link Snapshot} instances
+   * @param json a JSON string of table metadata
+   * @return a TableMetadata object
+   */
+  public static TableMetadata fromJson(FileIO io, String json) {
+    return fromJson(io, null, json);
+  }
+
+  /**
+   * Read TableMetadata from a JSON string.
+   *
+   * @param io a FileIO used by {@link Snapshot} instances
+   * @param metadataLocation metadata location for the returned {@link TableMetadata}
+   * @param json a JSON string of table metadata
+   * @return a TableMetadata object
+   */
+  public static TableMetadata fromJson(FileIO io, String metadataLocation, String json) {
+    try {
+      JsonNode node = JsonUtil.mapper().readValue(json, JsonNode.class);
+      return fromJson(io, metadataLocation, node);
+    } catch (IOException e) {
+      throw new UncheckedIOException("Failed to read JSON string: " + json, e);
+    }
+  }
+
   static TableMetadata fromJson(FileIO io, InputFile file, JsonNode node) {
+    return fromJson(io, file.location(), node);
+  }
+
+  @SuppressWarnings("checkstyle:CyclomaticComplexity")
+  static TableMetadata fromJson(FileIO io, String metadataLocation, JsonNode node) {
     Preconditions.checkArgument(node.isObject(),
         "Cannot parse metadata from a non-object: %s", node);
 
@@ -395,7 +430,7 @@ public class TableMetadataParser {
       }
     }
 
-    return new TableMetadata(file, formatVersion, uuid, location,
+    return new TableMetadata(metadataLocation, formatVersion, uuid, location,
         lastSequenceNumber, lastUpdatedMillis, lastAssignedColumnId, currentSchemaId, schemas, defaultSpecId, specs,
         lastAssignedPartitionId, defaultSortOrderId, sortOrders, properties, currentVersionId,
         snapshots, entries.build(), metadataEntries.build());
diff --git a/core/src/test/java/org/apache/iceberg/TestTableMetadata.java b/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
index 06e9b1b..6ddbeab 100644
--- a/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
+++ b/core/src/test/java/org/apache/iceberg/TestTableMetadata.java
@@ -20,7 +20,6 @@
 package org.apache.iceberg;
 
 import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonNode;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.UncheckedIOException;
@@ -112,8 +111,7 @@ public class TestTableMetadata {
         Arrays.asList(previousSnapshot, currentSnapshot), snapshotLog, ImmutableList.of());
 
     String asJson = TableMetadataParser.toJson(expected);
-    TableMetadata metadata = TableMetadataParser.fromJson(ops.io(), null,
-        JsonUtil.mapper().readValue(asJson, JsonNode.class));
+    TableMetadata metadata = TableMetadataParser.fromJson(ops.io(), asJson);
 
     Assert.assertEquals("Format version should match",
         expected.formatVersion(), metadata.formatVersion());
@@ -185,8 +183,7 @@ public class TestTableMetadata {
         currentSnapshotId, Arrays.asList(previousSnapshot, currentSnapshot), ImmutableList.of(), ImmutableList.of());
 
     String asJson = toJsonWithoutSpecAndSchemaList(expected);
-    TableMetadata metadata = TableMetadataParser
-        .fromJson(ops.io(), null, JsonUtil.mapper().readValue(asJson, JsonNode.class));
+    TableMetadata metadata = TableMetadataParser.fromJson(ops.io(), asJson);
 
     Assert.assertEquals("Format version should match",
         expected.formatVersion(), metadata.formatVersion());
@@ -308,8 +305,7 @@ public class TestTableMetadata {
         ImmutableList.copyOf(previousMetadataLog));
 
     String asJson = TableMetadataParser.toJson(base);
-    TableMetadata metadataFromJson = TableMetadataParser.fromJson(ops.io(), null,
-        JsonUtil.mapper().readValue(asJson, JsonNode.class));
+    TableMetadata metadataFromJson = TableMetadataParser.fromJson(ops.io(), asJson);
 
     Assert.assertEquals("Metadata logs should match", previousMetadataLog, metadataFromJson.previousFiles());
   }
@@ -336,7 +332,7 @@ public class TestTableMetadata {
     MetadataLogEntry latestPreviousMetadata = new MetadataLogEntry(currentTimestamp - 80,
         "/tmp/000003-" + UUID.randomUUID().toString() + ".metadata.json");
 
-    TableMetadata base = new TableMetadata(localInput(latestPreviousMetadata.file()), 1, UUID.randomUUID().toString(),
+    TableMetadata base = new TableMetadata(latestPreviousMetadata.file(), 1, UUID.randomUUID().toString(),
         TEST_LOCATION, 0, currentTimestamp - 80, 3,
         7, ImmutableList.of(TEST_SCHEMA), 5, ImmutableList.of(SPEC_5), SPEC_5.lastAssignedFieldId(),
         3, ImmutableList.of(SORT_ORDER_3), ImmutableMap.of("property", "value"), currentSnapshotId,
@@ -382,7 +378,7 @@ public class TestTableMetadata {
     MetadataLogEntry latestPreviousMetadata = new MetadataLogEntry(currentTimestamp - 50,
         "/tmp/000006-" + UUID.randomUUID().toString() + ".metadata.json");
 
-    TableMetadata base = new TableMetadata(localInput(latestPreviousMetadata.file()), 1, UUID.randomUUID().toString(),
+    TableMetadata base = new TableMetadata(latestPreviousMetadata.file(), 1, UUID.randomUUID().toString(),
         TEST_LOCATION, 0, currentTimestamp - 50, 3,
         7, ImmutableList.of(TEST_SCHEMA), 5,
         ImmutableList.of(SPEC_5), SPEC_5.lastAssignedFieldId(), 3, ImmutableList.of(SORT_ORDER_3),
@@ -434,7 +430,7 @@ public class TestTableMetadata {
     MetadataLogEntry latestPreviousMetadata = new MetadataLogEntry(currentTimestamp - 50,
         "/tmp/000006-" + UUID.randomUUID().toString() + ".metadata.json");
 
-    TableMetadata base = new TableMetadata(localInput(latestPreviousMetadata.file()), 1, UUID.randomUUID().toString(),
+    TableMetadata base = new TableMetadata(latestPreviousMetadata.file(), 1, UUID.randomUUID().toString(),
         TEST_LOCATION, 0, currentTimestamp - 50, 3, 7, ImmutableList.of(TEST_SCHEMA), 2,
         ImmutableList.of(SPEC_5), SPEC_5.lastAssignedFieldId(),
         TableMetadata.INITIAL_SORT_ORDER_ID, ImmutableList.of(SortOrder.unsorted()),
@@ -486,20 +482,17 @@ public class TestTableMetadata {
   @Test
   public void testParserVersionValidation() throws Exception {
     String supportedVersion1 = readTableMetadataInputFile("TableMetadataV1Valid.json");
-    TableMetadata parsed1 = TableMetadataParser.fromJson(
-        ops.io(), null, JsonUtil.mapper().readValue(supportedVersion1, JsonNode.class));
+    TableMetadata parsed1 = TableMetadataParser.fromJson(ops.io(), supportedVersion1);
     Assert.assertNotNull("Should successfully read supported metadata version", parsed1);
 
     String supportedVersion2 = readTableMetadataInputFile("TableMetadataV2Valid.json");
-    TableMetadata parsed2 = TableMetadataParser.fromJson(
-        ops.io(), null, JsonUtil.mapper().readValue(supportedVersion2, JsonNode.class));
+    TableMetadata parsed2 = TableMetadataParser.fromJson(ops.io(), supportedVersion2);
     Assert.assertNotNull("Should successfully read supported metadata version", parsed2);
 
     String unsupportedVersion = readTableMetadataInputFile("TableMetadataUnsupportedVersion.json");
     AssertHelpers.assertThrows("Should not read unsupported metadata",
         IllegalArgumentException.class, "Cannot read unsupported version",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupportedVersion, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupportedVersion)
     );
   }
 
@@ -509,8 +502,7 @@ public class TestTableMetadata {
     String unsupportedVersion = readTableMetadataInputFile("TableMetadataV2MissingPartitionSpecs.json");
     AssertHelpers.assertThrows("Should reject v2 metadata without partition specs",
         IllegalArgumentException.class, "partition-specs must exist in format v2",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupportedVersion, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupportedVersion)
     );
   }
 
@@ -519,8 +511,7 @@ public class TestTableMetadata {
     String unsupportedVersion = readTableMetadataInputFile("TableMetadataV2MissingLastPartitionId.json");
     AssertHelpers.assertThrows("Should reject v2 metadata without last assigned partition field id",
         IllegalArgumentException.class, "last-partition-id must exist in format v2",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupportedVersion, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupportedVersion)
     );
   }
 
@@ -529,8 +520,7 @@ public class TestTableMetadata {
     String unsupportedVersion = readTableMetadataInputFile("TableMetadataV2MissingSortOrder.json");
     AssertHelpers.assertThrows("Should reject v2 metadata without sort order",
         IllegalArgumentException.class, "sort-orders must exist in format v2",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupportedVersion, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupportedVersion)
     );
   }
 
@@ -539,8 +529,7 @@ public class TestTableMetadata {
     String unsupported = readTableMetadataInputFile("TableMetadataV2CurrentSchemaNotFound.json");
     AssertHelpers.assertThrows("Should reject v2 metadata without valid schema id",
         IllegalArgumentException.class, "Cannot find schema with current-schema-id=2 from schemas",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupported, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupported)
     );
   }
 
@@ -549,8 +538,7 @@ public class TestTableMetadata {
     String unsupported = readTableMetadataInputFile("TableMetadataV2MissingSchemas.json");
     AssertHelpers.assertThrows("Should reject v2 metadata without schemas",
         IllegalArgumentException.class, "schemas must exist in format v2",
-        () -> TableMetadataParser.fromJson(
-            ops.io(), null, JsonUtil.mapper().readValue(unsupported, JsonNode.class))
+        () -> TableMetadataParser.fromJson(ops.io(), unsupported)
     );
   }
 
@@ -726,8 +714,7 @@ public class TestTableMetadata {
   @Test
   public void testParseSchemaIdentifierFields() throws Exception {
     String data = readTableMetadataInputFile("TableMetadataV2Valid.json");
-    TableMetadata parsed = TableMetadataParser.fromJson(
-        ops.io(), null, JsonUtil.mapper().readValue(data, JsonNode.class));
+    TableMetadata parsed = TableMetadataParser.fromJson(ops.io(), data);
     Assert.assertEquals(Sets.newHashSet(), parsed.schemasById().get(0).identifierFieldIds());
     Assert.assertEquals(Sets.newHashSet(1, 2), parsed.schemasById().get(1).identifierFieldIds());
   }