[ https://issues.apache.org/jira/browse/AVRO-3001?focusedWorklogId=802496&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-802496 ]
ASF GitHub Bot logged work on AVRO-3001: ---------------------------------------- Author: ASF GitHub Bot Created on: 22/Aug/22 14:50 Start Date: 22/Aug/22 14:50 Worklog Time Spent: 10m Work Description: rayokota commented on code in PR #1833: URL: https://github.com/apache/avro/pull/1833#discussion_r951537746 ########## lang/csharp/src/apache/main/IO/JsonEncoder.cs: ########## @@ -0,0 +1,360 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Avro.IO.Parsing; +using System.Collections; +using System.IO; +using System.Text; +using Newtonsoft.Json; + +namespace Avro.IO +{ + /// <summary> + /// An <seealso cref="Encoder"/> for Avro's JSON data encoding. + /// + /// JsonEncoder buffers output, and data may not appear on the output until + /// <seealso cref="Encoder.Flush()"/> is called. + /// + /// JsonEncoder is not thread-safe. + /// </summary> + public class JsonEncoder : ParsingEncoder, Parser.ActionHandler + { + private readonly Parser parser; + private JsonWriter writer; + private bool includeNamespace = true; + + // Has anything been written into the collections? + private readonly BitArray isEmpty = new BitArray(64); + + /// <summary> + /// Initializes a new instance of the <see cref="JsonEncoder"/> class. + /// </summary> + public JsonEncoder(Schema sc, Stream stream) : this(sc, getJsonWriter(stream, false)) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="JsonEncoder"/> class. + /// </summary> + public JsonEncoder(Schema sc, Stream stream, bool pretty) : this(sc, getJsonWriter(stream, pretty)) + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="JsonEncoder"/> class. + /// </summary> + public JsonEncoder(Schema sc, JsonWriter writer) + { + Configure(writer); + this.parser = new Parser((new JsonGrammarGenerator()).Generate(sc), this); + } + + /// <inheritdoc /> + public override void Flush() + { + parser.ProcessImplicitActions(); + if (writer != null) + { + writer.Flush(); + } + } + + // by default, one object per line. + // with pretty option use default pretty printer with root line separator. + private static JsonWriter getJsonWriter(Stream stream, bool pretty) + { + JsonWriter writer = new JsonTextWriter(new StreamWriter(stream)); + if (pretty) + { + writer.Formatting = Formatting.Indented; + } + + return writer; + } + + /// <summary> + /// Whether to include the namespace. + /// </summary> + public virtual bool IncludeNamespace + { + get { return includeNamespace; } + set { this.includeNamespace = value; } + } + + + /// <summary> + /// Reconfigures this JsonEncoder to use the output stream provided. + /// <p/> + /// Otherwise, this JsonEncoder will flush its current output and then + /// reconfigure its output to use a default UTF8 JsonWriter that writes to the + /// provided OutputStream. + /// </summary> + /// <param name="stream"> The OutputStream to direct output to. Cannot be null. </param> + /// <returns> this JsonEncoder </returns> + public JsonEncoder Configure(Stream stream) + { + this.Configure(getJsonWriter(stream, false)); + return this; + } + + /// <summary> + /// Reconfigures this JsonEncoder to output to the JsonWriter provided. + /// <p/> + /// Otherwise, this JsonEncoder will flush its current output and then + /// reconfigure its output to use the provided JsonWriter. + /// </summary> + /// <param name="jsonWriter"> The JsonWriter to direct output to. Cannot be null. </param> + /// <returns> this JsonEncoder </returns> + public JsonEncoder Configure(JsonWriter jsonWriter) + { + if (null != parser) + { + Flush(); + } + + this.writer = jsonWriter; + return this; + } + + /// <inheritdoc /> + public override void WriteNull() + { + parser.Advance(Symbol.Null); + writer.WriteNull(); + } + + /// <inheritdoc /> + public override void WriteBoolean(bool b) + { + parser.Advance(Symbol.Boolean); + writer.WriteValue(b); + } + + /// <inheritdoc /> + public override void WriteInt(int n) + { + parser.Advance(Symbol.Int); + writer.WriteValue(n); + } + + /// <inheritdoc /> + public override void WriteLong(long n) + { + parser.Advance(Symbol.Long); + writer.WriteValue(n); + } + + /// <inheritdoc /> + public override void WriteFloat(float f) + { + parser.Advance(Symbol.Float); + writer.WriteValue(f); + } + + /// <inheritdoc /> + public override void WriteDouble(double d) + { + parser.Advance(Symbol.Double); + writer.WriteValue(d); + } + + /// <inheritdoc /> + public override void WriteString(string str) + { + parser.Advance(Symbol.String); + if (parser.TopSymbol() == Symbol.MapKeyMarker) + { + parser.Advance(Symbol.MapKeyMarker); + writer.WritePropertyName(str); + } + else + { + writer.WriteValue(str); + } + } + + /// <inheritdoc /> + public override void WriteBytes(byte[] bytes) + { + WriteBytes(bytes, 0, bytes.Length); + } + + /// <inheritdoc /> + public override void WriteBytes(byte[] bytes, int start, int len) + { + parser.Advance(Symbol.Bytes); + writeByteArray(bytes, start, len); + } + + private void writeByteArray(byte[] bytes, int start, int len) + { + Encoding iso = Encoding.GetEncoding("ISO-8859-1"); + writer.WriteValue(iso.GetString(bytes, start, len)); + } + + /// <inheritdoc /> + public override void WriteFixed(byte[] bytes) + { + WriteFixed(bytes, 0, bytes.Length); + } + + /// <inheritdoc /> + public override void WriteFixed(byte[] bytes, int start, int len) + { + parser.Advance(Symbol.Fixed); + Symbol.IntCheckAction top = (Symbol.IntCheckAction)parser.PopSymbol(); + if (len != top.Size) + { + throw new AvroTypeException("Incorrect length for fixed binary: expected " + top.Size + + " but received " + len + " bytes."); + } + + writeByteArray(bytes, start, len); + } + + /// <inheritdoc /> + public override void WriteEnum(int e) + { + parser.Advance(Symbol.Enum); + Symbol.EnumLabelsAction top = (Symbol.EnumLabelsAction)parser.PopSymbol(); + if (e < 0 || e >= top.Size) + { + throw new AvroTypeException("Enumeration out of range: max is " + top.Size + " but received " + e); + } + + writer.WriteValue(top.GetLabel(e)); + } + + /// <inheritdoc /> + public override void WriteArrayStart() + { + parser.Advance(Symbol.ArrayStart); + writer.WriteStartArray(); + Push(); + if (Depth() >= isEmpty.Length) + { + isEmpty.Length += isEmpty.Length; + } + + isEmpty.Set(Depth(), true); + } + + /// <inheritdoc /> + public override void WriteArrayEnd() + { + if (!isEmpty.Get(Pos)) + { + parser.Advance(Symbol.ItemEnd); + } + + Pop(); + parser.Advance(Symbol.ArrayEnd); + writer.WriteEndArray(); + } + + /// <inheritdoc /> + public override void WriteMapStart() + { + Push(); + if (Depth() >= isEmpty.Length) + { + isEmpty.Length += isEmpty.Length; + } + + isEmpty.Set(Depth(), true); + + parser.Advance(Symbol.MapStart); + writer.WriteStartObject(); + } + + /// <inheritdoc /> + public override void WriteMapEnd() + { + if (!isEmpty.Get(Pos)) + { + parser.Advance(Symbol.ItemEnd); + } + + Pop(); + + parser.Advance(Symbol.MapEnd); + writer.WriteEndObject(); + } + + /// <summary> + /// Start an array item. + /// </summary> + public new void StartItem() Review Comment: Ah, thanks for the detailed explained. I fixed this. Issue Time Tracking ------------------- Worklog Id: (was: 802496) Time Spent: 2.5h (was: 2h 20m) > JsonEncode Decode support for C# > -------------------------------- > > Key: AVRO-3001 > URL: https://issues.apache.org/jira/browse/AVRO-3001 > Project: Apache Avro > Issue Type: Improvement > Components: csharp > Affects Versions: 1.10.0, 1.11.0 > Reporter: Krishnan Unni > Assignee: Robert Yokota > Priority: Major > Labels: pull-request-available > Time Spent: 2.5h > Remaining Estimate: 0h > > The C# library for avro currently supports only the Binary encoding and also > with compile time types (Generic support only). As part of a project I am > doing I need to validate the avro schema against the incoming json data on > the fly without a predefined type (generated class). So basically comparing > an avro schema (string/json representation) against a raw json string. It is > possible with the Java library since it supports both non generic types and > streams as well as json encoding. With C# currently this is not possible. Is > there a plan to extend the C# library to provide these features? If yes, is > there a timeline? If not is there any alternative to achieve this? -- This message was sent by Atlassian Jira (v8.20.10#820010)