Thread overview
How to parse a json node that contains children of different types?
Jul 20, 2021
Bagomot
Jul 21, 2021
Mathias LANG
Jul 21, 2021
Bagomot
July 20, 2021

I have a json like this:

{
   "arguments":{
      "jvm":[
         {
            "rules":[
               {
                  "action":"allow",
                  "os":{
                     "name":"osx"
                  }
               }
            ],
            "value":[
               "-XstartOnFirstThread"
            ]
         },
         "-Djava.library.path=${natives_directory}"
      ]
   }
}

Here the "jvm" node is an array that has different data types for its elements (json object and string).

I am using asdf library to deserialize json. I am trying to deserialize this json into a structure like this:

struct Arguments{
    @serdeKeys("jvm")
    Object[] jvm;
}

But there is a problem with different types. I understand that Object[] is not suitable here, but I don’t know how to do it.

I ask you to help me with this.

July 21, 2021

On Tuesday, 20 July 2021 at 21:18:12 UTC, Bagomot wrote:

>

But there is a problem with different types. I understand that Object[] is not suitable here, but I don’t know how to do it.

I ask you to help me with this.

IIUC, the arguments are command line arguments passed to a Java program, and some of those might be passed to the JVM ?

So you probably will end up with something like:

struct Arguments{
    JVMArgs jvm;
    ProgramArgs program;
}

Of course, the question is, what's JVMArgs ?

Now, as you noticed, you can't represent an array of unrelated types in D (which makes sense). So what you can do is create a common type for it, by using an union.

union JVMArg
{
    RuleValue ruleValue;
    string str;
    // Etc...
}
alias JVMArgs = JVMArg[];

However, <YOUR-JSON-LIBRARY> might not support it directly, or might support it through its own type (you will need a tagged union, and not just a simple union, as you need to know the type that the library read).

But if you take a step back, I think you might find this solution is far from ideal.
Having worked on a JSON library myself, I can tell you they are all implemented with a tagged union. And converting a tagged union to a tagged union is no improvement.

Instead, I would recommend to just use the JSON directly. If you need to pass things around, you might want to deserialize it to a common format. For example, assuming your project is a process manager for Java program and you want to read a common set of arguments from a configuration file, you might want to just generate the strings:

auto myJSON = parseConfigFile("config.json");
string[] defaultJVMArgs = parseJVMArgs(myJSON);
auto processMonitor = new ProcessMonitor(defaultJVMArgs);

TL;DR: If you want to use loosely typed data in a strongly typed language, you need to come up with a common type. That common type is usually either a discriminated union (which a JSON object is, essentially) or something that is domain-specific.

Hope this helps. I had a quick look at asdf and couldn't see a support for tagged union, so you would probably need to provide your data structure with a deserializeFromAsdf method. If you want to do so, look into providing a wrapper to SumType, e.g.:

struct MyUnion (T...) {
    SumType!T data;
    alias data this;
    SerdeException deserializeFromAsdf(Asdf data) { /* Fill in the SumType */ }

But I would recommend just using the JSON object if you can.

July 21, 2021

On Wednesday, 21 July 2021 at 03:00:51 UTC, Mathias LANG wrote:

>

TL;DR: If you want to use loosely typed data in a strongly typed language, you need to come up with a common type. That common type is usually either a discriminated union (which a JSON object is, essentially) or something that is domain-specific.

Hope this helps. I had a quick look at asdf and couldn't see a support for tagged union, so you would probably need to provide your data structure with a deserializeFromAsdf method. If you want to do so, look into providing a wrapper to SumType, e.g.:

struct MyUnion (T...) {
    SumType!T data;
    alias data this;
    SerdeException deserializeFromAsdf(Asdf data) { /* Fill in the SumType */ }

But I would recommend just using the JSON object if you can.

Thank you! From your answer, I realized that in fact, I would rather do the parsing of these arguments myself.

Before using asdf, I tried to do the same with the standard std.json. The problem is the same there. I agree that this is logical for D.

I was also interested in SumType, I will try to do something with it for experience.

July 21, 2021

On 7/20/21 11:00 PM, Mathias LANG wrote:

>

But if you take a step back, I think you might find this solution is far from ideal.
Having worked on a JSON library myself, I can tell you they are all implemented with a tagged union. And converting a tagged union to a tagged union is no improvement.

Not jsoniopipe. In that case, you could use a specialized type with a fromJSON static member to do whatever you wanted.

-Steve