diff --git a/src/iceberg/json_internal.cc b/src/iceberg/json_internal.cc index e19f5b4e4..2ffc543fd 100644 --- a/src/iceberg/json_internal.cc +++ b/src/iceberg/json_internal.cc @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -37,7 +36,6 @@ #include "iceberg/snapshot.h" #include "iceberg/sort_order.h" #include "iceberg/statistics_file.h" -#include "iceberg/table.h" #include "iceberg/table_metadata.h" #include "iceberg/transform.h" #include "iceberg/type.h" @@ -173,12 +171,18 @@ void SetOptionalField(nlohmann::json& json, std::string_view key, } } +std::string SafeDumpJson(const nlohmann::json& json) { + return json.dump(/*indent=*/-1, /*indent_char=*/' ', /*ensure_ascii=*/false, + nlohmann::detail::error_handler_t::ignore); +} + template Result GetJsonValueImpl(const nlohmann::json& json, std::string_view key) { try { return json.at(key).get(); } catch (const std::exception& ex) { - return JsonParseError("Failed to parse key '{}' in {}", key, json.dump()); + return JsonParseError("Failed to parse '{}' from {}: {}", key, SafeDumpJson(json), + ex.what()); } } @@ -194,7 +198,7 @@ Result> GetJsonValueOptional(const nlohmann::json& json, template Result GetJsonValue(const nlohmann::json& json, std::string_view key) { if (!json.contains(key)) { - return JsonParseError("Missing '{}' in {}", key, json.dump()); + return JsonParseError("Missing '{}' in {}", key, SafeDumpJson(json)); } return GetJsonValueImpl(json, key); } @@ -245,7 +249,7 @@ Result> FromJsonList( ICEBERG_ASSIGN_OR_RAISE(auto list_json, GetJsonValue(json, key)); if (!list_json.is_array()) { return JsonParseError("Cannot parse '{}' from non-array: {}", key, - list_json.dump()); + SafeDumpJson(list_json)); } for (const auto& entry_json : list_json) { ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(entry_json)); @@ -270,7 +274,7 @@ Result>> FromJsonList( ICEBERG_ASSIGN_OR_RAISE(auto list_json, GetJsonValue(json, key)); if (!list_json.is_array()) { return JsonParseError("Cannot parse '{}' from non-array: {}", key, - list_json.dump()); + SafeDumpJson(list_json)); } for (const auto& entry_json : list_json) { ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(entry_json)); @@ -319,7 +323,7 @@ Result> FromJsonMap( try { return json.get(); } catch (const std::exception& ex) { - return JsonParseError("Cannot parse {} to a string value: {}", json.dump(), + return JsonParseError("Cannot parse {} to a string value: {}", SafeDumpJson(json), ex.what()); } }) { @@ -328,7 +332,7 @@ Result> FromJsonMap( ICEBERG_ASSIGN_OR_RAISE(auto map_json, GetJsonValue(json, key)); if (!map_json.is_object()) { return JsonParseError("Cannot parse '{}' from non-object: {}", key, - map_json.dump()); + SafeDumpJson(map_json)); } for (const auto& [key, value] : map_json.items()) { ICEBERG_ASSIGN_OR_RAISE(auto entry, from_json(value)); @@ -633,7 +637,7 @@ Result> SchemaFromJson(const nlohmann::json& json) { ICEBERG_ASSIGN_OR_RAISE(auto type, TypeFromJson(json)); if (type->type_id() != TypeId::kStruct) [[unlikely]] { - return JsonParseError("Schema must be a struct type, but got {}", json.dump()); + return JsonParseError("Schema must be a struct type, but got {}", SafeDumpJson(json)); } auto& struct_type = static_cast(*type); @@ -741,11 +745,12 @@ Result> SnapshotFromJson(const nlohmann::json& json) { return JsonParseError("Invalid snapshot summary field: {}", key); } if (!value.is_string()) { - return JsonParseError("Invalid snapshot summary field value: {}", value.dump()); + return JsonParseError("Invalid snapshot summary field value: {}", + SafeDumpJson(value)); } if (key == SnapshotSummaryFields::kOperation && !kValidDataOperation.contains(value.get())) { - return JsonParseError("Invalid snapshot operation: {}", value.dump()); + return JsonParseError("Invalid snapshot operation: {}", SafeDumpJson(value)); } summary[key] = value.get(); } @@ -975,7 +980,7 @@ Result> ParseSchemas( GetJsonValue(json, kSchemas)); if (!schema_array.is_array()) { return JsonParseError("Cannot parse schemas from non-array: {}", - schema_array.dump()); + SafeDumpJson(schema_array)); } ICEBERG_ASSIGN_OR_RAISE(current_schema_id, @@ -990,7 +995,7 @@ Result> ParseSchemas( } if (!current_schema) { return JsonParseError("Cannot find schema with {}={} from {}", kCurrentSchemaId, - current_schema_id.value(), schema_array.dump()); + current_schema_id.value(), SafeDumpJson(schema_array)); } } else { if (format_version != 1) { @@ -1021,7 +1026,7 @@ Status ParsePartitionSpecs(const nlohmann::json& json, int8_t format_version, GetJsonValue(json, kPartitionSpecs)); if (!spec_array.is_array()) { return JsonParseError("Cannot parse partition specs from non-array: {}", - spec_array.dump()); + SafeDumpJson(spec_array)); } ICEBERG_ASSIGN_OR_RAISE(default_spec_id, GetJsonValue(json, kDefaultSpecId)); @@ -1040,7 +1045,7 @@ Status ParsePartitionSpecs(const nlohmann::json& json, int8_t format_version, GetJsonValue(json, kPartitionSpec)); if (!partition_spec_json.is_array()) { return JsonParseError("Cannot parse v1 partition spec from non-array: {}", - partition_spec_json.dump()); + SafeDumpJson(partition_spec_json)); } int32_t next_partition_field_id = PartitionSpec::kLegacyPartitionDataIdStart; @@ -1098,7 +1103,8 @@ Status ParseSortOrders(const nlohmann::json& json, int8_t format_version, Result> TableMetadataFromJson(const nlohmann::json& json) { if (!json.is_object()) { - return JsonParseError("Cannot parse metadata from a non-object: {}", json.dump()); + return JsonParseError("Cannot parse metadata from a non-object: {}", + SafeDumpJson(json)); } auto table_metadata = std::make_unique(); @@ -1210,11 +1216,12 @@ Result> TableMetadataFromJson(const nlohmann::jso } Result FromJsonString(const std::string& json_string) { - try { - return nlohmann::json::parse(json_string); - } catch (const std::exception& e) { - return JsonParseError("Failed to parse JSON string: {}", e.what()); + auto json = + nlohmann::json::parse(json_string, /*cb=*/nullptr, /*allow_exceptions=*/false); + if (json.is_discarded()) [[unlikely]] { + return JsonParseError("Failed to parse JSON string: {}", json_string); } + return json; } Result ToJsonString(const nlohmann::json& json) {