vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
454 stars 72 forks source link

CodeGen Tool generates JsonNode not the object itself #228

Closed windowslucker1121 closed 2 months ago

windowslucker1121 commented 3 months ago

Hey there, thanks to your help last time here -> https://github.com/vpenades/SharpGLTF/issues/225 i was able to generate code and use my custom extension.

Now that i was able to successfully compile my "very basic" test schema i want to extend it to its fully potentional but the last 3 days i am really out of luck and now seeking here help again. :-/

I have the problem, that with the following schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "glTF Axis Definitions",
  "type": "object",
  "description": "Axis Definitions for glTF.",
  "allOf": [
    {
      "$ref": "glTFProperty.schema.json"
    }
  ],
  "properties": {
    "LinearAxis": {
      "type": "object",
      "description": "Linear Axis which has a direction (referenced nodes Z+ direction) and min/max Values",
      "properties": {
        "minValue": {
          "type": "number",
          "default": 0
        },
        "maxValue": {
          "type": "number",
          "default": 10
        }
      },
      "required": ["minValue", "maxValue"],
      "additionalProperties": false
    },
    "RotaryAxis": {
      "type": "object",
      "description": "Defines a Rotary Axis which has a Center Point (referenced nodes Transform Vector), a rotation Axis (referenced nodes Y-Vector (UP)) and min/max rotation Values",
      "properties": {
        "minRotation": {
          "type": "number",
          "default": 0
        },
        "maxRotation": {
          "type": "number",
          "default": 360
        }
      },
      "required": ["minRotation", "maxRotation"],
      "additionalProperties": false
    }
  },
  "additionalProperties": false
}

When generating Code with the CodeGen tool it generates the following output:

  // <auto-generated/>

  //------------------------------------------------------------------------------------------------
  //      This file has been programatically generated; DON´T EDIT!
  //------------------------------------------------------------------------------------------------

  #pragma warning disable SA1001
  #pragma warning disable SA1027
  #pragma warning disable SA1028
  #pragma warning disable SA1121
  #pragma warning disable SA1205
  #pragma warning disable SA1309
  #pragma warning disable SA1402
  #pragma warning disable SA1505
  #pragma warning disable SA1507
  #pragma warning disable SA1508
  #pragma warning disable SA1652

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Numerics;
  using System.Text.Json;

  namespace SharpGLTF.Schema2
  {
      using Collections;

      /// <summary>
      /// Axis Definitions for glTF.
      /// </summary>
      #if NET6_0_OR_GREATER
      [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
      #endif
      [global::System.CodeDom.Compiler.GeneratedCodeAttribute("SharpGLTF.CodeGen", "1.0.0.0")]
      partial class glTFAxisDefinitions : ExtraProperties
      {

          private System.Text.Json.Nodes.JsonNode _LinearAxis;

          private System.Text.Json.Nodes.JsonNode _RotaryAxis;

          protected override void SerializeProperties(Utf8JsonWriter writer)
          {
              base.SerializeProperties(writer);
              SerializeProperty(writer, "LinearAxis", _LinearAxis);
              SerializeProperty(writer, "RotaryAxis", _RotaryAxis);
          }

          protected override void DeserializeProperty(string jsonPropertyName, ref Utf8JsonReader reader)
          {
              switch (jsonPropertyName)
              {
                  case "LinearAxis": _LinearAxis = DeserializePropertyValue<System.Text.Json.Nodes.JsonNode>(ref reader); break;
                  case "RotaryAxis": _RotaryAxis = DeserializePropertyValue<System.Text.Json.Nodes.JsonNode>(ref reader); break;
                  default: base.DeserializeProperty(jsonPropertyName,ref reader); break;
              }
          }

      }

  }

Now that is something new i wasnt able to determine how to handle the JsonNode, nor do i know if this is correct. I tried changing the schema a dozen times and i even cant remember what i changed everything in the past days.

But then searching for other generated files, where these JsonNodes where generated i stumbled across this:

https://github.com/vpenades/SharpGLTF/blob/5a33d5452528d827ac55727f302d8a91a75c4186/src/SharpGLTF.Ext.3DTiles/Schema2/Generated/Ext.CESIUM_ext_structural_metadata_root.g.cs#L118-L120

digging a bit further how it was handled in that extension i found this:

https://github.com/vpenades/SharpGLTF/blob/5a33d5452528d827ac55727f302d8a91a75c4186/src/SharpGLTF.Ext.3DTiles/Schema2/Ext.StructuralMetadataRoot.cs#L540-L545

So is the "JsonNode" Type currently not supported and i need to pause my work here or is there anything i could do to work around it (or possible fix this?)

Thanks again for the help!!

vpenades commented 3 months ago

I think the problem is this:

"type": "object",

Keep in mind the codegen tool cannot "magically" determine the kind of data you're trying to store.

Also keep in mind that C# System.Object is not "magically" serializable to json.

So whenever you use "object" in the schema, the codeGen will translate it to System.Text.Json.JsonNode , which is c# API to create json object structures.

If you want to avoid this, you need to avoid using "object" and user other data types.

If there's no good match between the data type you place in the schema, and the data types used in c#, the CodeGen tool has some replacement helpers that can allow you to "tweak" the schema after loading it. You'll see plenty of examples in the other extensions already used by the schema.

But if you can't avoid using "object" because the data type is mutable, then you have to rely on JsonNode and learn the API to access the underlaying data.