Home > Back-end >  Trying to Deserialize JSON to typed Object in Powershell
Trying to Deserialize JSON to typed Object in Powershell

Time:11-06

I'm trying to deserialize a JSON string (which is coming from an API response) into my typed objects in Powershell, however, I keep receiving two types of errors.

I have two PowerShell classes such as:

cpublic class DataType
{
    [string] key
    [string] dataName
}

public class DataTypeList
{
    [string] key 
    [string] name 
    [string] localeKey 
}

public class Event
{
    [string] key
    [string] name
    [string] localeKey
    [DataType] DataType
    [List[DataTypeList]] DataTypeList
}

public class Root
{
   [List[Event]] $events
}

and my JSON response looks something like this:

  {
   "Events":[
      {
         "key":"1234",
         "name":"Bob Muprhy",
         "localeKey":"4",
         "DataType":{
            "key":"1111111",
            "dataName":"Name One"
         },
         "DataTypeList":[
            {
               "key":"983984",
               "name":"New name",
               "localeKey":"34985"
            },
            {
               "key":"124543534",
               "name":"New name new Name",
               "localeKey":"asdfsadf"
            }
         ]
      },
      {
         "key":"123456567",
         "name":"Pete big",
         "localeKey":"4",
         "DataType":{
            "key":"1111111",
            "dataName":"Name 1"
         },
         "DataTypeList":[
            {
               "key":"983984",
               "name":"New name",
               "localeKey":"34985"
            },
            {
               "key":"124543534",
               "name":"New name new Name",
               "localeKey":"asdfsadf"
            }
         ]
      }
   ]
}

My code currently looks something like this, I'm using Invoke-RestMethod as I've read up that it will automatically apply the ConvertFrom-JSON to the API response/content

Here i am getting the json response:

$json = Invoke-RestMethod -Uri "<API Link>"

Here I am trying to "deserialize the JSON into my object" by using the Cast-Initialization technique

$response = [Root]($json)

However i will get an error response saying: Cannot create object of type "Root". Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Collections.Generic.List`1[FeaturedEvent]

I tried also to do something like:

$response = [Root]($json.Events)

However, that will also return error Cannot convert the "System.Object[]" value of type "System.Object[]" to type "Root

When deserializing something in C# i know I would be able to do something like

*JsonConvert.DeserializeObject<Root>(json);*

Trying to replica the same here in Powershell

I also did try this:

 $root = [Root]::new()

 $root.Events = $json.Events

However again I received the same error

CodePudding user response:

Here's self-contained sample code that demonstrates that your approach should work (leaving the syntax errors in the class definitions aside, which have been corrected below).

  • The sample JSON from your question is parsed into a [pscustomobject] object graph via ConvertFrom-Json, to simulate your Invoke-RestMethod call.

  • A simple cast to [Root] is sufficient to convert the [pscustomobject] graph into a strongly typed object graph based on your custom classes.

  • The result is re-converted to JSON to demonstrate that the data was correctly parsed - note the source-code comments regarding case of the property names.

using namespace System.Collections.Generic

# Your custom classes.
class DataType
{
    [string] $key
    [string] $dataName
}

class DataTypeList
{
    [string] $key 
    [string] $name 
    [string] $localeKey 
}

class Event
{
    [string] $key
    [string] $name
    [string] $localeKey
    [DataType] $DataType
    [List[DataTypeList]] $DataTypeList
}

class Root
{
   [List[Event]] $Events
}

# Simulate an Invoke-RestMethod call that
# returns JSON, which Invoke-RestMethod automatically
# parses into a [pscustomobject] object graph.
$fromJson = ConvertFrom-Json @'
{
  "Events":[
     {
        "key":"1234",
        "name":"Bob Muprhy",
        "localeKey":"4",
        "DataType":{
           "key":"1111111",
           "dataName":"Name One"
        },
        "DataTypeList":[
           {
              "key":"983984",
              "name":"New name",
              "localeKey":"34985"
           },
           {
              "key":"124543534",
              "name":"New name new Name",
              "localeKey":"asdfsadf"
           }
        ]
     },
     {
        "key":"123456567",
        "name":"Pete big",
        "localeKey":"4",
        "DataType":{
           "key":"1111111",
           "dataName":"Name 1"
        },
        "DataTypeList":[
           {
              "key":"983984",
              "name":"New name",
              "localeKey":"34985"
           },
           {
              "key":"124543534",
              "name":"New name new Name",
              "localeKey":"asdfsadf"
           }
        ]
     }
  ]
}
'@

# Parse the [pscustomobject] graph into a strongly
# typed object graph based on the custom classes.
# Note: PowerShell ignores case differences between
#       the property names as specified in the original JSON
#       and the custom-class property names.
$fromJsonStronglyTyped = [Root] $fromJson 

# Reconvert to JSON to demonstrate that roundtripping succeeds.
# Note: The property names are written with the case as defined
#       in your custom classes, which may differ from the original JSON.
$fromJsonStronglyTyped | ConvertTo-Json -Depth 4

CodePudding user response:

Your datatype has an error. public class DataTypeList should have [DataType[]]$DataTypeList only according to $json. this should deserialize your json to custom [Root] type:

class DataType {
    [string]$key;
    [string]$dataName;
}

 class DataTypeList {
    [DataType[]]$DataTypeList;
}

class Event {
    [string]$key;
    [string]$name;
    [string]$localeKey;
    [DataType]$DataType;
    [Collections.Generic.List[DataTypeList]]$DataTypeList;
}

class Root {
   [Collections.Generic.List[Event]]$events;
}

$content = ([System.Web.Script.Serialization.JavaScriptSerializer]::new()).Deserialize($json, [Root])
  • Related