Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing json subtype based on parent property

I have a json coming with a dynamic attribute child, like below:

{  
  "label":"Some label",
  "attribute": {     <--- Dynamic attribute object
    "type": "TEXT",  <--- Field used to map `attribute` dynamic (inside child object)
    "languages":[
      {
          "language":"en_EN",
          "text":"do you approve?"
      }
    ]
  }
}

Or

{  
  "label":"Some label",
  "attribute": {
    "type": "NUMBER",
    "value: "10.0"
  }
}

I am able to deserialize above json properly using @JsonSubTypes with this code:

@Data
public class Field {
    private String label;
    private Attribute attribute;
}

@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Attribute.NumberAttribute.class, name = "NUMBER"),
    @JsonSubTypes.Type(value = Attribute.TextAttribute.class, name = "TEXT")
})
public class Attribute {
    private AttributeType type;

    @Data
    public static class TextAttribute extends Attribute {
        List<Language> languages;
    }

    @Data
    public static class NumberAttribute extends Attribute {
        String value;
    }

    @Data
    public static class Language {
        private String text;
        private String language;
    }
}

However, the problem I have is that I have to use type field coming inside the attribute object, and I would need to move the type to the parent object. The ending json should be like this:

{  
  "type": "TEXT",  <--- Field used to map `attribute` dynamic (in parent object)
  "label":"Some label",
  "attribute": {   <--- Dynamic attribute object
    "languages":[
      {
          "language":"en_EN",
          "text":"do you approve?"
      }
    ]
  }
}

Or

{  
  "type": "NUMBER",
  "label":"Some label",
  "attribute": {
    "value: "10.0"
  }
}

I couldn't find any way to use a parent field (or json path way) to use the type property being outside the dynamic subtype. Do you know how I can do this?

like image 472
Federico Piazza Avatar asked Oct 28 '25 10:10

Federico Piazza


1 Answers

You can achieve that by adding include = As.EXTERNAL_PROPERTY to @JsonTypeInfo. You just have to move the annotation to the field.

See the JavaDoc for EXTERNAL_PROPERTY:

Inclusion mechanism similar to PROPERTY, except that property is included one-level higher in hierarchy [...]

Here's an example:

@Data
class Field {
    private String label;
    private AttributeType attributeType;
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.EXTERNAL_PROPERTY, property = "attributeType")
    private Attribute attribute;
}

@Data
@JsonSubTypes({
        @JsonSubTypes.Type(value = Attribute.NumberAttribute.class, name = "NUMBER"),
        @JsonSubTypes.Type(value = Attribute.TextAttribute.class, name = "TEXT")
})
abstract class Attribute {
    @Data
    public static class TextAttribute extends Attribute {
        List<Language> languages;
    }

    @Data
    public static class NumberAttribute extends Attribute {
        String value;
    }

    @Data
    public static class Language {
        private String text;
        private String language;
    }
}

enum AttributeType {
    NUMBER, TEXT;
}
like image 158
Ken S Avatar answered Oct 29 '25 23:10

Ken S



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!