Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serilizing an object with tags similar to AWS Cloudformation #911

Closed
gitisz opened this issue Feb 23, 2024 · 4 comments
Closed

Serilizing an object with tags similar to AWS Cloudformation #911

gitisz opened this issue Feb 23, 2024 · 4 comments

Comments

@gitisz
Copy link

gitisz commented Feb 23, 2024

I'm trying to use the C# YamlDotNet to return a serialized output of an object expressed as YAML, where much of the YAML will have tags similiar to those avaialble in AWS Cloudformation templates, such as !FindInMap as documented (here)[https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html].

Here is one example where !FindInMap may be expressed:

value:
 - -Djob.enebled=true
 - !FindInMap [ "FOO", "BAR", "BAZ" ]

Or something slightly more complex, like a nested tag:

value:
- -Djob.enebled=true
- !FindInMap [ "FOO", "BAR", !Ref Baz ]

Using YamlDotNet, I see how to leverage SerializeBuilder, but WithTagMapping eludes me. In the examples above, how might a class/type look to achieve serialize to achieve the same?

Thanks

@EdwardCooke
Copy link
Collaborator

With the current implementation of mapping this is probably going to get you as close as you can get. With a little more work you could probably get the first element in your value object list to output without a single quote another type converter. Maybe something like an argument object or something. But, here you go to get you started.

using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;

var serializer = new SerializerBuilder()
    .WithTagMapping("!FindInMap", typeof(List<object>))
    .WithTagMapping("!Ref", typeof(Baz))
    .WithDefaultScalarStyle(ScalarStyle.DoubleQuoted)
    .WithTypeConverter(new BazTypeConverter())
    .Build();

var list = new List<object>();
list.AddRange(new[] { "FOO", "BAR" });
list.Add(new Baz());

var outer = new Outer
{
    Value =
    [
        "-Djob.enebled=true",
        list
    ]
};

var yaml = serializer.Serialize(outer);
Console.WriteLine(yaml);

var deserializer = new DeserializerBuilder()
    .WithTagMapping("!FindInMap", typeof(List<object>))
    .WithTagMapping("!Ref", typeof(Baz))
    .WithTypeConverter(new BazTypeConverter())
    .Build();

Console.WriteLine("=== Deserialized");
var result = deserializer.Deserialize<Outer>(yaml);
foreach (var o in result.Value)
{
    if (o is List<object> list1)
    {
        foreach (var o2 in list1)
        {
            Console.WriteLine($"  {o2}");
        }
    }
    else
    {
        Console.WriteLine(o);
    }
}


class Outer
{
    public object[] Value { get; set; }
}


class BazTypeConverter : IYamlTypeConverter
{
    public bool Accepts(Type type) => type == typeof(Baz);

    public object? ReadYaml(IParser parser, Type type)
    {
        var valid = parser.TryConsume<Scalar>(out var value);
        if (!valid || value == null)
        {
            throw new Exception($"Invalid type, expected scalar got {value?.GetType()}");
        }
        if (value.Value != "Baz")
        {
            throw new Exception("Invalid Scalar Value");
        }
        return new Baz();
    }

    public void WriteYaml(IEmitter emitter, object? value, Type type)
    {
        emitter.Emit(new Scalar(null, "!Ref", "Baz", ScalarStyle.Plain, false, false));
    }
}
class Baz
{
    public override string ToString()
    {
        return "I'm a Baz";
    }
}

Results in

Value:
- "-Djob.enebled=true"
- !FindInMap
  - "FOO"
  - "BAR"
  - !Ref Baz

=== Deserialized
-Djob.enebled=true
  FOO
  BAR
  I'm a Baz

@EdwardCooke
Copy link
Collaborator

Did the above answer your question?

@EdwardCooke
Copy link
Collaborator

Haven't heard back in a couple of months, I'm going to close the issue.

@gitisz
Copy link
Author

gitisz commented May 11, 2024

Thank you for the generous example! I did shelve this and used a client-side NodeJS alternative, but that was temporary. I'll give this a go and share back. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants