internal void OnPocoInfoAvailable(PocoJsonInfo p) { PocoJsonInfo = p; if (!p.IsECMAStandardCompliant) { ECMAStandardHandlers = Array.Empty <JsonCodeGenHandler>(); } }
bool ExtendPocoClass(IActivityMonitor monitor, IPocoRootInfo pocoInfo, JsonSerializationCodeGen jsonCodeGen, ITypeScope pocoClass) { bool success = true; // Each Poco class is a IWriter and has a constructor that accepts a Utf8JsonReader. pocoClass.Definition.BaseTypes.Add(new ExtendedTypeName("CK.Core.PocoJsonSerializer.IWriter")); // Defines ToString() to return the Json representation only if it is not already defined. var toString = FunctionDefinition.Parse("public override string ToString()"); if (pocoClass.FindFunction(toString.Key, false) == null) { pocoClass .CreateFunction(toString) .GeneratedByComment().NewLine() .Append("var m = new System.Buffers.ArrayBufferWriter<byte>();").NewLine() .Append("using( var w = new System.Text.Json.Utf8JsonWriter( m ) )").NewLine() .OpenBlock() .Append("Write( w, false, null );").NewLine() .Append("w.Flush();").NewLine() .CloseBlock() .Append("return Encoding.UTF8.GetString( m.WrittenMemory.Span );"); } // The Write method: // - The writeHeader part may contain the ECMAScriptStandard non compliant exception (if it appears that a UnionType is not compliant). // - The write part will be filled with the properties (name and writer code). pocoClass.Append("public void Write( System.Text.Json.Utf8JsonWriter w, bool withType, PocoJsonSerializerOptions options )") .OpenBlock() .GeneratedByComment().NewLine() .CreatePart(out var writeHeader) .Append("bool usePascalCase = options != null && options.ForJsonSerializer.PropertyNamingPolicy != System.Text.Json.JsonNamingPolicy.CamelCase;").NewLine() .Append("if( withType ) { w.WriteStartArray(); w.WriteStringValue( ").AppendSourceString(pocoInfo.Name).Append("); }").NewLine() .Append("w.WriteStartObject();") .CreatePart(out var write) .Append("w.WriteEndObject();").NewLine() .Append("if( withType ) w.WriteEndArray();").NewLine() .CloseBlock(); // The constructor calls the private Read method. pocoClass.Append("public ").Append(pocoClass.Name).Append("( ref System.Text.Json.Utf8JsonReader r, PocoJsonSerializerOptions options ) : this()") .OpenBlock() .Append("Read( ref r, options );") .CloseBlock(); // Poco has a Read method but it is not (currently) exposed. // This returns two parts: a header (to inject the ECMAScriptStandard non compliant // exception if it appears that a UnionType is not compliant) and the switch-case part on the // property names with their reader code. var(readHeader, read) = GenerateReadBody(pocoInfo, pocoClass); bool isECMAScriptStandardCompliant = true; var jsonProperties = new PocoJsonPropertyInfo[pocoInfo.PropertyList.Count]; foreach (var p in pocoInfo.PropertyList) { var mainHandler = jsonCodeGen.GetHandler(p.PropertyNullableTypeTree); if (mainHandler == null) { success = false; continue; } PocoJsonPropertyInfo?pJ; if (p.PropertyUnionTypes.Any()) { pJ = HandleUnionType(p, monitor, jsonCodeGen, write, read, ref isECMAScriptStandardCompliant, mainHandler); if (pJ == null) { success = false; break; } } else { var handlers = new[] { mainHandler }; pJ = new PocoJsonPropertyInfo(p, handlers, mainHandler.HasECMAScriptStandardJsonName && isECMAScriptStandardCompliant ? handlers : null); // Actual Read/Write generation cannot be done here (it must be postponed). // This loop registers/allows the poco property types (the call to GetHandler triggers // the type registration) but writing them requires to know whether those types are final or not . // We store (using closure) the property, the write and read parts and the handler(s) // (to avoid another lookup) and wait for the FinalizeJsonSupport to be called. _finalReadWrite.Add(() => { var fieldName = "_v" + p.Index; write.Append("w.WritePropertyName( usePascalCase ? ") .AppendSourceString(p.PropertyName) .Append(" : ") .AppendSourceString(System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(p.PropertyName)) .Append(" );").NewLine(); mainHandler.GenerateWrite(write, fieldName); write.NewLine(); var camel = System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(p.PropertyName); if (camel != p.PropertyName) { read.Append("case ").AppendSourceString(camel).Append(": "); } read.Append("case ").AppendSourceString(p.PropertyName).Append(": ") .OpenBlock(); mainHandler.GenerateRead(read, fieldName, assignOnly: !p.IsReadOnly); read.Append("break; ") .CloseBlock(); }); } p.AddAnnotation(pJ); jsonProperties[p.Index] = pJ; } if (success) { if (!isECMAScriptStandardCompliant) { writeHeader.And(readHeader).Append("if( options != null && options.Mode == PocoJsonSerializerMode.ECMAScriptStandard ) throw new NotSupportedException( \"Poco '") .Append(pocoInfo.Name) .Append("' is not compliant with the ECMAScripStandard mode.\" );").NewLine(); } var info = new PocoJsonInfo(pocoInfo, isECMAScriptStandardCompliant, jsonProperties); pocoInfo.AddAnnotation(info); } return(success); }