KalleOlaviNiemitalo commented on code in PR #3247:
URL: https://github.com/apache/avro/pull/3247#discussion_r1983712300
##########
lang/csharp/src/apache/main/CodeGen/CodeGen.cs:
##########
@@ -1266,5 +1273,102 @@ private static string
ReplaceMappedNamespacesInSchema(string input, IEnumerable<
return
$@"""namespace""{m.Groups[1].Value}:{m.Groups[2].Value}""{ns}""";
});
}
+ /// <summary>
+ /// Replace namespaces in a parsed JSON schema object for all "type"
fields.
+ /// </summary>
+ /// <param name="schemaJson">The JSON schema as a string.</param>
+ /// <param name="namespaceMapping">The mapping of old namespaces to new
namespaces.</param>
+ /// <returns>The updated JSON schema as a string.</returns>
+ private static string ReplaceMappedNamespacesInSchemaTypes(string
schemaJson, IEnumerable<KeyValuePair<string, string>> namespaceMapping)
+ {
+ if (string.IsNullOrWhiteSpace(schemaJson) || namespaceMapping == null)
+ {
+ return schemaJson;
+ }
+
+ var schemaToken = JToken.Parse(schemaJson);
+
+ UpdateNamespacesInJToken(schemaToken, namespaceMapping);
+
+ return schemaToken.ToString(Formatting.Indented);
}
+
+ /// <summary>
+ /// Recursively navigates and updates "type" fields in a JToken.
+ /// </summary>
+ /// <param name="token">The current JToken to process.</param>
+ /// <param name="namespaceMapping">The mapping of old namespaces to new
namespaces.</param>
+ private static void UpdateNamespacesInJToken(JToken token,
IEnumerable<KeyValuePair<string, string>> namespaceMapping)
+ {
+ if (token is JObject obj)
+ {
+ if (obj.ContainsKey("type"))
+ {
+ var typeToken = obj["type"];
+ if (typeToken is JValue) // Single type
+ {
+ string type = typeToken.ToString();
+ obj["type"] = ReplaceNamespace(type, namespaceMapping);
+ }
+ else if (typeToken is JArray typeArray) // Array of types
+ {
+ for (int i = 0; i < typeArray.Count; i++)
+ {
+ var arrayItem = typeArray[i];
+ if (arrayItem is JValue) // Simple type
+ {
+ string type = arrayItem.ToString();
+ typeArray[i] = ReplaceNamespace(type,
namespaceMapping);
+ }
+ else if (arrayItem is JObject nestedObj) // Nested
object
+ {
+ UpdateNamespacesInJToken(nestedObj,
namespaceMapping);
+ }
+ }
+ }
+ else if (typeToken is JObject nestedTypeObj) // Complex type
+ {
+ UpdateNamespacesInJToken(nestedTypeObj, namespaceMapping);
+ }
+ }
+
+ // Recurse into all properties of the object
+ foreach (var property in obj.Properties())
+ {
+ UpdateNamespacesInJToken(property.Value, namespaceMapping);
+ }
Review Comment:
This will replace namespace-looking strings in "type" properties even within
the "default" property of a field. Those should not be modified because they
affect the meaning of the schema, rather than only the local code generation.
##########
lang/csharp/src/apache/main/CodeGen/CodeGen.cs:
##########
@@ -1266,5 +1273,102 @@ private static string
ReplaceMappedNamespacesInSchema(string input, IEnumerable<
return
$@"""namespace""{m.Groups[1].Value}:{m.Groups[2].Value}""{ns}""";
});
}
+ /// <summary>
+ /// Replace namespaces in a parsed JSON schema object for all "type"
fields.
+ /// </summary>
+ /// <param name="schemaJson">The JSON schema as a string.</param>
+ /// <param name="namespaceMapping">The mapping of old namespaces to new
namespaces.</param>
+ /// <returns>The updated JSON schema as a string.</returns>
+ private static string ReplaceMappedNamespacesInSchemaTypes(string
schemaJson, IEnumerable<KeyValuePair<string, string>> namespaceMapping)
+ {
+ if (string.IsNullOrWhiteSpace(schemaJson) || namespaceMapping == null)
+ {
+ return schemaJson;
+ }
+
+ var schemaToken = JToken.Parse(schemaJson);
+
+ UpdateNamespacesInJToken(schemaToken, namespaceMapping);
+
+ return schemaToken.ToString(Formatting.Indented);
}
+
+ /// <summary>
+ /// Recursively navigates and updates "type" fields in a JToken.
+ /// </summary>
+ /// <param name="token">The current JToken to process.</param>
+ /// <param name="namespaceMapping">The mapping of old namespaces to new
namespaces.</param>
+ private static void UpdateNamespacesInJToken(JToken token,
IEnumerable<KeyValuePair<string, string>> namespaceMapping)
+ {
+ if (token is JObject obj)
+ {
+ if (obj.ContainsKey("type"))
+ {
+ var typeToken = obj["type"];
+ if (typeToken is JValue) // Single type
+ {
+ string type = typeToken.ToString();
+ obj["type"] = ReplaceNamespace(type, namespaceMapping);
+ }
+ else if (typeToken is JArray typeArray) // Array of types
+ {
+ for (int i = 0; i < typeArray.Count; i++)
+ {
+ var arrayItem = typeArray[i];
+ if (arrayItem is JValue) // Simple type
+ {
+ string type = arrayItem.ToString();
+ typeArray[i] = ReplaceNamespace(type,
namespaceMapping);
+ }
+ else if (arrayItem is JObject nestedObj) // Nested
object
+ {
+ UpdateNamespacesInJToken(nestedObj,
namespaceMapping);
+ }
+ }
+ }
+ else if (typeToken is JObject nestedTypeObj) // Complex type
+ {
+ UpdateNamespacesInJToken(nestedTypeObj, namespaceMapping);
+ }
+ }
+
+ // Recurse into all properties of the object
+ foreach (var property in obj.Properties())
+ {
+ UpdateNamespacesInJToken(property.Value, namespaceMapping);
+ }
+ }
+ else if (token is JArray array)
+ {
+ // Recurse into all elements of the array
+ foreach (var element in array)
+ {
+ UpdateNamespacesInJToken(element, namespaceMapping);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Replace a namespace in a string based on the provided mapping.
+ /// </summary>
+ /// <param name="originalNamespace">The original namespace string.</param>
+ /// <param name="namespaceMapping">The mapping of old namespaces to new
namespaces.</param>
+ /// <returns>The updated namespace string.</returns>
+ private static string ReplaceNamespace(string originalNamespace,
IEnumerable<KeyValuePair<string, string>> namespaceMapping)
+ {
+ foreach (var mapping in namespaceMapping)
+ {
+ if (originalNamespace == mapping.Key)
+ {
+ return mapping.Value;
+ }
+ else if (originalNamespace.StartsWith($"{mapping.Key}."))
Review Comment:
This calls String.StartsWith(String), which uses
StringComparison.CurrentCulture; but should instead use
StringComparison.Ordinal.
With StringComparison.CurrentCulture, it is possible that
`originalNamespace.StartsWith($"{mapping.Key}.")` returns true but
`originalNamespace.Length < $"{mapping.Key}.".Length`, which would then cause
the subsequent Substring call to throw. This would happen if `mapping.Key`
includes characters that are ignored in linguistic comparisons.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]