0

I am attempting to use JsonSerializer.Deserialize() from System.Text.JSON in .NET 6.

I have no control over the format of the JSON.

I have used it successfully in the past but now the data I need to consume is more complicated (but not VERY complicated). I am assuming that I am simply describing my data incorrectly.

I have tried several things.... but the description below is the only way so far that I could consume the data at all.

I think my biggest problem is that I am trying to use the wiz-bang "Paste Special -> Paste JSON as Classes" without really understanding how to form my classes for serialization/deserialization.

Here is a simple example of the JSON I am trying to consume:

[
  {
    "version": "1.0b",
    "sub_version": "x.y.barf"
  },
  {
    "somestring": "I am a string",
    "isCool": false,
    "a_cool_array": [
      "bob",
      "jill",
      "pete"
    ]
  }
]

If I use the whiz-bang "Paste Special" tool, I get the following generated for me.

public class Rootobject
{
    public Class1[] Property1 { get; set; }
}

public class Class1
{
    public string version { get; set; }//<-- I need these to remain in their own object 
    public string sub_version { get; set; }//<-- I need these to remain in their own object
    public string somestring { get; set; }
    public bool isCool { get; set; }
    public string[] a_cool_array { get; set; }
}

Here is the problem that I have.

The whiz-bang tool put my first object (with one version strings) and second (more complicated) object into the same object.

If I use a call like this:

var deserializedJSON = JsonSerializer.Deserialize<List<Class1>>(myJSONTextHere);

I end up with two objects in the list.

The first one has the versions filled out, the second one only has the other fields filled out.

This all makes sense to me but I don't know how to get around the problem.

I need these objects to model the JSON and I need them to save back in the same format when I re-serailize the modified classes elsewhere. This isn't my exact problem as I have simplified it for the question.

dbc
  • 104,963
  • 20
  • 228
  • 340
Señor CMasMas
  • 4,290
  • 2
  • 14
  • 21
  • If I am not mistaken, the issue is with how your JSON data is structured - I believe it is structured to represent two objects, which is why it is being created as so (outer-most set of {} brackets). Unless, that's the intention & then, I'm not sure I understand the issue. – Dash Apr 08 '22 at 17:07
  • Is there any way to change the JSON? The problem is that as far as the data is concerned, it's not split up into different types of data, it's just a `List>`, which is why the whiz-bang tool can't change it into 2 classes. – Neil Apr 08 '22 at 17:12
  • I am absolutely 100% not able to change the data structure in any way shape or form @Neil. I would have never written it this way in the first place. – Señor CMasMas Apr 08 '22 at 18:29
  • You have a couple options. 1) You could define a polymorphic type hierarchy with two subtypes, one for the first entry and one for the second, then write a custom jsonconverter along the lines of the ones from [Is polymorphic deserialization possible in System.Text.Json?](https://stackoverflow.com/q/58074304/3744182). 2) You could deserialize to `JsonNode` which represents an editable JSON DOM and make the necessary changes manually. Does either option answer your question? – dbc Apr 10 '22 at 15:12

2 Answers2

1

Your json needs to look like this:

{
 "class1": [
   //more json
 ],
 "class2": [
   //more json
 ]
}

Then you will have:

public class RootObject 
{
 // class1 and 2 in here
}

public class Class1
{

}

public class Class2
{

}
jasonc
  • 213
  • 1
  • 7
1

I have found one way around this problem.
It is ugly but seems to work. I hate that my code has to know about the data it is manipulating.

I used the actual JSON DOM to split the two disparate classes into individual JSON objects, then used the class de-serializer to load the individual objects into their given types.

In the following example, I am not checking anything.. I happen to know the order of the objects. I could check the raw JSON to make sure it was what I was looking for. In this case, I don't need to.

So, instead of taking the class structure as pasted by the super spiffy "Paste Classes from JSON" thingamajigger.. I split the classes myself.

Like this:

    public class VersionClass
    {
        public string version { get; set; }
        public string sub_version { get; set; }
    }

    public class DataClass
    {
        public string somestring { get; set; }
        public bool isCool { get; set; }
        public string[] a_cool_array { get; set; }
    }

Then, I can load the JSON into the objects I need like this:

     using var jsonDoc = JsonDocument.Parse(jsonText);

     var versionClass = jsonDoc.RootElement[0].Deserialize<VersionClass>();
     var dataClass    = jsonDoc.RootElement[1].Deserialize<DataClass>();

I hope this helps someone having the same problem.

Señor CMasMas
  • 4,290
  • 2
  • 14
  • 21
  • Ugly, but I guess it works. I hope you report back to whoever generated the JSON to tell them that their output is not easy to work with. I would guess it's handballed, rather than using a compliant JSON library to generate it. – Neil Apr 09 '22 at 12:06
  • Yes @Neil .. am getting the yuckies just writing the code this way. The "schema" is set in stone. :( There is nobody to report to that would care (a LARGE 3rd party). – Señor CMasMas Apr 09 '22 at 18:41
  • I don't see what is ugly here, other than the assumption that `VersionClass` comes first and `DataClass` comes second. – dbc Apr 10 '22 at 15:13