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

KnownSubType with property value #74

Closed
Blackbaud-ChristiSchneider opened this issue May 23, 2019 · 4 comments
Closed

KnownSubType with property value #74

Blackbaud-ChristiSchneider opened this issue May 23, 2019 · 4 comments
Labels

Comments

@Blackbaud-ChristiSchneider

Is your feature request related to a problem? Please describe.
I am trying to deserialize an array of items which derive from a base class. These items don't have a $type property but do have a similar property by a different name, which is set to a constant string per property type. I am able to use KnownSubTypeWithProperty to get pretty close but I don't think this solution will continue to work as more subtypes are added.

Describe the solution you'd like
An attribute that allows you to specify the type, property name, and property value to look for.

[JsonSubtypes.KnownSubTypeWithPropertyValue(typeof(HeaderWidget), "widget_type", "HEADER")]
[JsonSubtypes.KnownSubTypeWithPropertyValue(typeof(EmailWidget), "widget_type", "EMAIL")]

Describe alternatives you've considered
I am currently using KnownSubTypeWithProperty to differentiate between the types but two of my types are identical except for the widget_type field.
EmailWidget

    {
      "label": {
        "text": "Email",
        "hint": "Original text: Email"
      },
      "required": true,
      "order": 4,
      "widget_type": "EMAIL"
    }

TextWidget

    {
      "label": {
        "text": "Comments",
        "hint": "Original text: Comments"
      },
      "order": 3,
      "widget_type": "TEXT"
    }

Right now I am differentiating by not having any of the TextWidgets that I have specified include the required property, but that's not going to work in all cases. I could also make these two types actually be the same class but I think that is a less than ideal solution since all other types have their own class and I'd like to keep it consistent.

Additional context

I think this is related to #69 but not quite the same.

*** Source/destination types

This is a subset of the types I have.

    [JsonConverter(typeof(JsonSubtypes))]
    [JsonSubtypes.KnownSubTypeWithProperty(typeof(HeaderWidget), "text")]
    [JsonSubtypes.KnownSubTypeWithProperty(typeof(NameWidget), "placeholder_last_name")]
    public abstract class Widget
    {
        [Newtonsoft.Json.JsonProperty("order", Required = Newtonsoft.Json.Required.Always)]
        public int Order { get; set; }

        [Newtonsoft.Json.JsonProperty("widget_type", Required = Newtonsoft.Json.Required.Always)]
        public string WidgetType { get; set; }
    }

    public class HeaderWidget : Widget
    {
        public const string WIDGET_TYPE = "HEADER";

        public HeaderWidget()
        {
            WidgetType = WIDGET_TYPE;
        }

        [Newtonsoft.Json.JsonProperty("text", Required = Newtonsoft.Json.Required.Always)]
        public string Text { get; set; }
    }

    [ExcludeFromCodeCoverage]
    public class NameWidget : Widget
    {
        public const string WIDGET_TYPE = "NAME";

        public NameWidget()
        {
            WidgetType = WIDGET_TYPE;
        }

        [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Always)]
        public WidgetLabel Label { get; set; }

        [Newtonsoft.Json.JsonProperty("placeholder_last_name", Required = Newtonsoft.Json.Required.Always)]
        public string PlaceholderLastName { get; set; }

        [Newtonsoft.Json.JsonProperty("placeholder_first_name", Required = Newtonsoft.Json.Required.Always)]
        public string PlaceholderFirstName { get; set; }
    }

*** Source/destination JSON

    {
      "text": "Gift amount",
      "order": 0,
      "widget_type": "HEADER"
    },
    {
      "label": {
        "text": "Name",
        "hint": "Original text: Name"
      },
      "placeholder_last_name": "Last name",
      "placeholder_first_name": "First name",
      "order": 3,
      "widget_type": "NAME"
    }
@manuc66
Copy link
Owner

manuc66 commented May 26, 2019

Hi @Blackbaud-ChristiSchneider

It seems that it could be supported by the feature implemented in #60 (not yet released)

@Blackbaud-ChristiSchneider
Copy link
Author

I took a few minutes to out and it didn't work - I'll see if I can find some time to dig in. I'm not sure if I'm misunderstanding how it is intended to work - should we expect that $PayloadKind (or whatever) is included in the json to deserialize?

@manuc66
Copy link
Owner

manuc66 commented May 29, 2019

And why not simply with:

    [JsonConverter(typeof(JsonSubtypes), "widget_type")]
    [JsonSubtypes.KnownSubType(typeof(HeaderWidget), "HEADER")]
    [JsonSubtypes.KnownSubType(typeof(NameWidget), "NAME")]
    [JsonSubtypes.KnownSubType(typeof(EmailWidget), "EMAIL")]
    public abstract class Widget
    {
        [JsonProperty("order", Required = Required.Always)]
        public int Order { get; set; }

        [JsonProperty("widget_type", Required = Required.Always)]
        public string WidgetType { get; set; }
    }

See: https://dotnetfiddle.net/z47EJT

(#60 is if you have by example an abstract class TitleWidget with child that are discriminated with another field level...)

@manuc66 manuc66 closed this as completed Jun 6, 2019
@Blackbaud-ChristiSchneider
Copy link
Author

I confirmed this works with 1.6.0, thanks a bunch!

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

No branches or pull requests

2 participants