Skip to content

Commit

Permalink
Xml support for C#
Browse files Browse the repository at this point in the history
Signed-off-by: Clemens Vasters <clemens@vasters.com>
  • Loading branch information
clemensv committed Oct 17, 2024
1 parent 82fddde commit 7d55af3
Show file tree
Hide file tree
Showing 12 changed files with 331 additions and 130 deletions.
13 changes: 11 additions & 2 deletions avrotize/avrotize.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,18 @@ def create_subparsers(subparsers, commands):
if arg['type'] == 'bool':
kwargs['action'] = 'store_true'
del kwargs['type']
carg = cmd_parser.add_argument(arg['name'], **kwargs)
argname = arg['name']
if '_' in argname:
argname2 = argname.replace('_', '-')
carg = cmd_parser.add_argument(argname, argname2, **kwargs)
else:
carg = cmd_parser.add_argument(arg['name'], **kwargs)
else:
carg = cmd_parser.add_argument(arg['name'], **kwargs)
if '_' in arg['name']:
argname2 = arg['name'].replace('_', '-')
carg = cmd_parser.add_argument(arg['name'], argname2, **kwargs)
else:
carg = cmd_parser.add_argument(arg['name'], **kwargs)
carg.required = arg.get('required', True)

def dynamic_import(module, func):
Expand Down
219 changes: 160 additions & 59 deletions avrotize/avrotocsharp.py

Large diffs are not rendered by default.

14 changes: 12 additions & 2 deletions avrotize/avrotocsharp/class_test.cs.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,24 @@ public class {{ test_class_name }}
{%- if avro_annotation %}
/// <summary> Testing Avro serializer </summary>
[Test]
public void Test_ToByteArray_FromData()
public void Test_ToByteArray_FromData_Avro()
{
var mediaType = "application/vnd.apache.avro+avro";
var bytes = _instance.ToByteArray(mediaType);
var newInstance = {{ class_base_name }}.FromData(bytes, mediaType);
_instance.Should().BeEquivalentTo(newInstance);
}

{%- endif %}
{%- if system_xml_annotation %}
/// <summary> Testing XML serializer </summary>
[Test]
public void Test_ToByteArray_FromData_Xml()
{
var mediaType = "application/xml";
var bytes = _instance.ToByteArray(mediaType);
var newInstance = {{ class_base_name }}.FromData(bytes, mediaType);
_instance.Should().BeEquivalentTo(newInstance);
}
{%- endif %}
}
{% endfilter %}
Expand Down
64 changes: 57 additions & 7 deletions avrotize/avrotocsharp/dataclass_core.jinja
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
/// <summary>
/// Creates an object from the data
/// </summary>
Expand All @@ -11,7 +11,7 @@
if ( data is {{ class_name }}) return ({{ class_name }})data;
if ( contentTypeString == null ) contentTypeString = System.Net.Mime.MediaTypeNames.Application.Octet;
var contentType = new System.Net.Mime.ContentType(contentTypeString);
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
if ( contentType.MediaType.EndsWith("+gzip"))
{
var stream = data switch
Expand Down Expand Up @@ -87,10 +87,37 @@
return ((System.BinaryData)data).ToObjectFromJson<{{ class_name }}>();
}
}
{%- endif %}
{%- if system_xml_annotation %}
if ( contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Text.Xml) || contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Application.Xml) || contentType.MediaType.EndsWith("+xml"))
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof({{ class_name }}));
if (data is string)
{
using (var reader = new System.IO.StringReader((string)data))
{
return ({{ class_name }}?)serializer.Deserialize(reader);
}
}
else if (data is System.IO.Stream)
{
return ({{ class_name }}?)serializer.Deserialize((System.IO.Stream)data);
}
else if (data is System.BinaryData)
{
var memoryStream = new System.IO.MemoryStream(((System.BinaryData)data).ToArray());
return ({{ class_name }}?)serializer.Deserialize(memoryStream);
}
else if (data is byte[])
{
var memoryStream = new System.IO.MemoryStream((byte[])data);
return ({{ class_name }}?)serializer.Deserialize(memoryStream);
}
}
{%- endif %}
throw new System.NotSupportedException($"Unsupported media type {contentType.MediaType}");
}
{%-endif %}
{%- endif %}

{%- if avro_annotation %}
private class SpecificDatumWriter : global::Avro.Specific.SpecificDatumWriter<{{ class_name }}>
Expand All @@ -101,15 +128,23 @@

protected override WriteItem ResolveEnum(global::Avro.EnumSchema es)
{
return base.ResolveEnum(global::Avro.EnumSchema.Create(es.Name, es.Symbols, GetType().Assembly.GetName().Name+"."+es.Namespace, null, null, es.Documentation, es.Default));
var enumType = GetType().Assembly.GetType(GetType().Assembly.GetName().Name+"."+es.Namespace + "." + es.Name, false, true);
if (enumType != null)
{
return base.ResolveEnum(global::Avro.EnumSchema.Create(enumType.Name, es.Symbols, enumType.Namespace, null, null, es.Documentation, es.Default));
}
else
{
return base.ResolveEnum(es);
}
}
}
{%- endif %}

{%- if avro_annotation %}
{%- endif%}

{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
/// <summary>
/// Converts the object to a byte array
/// </summary>
Expand Down Expand Up @@ -151,7 +186,22 @@
result = System.Text.Encoding.GetEncoding(contentType.CharSet??"utf-8").GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(this));
}
{%- endif %}
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation %}
{%- if system_xml_annotation %}
if (contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Text.Xml) || contentType.MediaType.StartsWith(System.Net.Mime.MediaTypeNames.Application.Xml) || contentType.MediaType.EndsWith("+xml"))
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof({{ class_name }}));
using (var stream = new System.IO.MemoryStream())
{
using (var writer = new System.IO.StreamWriter(stream))
{
serializer.Serialize(writer, this);
writer.Flush();
result = stream.ToArray();
}
}
}
{%- endif %}
{%- if avro_annotation or system_text_json_annotation or newtonsoft_json_annotation or system_xml_annotation %}
if (result != null && contentType.MediaType.EndsWith("+gzip"))
{
var stream = new System.IO.MemoryStream();
Expand All @@ -166,7 +216,7 @@
}
{%- endif %}

{%- if system_text_json_annotation %}
{%- if system_text_json_annotation or newtonsoft_json_annotation %}
/// <summary>
/// Checks if the JSON element matches the schema
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions avrotize/avrotocsharp/project.csproj.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
{%- if avro_annotation %}
<PackageReference Include="Apache.Avro" Version="1.11.3" />
{%- endif %}
{%- if newtonsoft_json_annotation %}
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
{%- endif %}
{%- if system_text_json_annotation %}
<PackageReference Include="System.Text.Json" Version="8.0.5" />
{%- endif %}
<PackageReference Include="System.Memory.Data" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions avrotize/avrotots/class_core.ts.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ export class {{ class_name }} {
throw new Error(`Unsupported media type: ${contentTypeString}`);
}


{%- if typed_json_annotation %}
public static isJsonMatch(element: any): boolean {
{%- if fields|length == 0 %}
return true;
Expand All @@ -120,4 +122,5 @@ export class {{ class_name }} {
{%- endif %}
}
{%- endif %}
{%- endif %}
}
2 changes: 2 additions & 0 deletions avrotize/avrotots/enum_core.ts.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export class {{ enum_name }}Utils {
}
}

{%- if typed_json_annotation %}
static isJsonMatch(value: string): boolean {
return Object.values({{ enum_name }}).includes(value as {{ enum_name }});
}
{%- endif %}
}
8 changes: 8 additions & 0 deletions avrotize/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@
"avro_annotation": "args.avro_annotation",
"system_text_json_annotation": "args.system_text_json_annotation",
"newtonsoft_json_annotation": "args.newtonsoft_json_annotation",
"system_xml_annotation": "args.system_xml_annotation",
"pascal_properties": "args.pascal_properties",
"base_namespace": "args.namespace"
}
Expand Down Expand Up @@ -944,6 +945,13 @@
"default": false,
"required": false
},
{
"name": "--system-xml-annotation",
"type": "bool",
"help": "Use System.Xml annotations",
"default": false,
"required": false
},
{
"name": "--newtonsoft-json-annotation",
"type": "bool",
Expand Down
3 changes: 3 additions & 0 deletions avrotize/xsdtoavro.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self) -> None:
""" Initialize the class. """
self.simple_type_map: Dict[str, str | dict] = {}
self.avro_namespace = ''
self.xml_namespace = ''

def xsd_targetnamespace_to_avro_namespace(self, targetnamespace: str) -> str:
"""Convert a XSD namespace to Avro Namespace."""
Expand Down Expand Up @@ -303,6 +304,7 @@ def process_top_level_element(self, element: ET.Element, namespaces: dict):
'type': 'record',
'name': 'Root',
'namespace': self.avro_namespace,
'xmlns': self.xml_namespace,
'fields': []
}
annotation = element.find(f'{{{XSD_NAMESPACE}}}annotation', namespaces)
Expand Down Expand Up @@ -349,6 +351,7 @@ def xsd_to_avro(self, xsd_path: str, code_namespace: str | None = None):
target_namespace = root.get('targetNamespace')
if target_namespace is None:
raise ValueError('targetNamespace not found')
self.xml_namespace = target_namespace
if not code_namespace:
self.avro_namespace = self.xsd_targetnamespace_to_avro_namespace(target_namespace)
else:
Expand Down
Loading

0 comments on commit 7d55af3

Please sign in to comment.