简体   繁体   中英

Polymorphic deserialization of jackson using parent property value

I have a json as follows:

{
    "transformationRules": [
        {
            "targetFieldName": "pageUrlNumber",
            "inputPath": "$.metadata.pageUrl",
            "rules": [
                {
                    "name": "regex",
                    "regexPattern": "\\d+",
                    "regexTransformType": "extract",
                    "order":2
                }
            ]
        },
        {
            "targetFieldName": "categories",
            "inputPath": "$.attributes[0].productInfo.breadCrumbs",
            "rules": [
                {
                    "name": "transform"
                }
            ]
        }
    ]
}

The rules array has json of different classes.

I want convert the above json to their pojos depending on the value of the name ie regex, transform. I have tried the following code.

Rule.java

@NoArgsConstructor
@Data
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
        property = "name")
@JsonSubTypes({
        @JsonSubTypes.Type(value = RegexRule.class, name = "regex"),
        @JsonSubTypes.Type(value = Transform.class, name = "transform"),
})
public abstract class Rule {

    @JsonProperty("name")
    private String name;

    @JsonProperty("order")
    private int order = 1;

    protected Rule(String name, int order) {
        this.name = name;
        this.order = order;
    }

}

RegexRule.java

@NoArgsConstructor
@Data
public class RegexRule extends Rule{

    @JsonProperty("regexPattern")
    private String regexPattern;

    @JsonProperty("regexTransformType")
    private String regexTransformType;

    @JsonProperty("replacementValue")
    private String replacementValue = "";

    @JsonProperty("regexGroupNumber")
    private int regexGroupNumber = 0;

    public RegexRule(String name, int order, String regexPattern, String regexTransformType, String replacementValue, int regexGroupNumber) {
        super(name, order);
        this.regexGroupNumber = regexGroupNumber;
        this.regexPattern = regexPattern;
        this.regexTransformType = regexTransformType;
        this.replacementValue = replacementValue;
    }
}

Transform.java

@NoArgsConstructor
@Data
public class Transform extends Rule{

    public Transform(String name, int order) {
        super(name, order);
    }
}

Main.java

for(TransformationRule transformationRule: getTransformationRules()){
            for(Rule rule:transformationRule.getRules()){
                System.out.println(rule.getName());
            }
        }

Output:

null
null

In my Main function, when I deserialize the json to the pojos, I'm getting name as null. Instead I should get regex and transform as output

What mistake have I done here? I need the name for a factory method

As.EXTERNAL_PROPERTY sounds wrong here and I'm surprised if that worked at all, that would imply:

{
  "name": "regex", // This is the *external* property, one level up
  { // this is the Rule
    "order": 2,
    ...
  }
}

Try

  • As.PROPERTY
    • You can delete Rule#name from the POJO as it is treated as meta-data existing only for Jackson to deserialise correctly. Remember rule.getName()=="regex" is the same as rule instanceof RegexRule
  • As.EXISTING_PROPERTY
    • Will populate the field as you expected but might have slightly worse performance at scale (only matters if this is something the app is doing continuously)
    • See the original feature request for another example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM