You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by bl...@apache.org on 2022/10/06 18:56:52 UTC

[iceberg] branch master updated: Core: Provide better error message on invalid enums (#5910)

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

blue 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 caf03aed92 Core: Provide better error message on invalid enums (#5910)
caf03aed92 is described below

commit caf03aed926665014c22cc4a68902bf684f258f9
Author: Eduard Tudenhöfner <et...@gmail.com>
AuthorDate: Thu Oct 6 20:56:45 2022 +0200

    Core: Provide better error message on invalid enums (#5910)
---
 .../java/org/apache/iceberg/DistributionMode.java     |  8 ++++++--
 .../main/java/org/apache/iceberg/RewriteJobOrder.java |  9 +++++++--
 .../main/java/org/apache/iceberg/SnapshotRefType.java | 15 ++++++++++++++-
 .../main/java/org/apache/iceberg/SortDirection.java   | 15 ++++++++++++++-
 .../org/apache/iceberg/actions/DeleteOrphanFiles.java |  8 ++++++--
 .../org/apache/iceberg/expressions/Expression.java    | 12 ++++++++++++
 .../org/apache/iceberg/metrics/MetricsContext.java    |  8 +++++++-
 .../main/java/org/apache/iceberg/IsolationLevel.java  |  9 +++++++--
 .../java/org/apache/iceberg/MetadataUpdateParser.java |  3 +--
 .../java/org/apache/iceberg/SnapshotRefParser.java    |  3 +--
 .../main/java/org/apache/iceberg/SortOrderParser.java |  8 ++------
 .../java/org/apache/iceberg/TableMetadataParser.java  |  6 +++++-
 .../apache/iceberg/expressions/ExpressionParser.java  |  4 ++--
 .../org/apache/iceberg/metrics/TimerResultParser.java | 14 +++++++++++---
 .../iceberg/rest/requests/ReportMetricsRequest.java   | 12 +++++++++++-
 .../rest/requests/ReportMetricsRequestParser.java     |  4 ++--
 .../apache/iceberg/TableMetadataParserCodecTest.java  |  2 +-
 .../org/apache/iceberg/TestSnapshotRefParser.java     |  2 +-
 .../java/org/apache/iceberg/TestSortOrderParser.java  | 19 +++++++++++++++++++
 .../iceberg/expressions/TestExpressionParser.java     |  4 ++--
 .../iceberg/metrics/TestCounterResultParser.java      |  2 +-
 .../apache/iceberg/metrics/TestTimerResultParser.java |  2 +-
 .../rest/requests/TestReportMetricsRequestParser.java |  3 +--
 .../iceberg/flink/sink/TestFlinkIcebergSink.java      |  2 +-
 .../iceberg/flink/sink/TestFlinkIcebergSink.java      |  2 +-
 .../iceberg/flink/sink/TestFlinkIcebergSink.java      |  2 +-
 .../iceberg/spark/source/SparkMergeBuilder.java       |  3 +--
 .../iceberg/spark/source/SparkMergeBuilder.java       |  3 +--
 28 files changed, 139 insertions(+), 45 deletions(-)

diff --git a/api/src/main/java/org/apache/iceberg/DistributionMode.java b/api/src/main/java/org/apache/iceberg/DistributionMode.java
index b4f2649ce1..a7625675e1 100644
--- a/api/src/main/java/org/apache/iceberg/DistributionMode.java
+++ b/api/src/main/java/org/apache/iceberg/DistributionMode.java
@@ -52,7 +52,11 @@ public enum DistributionMode {
   }
 
   public static DistributionMode fromName(String modeName) {
-    Preconditions.checkNotNull(modeName, "Name of distribution mode should not be null");
-    return DistributionMode.valueOf(modeName.toUpperCase(Locale.ENGLISH));
+    Preconditions.checkArgument(null != modeName, "Invalid distribution mode: null");
+    try {
+      return DistributionMode.valueOf(modeName.toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(String.format("Invalid distribution mode: %s", modeName));
+    }
   }
 }
diff --git a/api/src/main/java/org/apache/iceberg/RewriteJobOrder.java b/api/src/main/java/org/apache/iceberg/RewriteJobOrder.java
index 2face482a5..7038f127af 100644
--- a/api/src/main/java/org/apache/iceberg/RewriteJobOrder.java
+++ b/api/src/main/java/org/apache/iceberg/RewriteJobOrder.java
@@ -55,9 +55,14 @@ public enum RewriteJobOrder {
   }
 
   public static RewriteJobOrder fromName(String orderName) {
-    Preconditions.checkArgument(orderName != null, "Rewrite job order name should not be null");
+    Preconditions.checkArgument(orderName != null, "Invalid rewrite job order name: null");
     // Replace the hyphen in order name with underscore to map to the enum value. For example:
     // bytes-asc to BYTES_ASC
-    return RewriteJobOrder.valueOf(orderName.replaceFirst("-", "_").toUpperCase(Locale.ENGLISH));
+    try {
+      return RewriteJobOrder.valueOf(orderName.replaceFirst("-", "_").toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          String.format("Invalid rewrite job order name: %s", orderName), e);
+    }
   }
 }
diff --git a/api/src/main/java/org/apache/iceberg/SnapshotRefType.java b/api/src/main/java/org/apache/iceberg/SnapshotRefType.java
index b878d9d0dd..b72c675da6 100644
--- a/api/src/main/java/org/apache/iceberg/SnapshotRefType.java
+++ b/api/src/main/java/org/apache/iceberg/SnapshotRefType.java
@@ -18,7 +18,20 @@
  */
 package org.apache.iceberg;
 
+import java.util.Locale;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
+
 enum SnapshotRefType {
   BRANCH,
-  TAG
+  TAG;
+
+  public static SnapshotRefType fromString(String snapshotRefType) {
+    Preconditions.checkArgument(null != snapshotRefType, "Invalid snapshot ref type: null");
+    try {
+      return SnapshotRefType.valueOf(snapshotRefType.toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          String.format("Invalid snapshot ref type: %s", snapshotRefType), e);
+    }
+  }
 }
diff --git a/api/src/main/java/org/apache/iceberg/SortDirection.java b/api/src/main/java/org/apache/iceberg/SortDirection.java
index 5436f14c9c..d76fe199f9 100644
--- a/api/src/main/java/org/apache/iceberg/SortDirection.java
+++ b/api/src/main/java/org/apache/iceberg/SortDirection.java
@@ -18,7 +18,20 @@
  */
 package org.apache.iceberg;
 
+import java.util.Locale;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
+
 public enum SortDirection {
   ASC,
-  DESC
+  DESC;
+
+  public static SortDirection fromString(String directionAsString) {
+    Preconditions.checkArgument(null != directionAsString, "Invalid sort direction: null");
+    try {
+      return SortDirection.valueOf(directionAsString.toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          String.format("Invalid sort direction: %s", directionAsString), e);
+    }
+  }
 }
diff --git a/api/src/main/java/org/apache/iceberg/actions/DeleteOrphanFiles.java b/api/src/main/java/org/apache/iceberg/actions/DeleteOrphanFiles.java
index 2dd741770c..0e00eb67b2 100644
--- a/api/src/main/java/org/apache/iceberg/actions/DeleteOrphanFiles.java
+++ b/api/src/main/java/org/apache/iceberg/actions/DeleteOrphanFiles.java
@@ -153,8 +153,12 @@ public interface DeleteOrphanFiles extends Action<DeleteOrphanFiles, DeleteOrpha
     DELETE;
 
     public static PrefixMismatchMode fromString(String modeAsString) {
-      Preconditions.checkArgument(modeAsString != null, "Mode should not be null");
-      return PrefixMismatchMode.valueOf(modeAsString.toUpperCase(Locale.ENGLISH));
+      Preconditions.checkArgument(modeAsString != null, "Invalid mode: null");
+      try {
+        return PrefixMismatchMode.valueOf(modeAsString.toUpperCase(Locale.ENGLISH));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(String.format("Invalid mode: %s", modeAsString), e);
+      }
     }
   }
 }
diff --git a/api/src/main/java/org/apache/iceberg/expressions/Expression.java b/api/src/main/java/org/apache/iceberg/expressions/Expression.java
index b013be9395..cd82aa07ad 100644
--- a/api/src/main/java/org/apache/iceberg/expressions/Expression.java
+++ b/api/src/main/java/org/apache/iceberg/expressions/Expression.java
@@ -19,6 +19,8 @@
 package org.apache.iceberg.expressions;
 
 import java.io.Serializable;
+import java.util.Locale;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
 
 /** Represents a boolean expression tree. */
 public interface Expression extends Serializable {
@@ -43,6 +45,16 @@ public interface Expression extends Serializable {
     STARTS_WITH,
     NOT_STARTS_WITH;
 
+    public static Operation fromString(String operationType) {
+      Preconditions.checkArgument(null != operationType, "Invalid operation type: null");
+      try {
+        return Expression.Operation.valueOf(operationType.toUpperCase(Locale.ENGLISH));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(
+            String.format("Invalid operation type: %s", operationType), e);
+      }
+    }
+
     /** Returns the operation used when this is negated. */
     public Operation negate() {
       switch (this) {
diff --git a/api/src/main/java/org/apache/iceberg/metrics/MetricsContext.java b/api/src/main/java/org/apache/iceberg/metrics/MetricsContext.java
index 1c2e9fe70f..73713d9970 100644
--- a/api/src/main/java/org/apache/iceberg/metrics/MetricsContext.java
+++ b/api/src/main/java/org/apache/iceberg/metrics/MetricsContext.java
@@ -23,6 +23,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
 
 /**
  * Generalized interface for creating telemetry related instances for tracking operations.
@@ -45,7 +46,12 @@ public interface MetricsContext extends Serializable {
     }
 
     public static Unit fromDisplayName(String displayName) {
-      return Unit.valueOf(displayName.toUpperCase(Locale.ROOT));
+      Preconditions.checkArgument(null != displayName, "Invalid unit: null");
+      try {
+        return Unit.valueOf(displayName.toUpperCase(Locale.ENGLISH));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(String.format("Invalid unit: %s", displayName), e);
+      }
     }
   }
 
diff --git a/core/src/main/java/org/apache/iceberg/IsolationLevel.java b/core/src/main/java/org/apache/iceberg/IsolationLevel.java
index 1f4dd9aadd..bf7098b6e9 100644
--- a/core/src/main/java/org/apache/iceberg/IsolationLevel.java
+++ b/core/src/main/java/org/apache/iceberg/IsolationLevel.java
@@ -41,7 +41,12 @@ public enum IsolationLevel {
   SNAPSHOT;
 
   public static IsolationLevel fromName(String levelName) {
-    Preconditions.checkArgument(levelName != null, "Level name is null");
-    return IsolationLevel.valueOf(levelName.toUpperCase(Locale.ROOT));
+    Preconditions.checkArgument(levelName != null, "Invalid isolation level: null");
+    try {
+      return IsolationLevel.valueOf(levelName.toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(
+          String.format("Invalid isolation level: %s", levelName), e);
+    }
   }
 }
diff --git a/core/src/main/java/org/apache/iceberg/MetadataUpdateParser.java b/core/src/main/java/org/apache/iceberg/MetadataUpdateParser.java
index 168da90122..955f6be8c9 100644
--- a/core/src/main/java/org/apache/iceberg/MetadataUpdateParser.java
+++ b/core/src/main/java/org/apache/iceberg/MetadataUpdateParser.java
@@ -461,8 +461,7 @@ public class MetadataUpdateParser {
   private static MetadataUpdate readSetSnapshotRef(JsonNode node) {
     String refName = JsonUtil.getString(REF_NAME, node);
     long snapshotId = JsonUtil.getLong(SNAPSHOT_ID, node);
-    SnapshotRefType type =
-        SnapshotRefType.valueOf(JsonUtil.getString(TYPE, node).toUpperCase(Locale.ENGLISH));
+    SnapshotRefType type = SnapshotRefType.fromString(JsonUtil.getString(TYPE, node));
     Integer minSnapshotsToKeep = JsonUtil.getIntOrNull(MIN_SNAPSHOTS_TO_KEEP, node);
     Long maxSnapshotAgeMs = JsonUtil.getLongOrNull(MAX_SNAPSHOT_AGE_MS, node);
     Long maxRefAgeMs = JsonUtil.getLongOrNull(MAX_REF_AGE_MS, node);
diff --git a/core/src/main/java/org/apache/iceberg/SnapshotRefParser.java b/core/src/main/java/org/apache/iceberg/SnapshotRefParser.java
index ac600a7dbf..3c14ceab7d 100644
--- a/core/src/main/java/org/apache/iceberg/SnapshotRefParser.java
+++ b/core/src/main/java/org/apache/iceberg/SnapshotRefParser.java
@@ -74,8 +74,7 @@ public class SnapshotRefParser {
     Preconditions.checkArgument(
         node.isObject(), "Cannot parse snapshot reference from a non-object: %s", node);
     long snapshotId = JsonUtil.getLong(SNAPSHOT_ID, node);
-    SnapshotRefType type =
-        SnapshotRefType.valueOf(JsonUtil.getString(TYPE, node).toUpperCase(Locale.ENGLISH));
+    SnapshotRefType type = SnapshotRefType.fromString(JsonUtil.getString(TYPE, node));
     Integer minSnapshotsToKeep = JsonUtil.getIntOrNull(MIN_SNAPSHOTS_TO_KEEP, node);
     Long maxSnapshotAgeMs = JsonUtil.getLongOrNull(MAX_SNAPSHOT_AGE_MS, node);
     Long maxRefAgeMs = JsonUtil.getLongOrNull(MAX_REF_AGE_MS, node);
diff --git a/core/src/main/java/org/apache/iceberg/SortOrderParser.java b/core/src/main/java/org/apache/iceberg/SortOrderParser.java
index 79ff32d19d..4481f83513 100644
--- a/core/src/main/java/org/apache/iceberg/SortOrderParser.java
+++ b/core/src/main/java/org/apache/iceberg/SortOrderParser.java
@@ -56,7 +56,7 @@ public class SortOrderParser {
   }
 
   private static String toJson(SortDirection direction) {
-    return direction.toString().toLowerCase(Locale.ROOT);
+    return direction.toString().toLowerCase(Locale.ENGLISH);
   }
 
   private static String toJson(NullOrder nullOrder) {
@@ -144,7 +144,7 @@ public class SortOrderParser {
       int sourceId = JsonUtil.getInt(SOURCE_ID, element);
 
       String directionAsString = JsonUtil.getString(DIRECTION, element);
-      SortDirection direction = toDirection(directionAsString);
+      SortDirection direction = SortDirection.fromString(directionAsString);
 
       String nullOrderingAsString = JsonUtil.getString(NULL_ORDER, element);
       NullOrder nullOrder = toNullOrder(nullOrderingAsString);
@@ -153,10 +153,6 @@ public class SortOrderParser {
     }
   }
 
-  private static SortDirection toDirection(String directionAsString) {
-    return SortDirection.valueOf(directionAsString.toUpperCase(Locale.ROOT));
-  }
-
   private static NullOrder toNullOrder(String nullOrderingAsString) {
     switch (nullOrderingAsString.toLowerCase(Locale.ROOT)) {
       case "nulls-first":
diff --git a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
index 52a913943e..7633a7dd39 100644
--- a/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
+++ b/core/src/main/java/org/apache/iceberg/TableMetadataParser.java
@@ -59,7 +59,11 @@ public class TableMetadataParser {
 
     public static Codec fromName(String codecName) {
       Preconditions.checkArgument(codecName != null, "Codec name is null");
-      return Codec.valueOf(codecName.toUpperCase(Locale.ENGLISH));
+      try {
+        return Codec.valueOf(codecName.toUpperCase(Locale.ENGLISH));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(String.format("Invalid codec name: %s", codecName), e);
+      }
     }
 
     public static Codec fromFileName(String fileName) {
diff --git a/core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java b/core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java
index 6748f0bb37..9a6bfe863f 100644
--- a/core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java
+++ b/core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java
@@ -230,7 +230,7 @@ public class ExpressionParser {
     }
 
     private String operationType(Expression.Operation op) {
-      return op.toString().replaceAll("_", "-").toLowerCase(Locale.ROOT);
+      return op.toString().replaceAll("_", "-").toLowerCase(Locale.ENGLISH);
     }
 
     private void term(Term term) throws IOException {
@@ -312,7 +312,7 @@ public class ExpressionParser {
   }
 
   private static Expression.Operation fromType(String type) {
-    return Expression.Operation.valueOf(type.replaceAll("-", "_").toUpperCase(Locale.ROOT));
+    return Expression.Operation.fromString(type.replaceAll("-", "_"));
   }
 
   @SuppressWarnings("unchecked")
diff --git a/core/src/main/java/org/apache/iceberg/metrics/TimerResultParser.java b/core/src/main/java/org/apache/iceberg/metrics/TimerResultParser.java
index a296d69689..da0550b9d6 100644
--- a/core/src/main/java/org/apache/iceberg/metrics/TimerResultParser.java
+++ b/core/src/main/java/org/apache/iceberg/metrics/TimerResultParser.java
@@ -53,7 +53,7 @@ class TimerResultParser {
 
     gen.writeStartObject();
     gen.writeNumberField(COUNT, timer.count());
-    gen.writeStringField(TIME_UNIT, timer.timeUnit().name().toLowerCase(Locale.ROOT));
+    gen.writeStringField(TIME_UNIT, timer.timeUnit().name().toLowerCase(Locale.ENGLISH));
     gen.writeNumberField(TOTAL_DURATION, fromDuration(timer.totalDuration(), timer.timeUnit()));
     gen.writeEndObject();
   }
@@ -67,7 +67,7 @@ class TimerResultParser {
     Preconditions.checkArgument(json.isObject(), "Cannot parse timer from non-object: %s", json);
 
     long count = JsonUtil.getLong(COUNT, json);
-    TimeUnit unit = TimeUnit.valueOf(JsonUtil.getString(TIME_UNIT, json).toUpperCase(Locale.ROOT));
+    TimeUnit unit = toTimeUnit(JsonUtil.getString(TIME_UNIT, json));
     long duration = JsonUtil.getLong(TOTAL_DURATION, json);
     return TimerResult.of(unit, toDuration(duration, unit), count);
   }
@@ -96,7 +96,7 @@ class TimerResultParser {
         timer.has(TOTAL_DURATION), MISSING_FIELD_ERROR_MSG, timerName, TOTAL_DURATION);
 
     long count = JsonUtil.getLong(COUNT, timer);
-    TimeUnit unit = TimeUnit.valueOf(JsonUtil.getString(TIME_UNIT, timer).toUpperCase(Locale.ROOT));
+    TimeUnit unit = toTimeUnit(JsonUtil.getString(TIME_UNIT, timer));
     long duration = JsonUtil.getLong(TOTAL_DURATION, timer);
     return TimerResult.of(unit, toDuration(duration, unit), count);
   }
@@ -111,6 +111,14 @@ class TimerResultParser {
     return Duration.of(val, toChronoUnit(unit));
   }
 
+  private static TimeUnit toTimeUnit(String timeUnit) {
+    try {
+      return TimeUnit.valueOf(timeUnit.toUpperCase(Locale.ENGLISH));
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(String.format("Invalid time unit: %s", timeUnit), e);
+    }
+  }
+
   private static ChronoUnit toChronoUnit(TimeUnit unit) {
     switch (unit) {
       case NANOSECONDS:
diff --git a/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequest.java b/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequest.java
index c3055d661e..963cb1a4f0 100644
--- a/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequest.java
+++ b/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.iceberg.rest.requests;
 
+import java.util.Locale;
 import org.apache.iceberg.metrics.MetricsReport;
 import org.apache.iceberg.metrics.ScanReport;
 import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
@@ -28,7 +29,16 @@ import org.immutables.value.Value;
 public interface ReportMetricsRequest extends RESTRequest {
 
   enum ReportType {
-    SCAN_REPORT
+    SCAN_REPORT;
+
+    static ReportType fromString(String reportType) {
+      Preconditions.checkArgument(null != reportType, "Invalid report type: null");
+      try {
+        return ReportType.valueOf(reportType.toUpperCase(Locale.ENGLISH));
+      } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException(String.format("Invalid report type: %s", reportType), e);
+      }
+    }
   }
 
   ReportType reportType();
diff --git a/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequestParser.java b/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequestParser.java
index c0e826d03b..f180da09cd 100644
--- a/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequestParser.java
+++ b/core/src/main/java/org/apache/iceberg/rest/requests/ReportMetricsRequestParser.java
@@ -57,11 +57,11 @@ public class ReportMetricsRequestParser {
   }
 
   private static String fromReportType(ReportType reportType) {
-    return reportType.name().replaceAll("_", "-").toLowerCase(Locale.ROOT);
+    return reportType.name().replaceAll("_", "-").toLowerCase(Locale.ENGLISH);
   }
 
   private static ReportType toReportType(String type) {
-    return ReportType.valueOf(type.replaceAll("-", "_").toUpperCase(Locale.ROOT));
+    return ReportType.fromString(type.replaceAll("-", "_"));
   }
 
   public static ReportMetricsRequest fromJson(String json) {
diff --git a/core/src/test/java/org/apache/iceberg/TableMetadataParserCodecTest.java b/core/src/test/java/org/apache/iceberg/TableMetadataParserCodecTest.java
index bcc08b26eb..597eb50fd3 100644
--- a/core/src/test/java/org/apache/iceberg/TableMetadataParserCodecTest.java
+++ b/core/src/test/java/org/apache/iceberg/TableMetadataParserCodecTest.java
@@ -42,7 +42,7 @@ public class TableMetadataParserCodecTest {
   public void testInvalidCodecName() {
     Assertions.assertThatThrownBy(() -> Codec.fromName("invalid"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("No enum constant org.apache.iceberg.TableMetadataParser.Codec.INVALID");
+        .hasMessage("Invalid codec name: invalid");
   }
 
   @Test
diff --git a/core/src/test/java/org/apache/iceberg/TestSnapshotRefParser.java b/core/src/test/java/org/apache/iceberg/TestSnapshotRefParser.java
index 8216ea3437..d193671d61 100644
--- a/core/src/test/java/org/apache/iceberg/TestSnapshotRefParser.java
+++ b/core/src/test/java/org/apache/iceberg/TestSnapshotRefParser.java
@@ -151,7 +151,7 @@ public class TestSnapshotRefParser {
     AssertHelpers.assertThrows(
         "SnapshotRefParser should fail to deserialize ref with invalid tag",
         IllegalArgumentException.class,
-        "No enum constant",
+        "Invalid snapshot ref type: not-a-valid-tag-type",
         () -> SnapshotRefParser.fromJson(invalidTagType));
 
     String invalidRefAge =
diff --git a/core/src/test/java/org/apache/iceberg/TestSortOrderParser.java b/core/src/test/java/org/apache/iceberg/TestSortOrderParser.java
index 2505bcedce..2bd5b1e62b 100644
--- a/core/src/test/java/org/apache/iceberg/TestSortOrderParser.java
+++ b/core/src/test/java/org/apache/iceberg/TestSortOrderParser.java
@@ -54,4 +54,23 @@ public class TestSortOrderParser extends TableTestBase {
     Assert.assertEquals(DESC, order.fields().get(0).direction());
     Assert.assertEquals(NULLS_FIRST, order.fields().get(0).nullOrder());
   }
+
+  @Test
+  public void invalidSortDirection() {
+    String jsonString =
+        "{\n"
+            + "  \"order-id\" : 10,\n"
+            + "  \"fields\" : [ {\n"
+            + "    \"transform\" : \"custom_transform\",\n"
+            + "    \"source-id\" : 2,\n"
+            + "    \"direction\" : \"invalid\",\n"
+            + "    \"null-order\" : \"nulls-first\"\n"
+            + "  } ]\n"
+            + "}";
+
+    org.assertj.core.api.Assertions.assertThatThrownBy(
+            () -> SortOrderParser.fromJson(table.schema(), jsonString))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Invalid sort direction: invalid");
+  }
 }
diff --git a/core/src/test/java/org/apache/iceberg/expressions/TestExpressionParser.java b/core/src/test/java/org/apache/iceberg/expressions/TestExpressionParser.java
index 72445786f5..a41597f88b 100644
--- a/core/src/test/java/org/apache/iceberg/expressions/TestExpressionParser.java
+++ b/core/src/test/java/org/apache/iceberg/expressions/TestExpressionParser.java
@@ -301,7 +301,7 @@ public class TestExpressionParser {
                         + "  }\n"
                         + "}"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("No enum constant org.apache.iceberg.expressions.Expression.Operation.ILLEGAL");
+        .hasMessage("Invalid operation type: illegal");
 
     Assertions.assertThatThrownBy(
             () ->
@@ -315,7 +315,7 @@ public class TestExpressionParser {
                         + "  }\n"
                         + "}"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("No enum constant org.apache.iceberg.expressions.Expression.Operation.ILLEGAL");
+        .hasMessage("Invalid operation type: ILLEGAL");
   }
 
   @Test
diff --git a/core/src/test/java/org/apache/iceberg/metrics/TestCounterResultParser.java b/core/src/test/java/org/apache/iceberg/metrics/TestCounterResultParser.java
index 8dfb6b353a..e3e705d033 100644
--- a/core/src/test/java/org/apache/iceberg/metrics/TestCounterResultParser.java
+++ b/core/src/test/java/org/apache/iceberg/metrics/TestCounterResultParser.java
@@ -60,7 +60,7 @@ public class TestCounterResultParser {
     Assertions.assertThatThrownBy(
             () -> CounterResultParser.fromJson("{\"unit\":\"unknown\",\"value\":23}"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("No enum constant org.apache.iceberg.metrics.MetricsContext.Unit.UNKNOWN");
+        .hasMessage("Invalid unit: unknown");
   }
 
   @Test
diff --git a/core/src/test/java/org/apache/iceberg/metrics/TestTimerResultParser.java b/core/src/test/java/org/apache/iceberg/metrics/TestTimerResultParser.java
index 30e20148a7..1e097c1a40 100644
--- a/core/src/test/java/org/apache/iceberg/metrics/TestTimerResultParser.java
+++ b/core/src/test/java/org/apache/iceberg/metrics/TestTimerResultParser.java
@@ -80,7 +80,7 @@ public class TestTimerResultParser {
                 TimerResultParser.fromJson(
                     "{\"count\":44,\"time-unit\":\"unknown\",\"total-duration\":24}"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage("No enum constant java.util.concurrent.TimeUnit.UNKNOWN");
+        .hasMessage("Invalid time unit: unknown");
   }
 
   @Test
diff --git a/core/src/test/java/org/apache/iceberg/rest/requests/TestReportMetricsRequestParser.java b/core/src/test/java/org/apache/iceberg/rest/requests/TestReportMetricsRequestParser.java
index f894b67513..4c947c7927 100644
--- a/core/src/test/java/org/apache/iceberg/rest/requests/TestReportMetricsRequestParser.java
+++ b/core/src/test/java/org/apache/iceberg/rest/requests/TestReportMetricsRequestParser.java
@@ -67,8 +67,7 @@ public class TestReportMetricsRequestParser {
     Assertions.assertThatThrownBy(
             () -> ReportMetricsRequestParser.fromJson("{\"report-type\":\"invalid\"}"))
         .isInstanceOf(IllegalArgumentException.class)
-        .hasMessage(
-            "No enum constant org.apache.iceberg.rest.requests.ReportMetricsRequest.ReportType.INVALID");
+        .hasMessage("Invalid report type: invalid");
 
     Assertions.assertThatThrownBy(
             () ->
diff --git a/flink/v1.13/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java b/flink/v1.13/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
index 79daac3750..0d3a3a794b 100644
--- a/flink/v1.13/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
+++ b/flink/v1.13/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
@@ -350,7 +350,7 @@ public class TestFlinkIcebergSink {
     AssertHelpers.assertThrows(
         "Should fail with invalid distribution mode.",
         IllegalArgumentException.class,
-        "No enum constant org.apache.iceberg.DistributionMode.UNRECOGNIZED",
+        "Invalid distribution mode: UNRECOGNIZED",
         () -> {
           builder.append();
 
diff --git a/flink/v1.14/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java b/flink/v1.14/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
index b7b9539721..0c3fe5a2a0 100644
--- a/flink/v1.14/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
+++ b/flink/v1.14/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
@@ -362,7 +362,7 @@ public class TestFlinkIcebergSink {
     AssertHelpers.assertThrows(
         "Should fail with invalid distribution mode.",
         IllegalArgumentException.class,
-        "No enum constant org.apache.iceberg.DistributionMode.UNRECOGNIZED",
+        "Invalid distribution mode: UNRECOGNIZED",
         () -> {
           builder.append();
 
diff --git a/flink/v1.15/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java b/flink/v1.15/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
index 6d29475991..e17fe5c526 100644
--- a/flink/v1.15/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
+++ b/flink/v1.15/flink/src/test/java/org/apache/iceberg/flink/sink/TestFlinkIcebergSink.java
@@ -361,7 +361,7 @@ public class TestFlinkIcebergSink {
     AssertHelpers.assertThrows(
         "Should fail with invalid distribution mode.",
         IllegalArgumentException.class,
-        "No enum constant org.apache.iceberg.DistributionMode.UNRECOGNIZED",
+        "Invalid distribution mode: UNRECOGNIZED",
         () -> {
           builder.append();
 
diff --git a/spark/v3.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java b/spark/v3.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
index 24cd831567..e21b302a3a 100644
--- a/spark/v3.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
+++ b/spark/v3.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
@@ -25,7 +25,6 @@ import static org.apache.iceberg.TableProperties.MERGE_ISOLATION_LEVEL_DEFAULT;
 import static org.apache.iceberg.TableProperties.UPDATE_ISOLATION_LEVEL;
 import static org.apache.iceberg.TableProperties.UPDATE_ISOLATION_LEVEL_DEFAULT;
 
-import java.util.Locale;
 import java.util.Map;
 import org.apache.iceberg.IsolationLevel;
 import org.apache.iceberg.Table;
@@ -70,7 +69,7 @@ class SparkMergeBuilder implements MergeBuilder {
     } else {
       throw new IllegalArgumentException("Unsupported operation: " + operation);
     }
-    return IsolationLevel.valueOf(isolationLevelAsString.toUpperCase(Locale.ROOT));
+    return IsolationLevel.fromName(isolationLevelAsString);
   }
 
   @Override
diff --git a/spark/v3.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java b/spark/v3.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
index 24cd831567..e21b302a3a 100644
--- a/spark/v3.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
+++ b/spark/v3.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkMergeBuilder.java
@@ -25,7 +25,6 @@ import static org.apache.iceberg.TableProperties.MERGE_ISOLATION_LEVEL_DEFAULT;
 import static org.apache.iceberg.TableProperties.UPDATE_ISOLATION_LEVEL;
 import static org.apache.iceberg.TableProperties.UPDATE_ISOLATION_LEVEL_DEFAULT;
 
-import java.util.Locale;
 import java.util.Map;
 import org.apache.iceberg.IsolationLevel;
 import org.apache.iceberg.Table;
@@ -70,7 +69,7 @@ class SparkMergeBuilder implements MergeBuilder {
     } else {
       throw new IllegalArgumentException("Unsupported operation: " + operation);
     }
-    return IsolationLevel.valueOf(isolationLevelAsString.toUpperCase(Locale.ROOT));
+    return IsolationLevel.fromName(isolationLevelAsString);
   }
 
   @Override