Shiv
Shiv

Reputation: 115

How to make serialize missing fields in JSON String with jackson

I am reading a JSON String where every field is optional and i need to either get the values from config or set it to a default value.

Say my JSON is -

{
"action": {
           "onWarning":{
               "alert":{
                      "isEnabled": true,
                    "name": "DVS.sd_service.data-validation.bigdata.warning"
                       }
               },
           "onError":{
             "alert":{
                    "isEnabled": false,
                    "name": "DVS.sd_service.data-validation.bigdata.error"
                    }
               }
         }
}

And my code to read this JSON is -

    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    mapper.registerModule(new Jdk8Module());
    JobConfig jobConfig = mapper.readValue(contentJson, JobConfig.class);

And below are my wrapper classes -

@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class JobConfig {
    public Optional<AlertConfig> action;
}

@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class AlertWrapper {
    public Optional<Alert> alert;
}

@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class AlertConfig {
    public Optional<AlertWrapper> onSuccess;
    public Optional<AlertWrapper> onWarning;
    public Optional<AlertWrapper> onError;
}

@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Alert{
    public Optional<Boolean> isEnabled;
    public Optional<String> name;
}

Now the objective here is to read OnError.alert.isEnabled however if this field or the entire onError part is not available then we have to set it to default True

The function i have written for this is :-

private Optional<Boolean> getErrorIsEnabled(JobConfig jobConfig ) {
        Optional<Boolean> isEnabled = Optional.empty();
        if(jobConfig.action.isPresent()) {
            if(jobConfig.action.get().onError.isPresent()){
                if(jobConfig.action.get().onError.get().alert.isPresent()) {
                    if(jobConfig.action.get().onError.get().alert.get().isEnabled.isPresent()){
                        isEnabled= jobConfig.action.get().onError.get().alert.get().isEnabled;
                    }
                }
            }
        }
        return isEnabled;
    }

This way i get to find if the vale is available in config by calling the above function -

getErrorIsEnabled(jobConfig).orElse(true)

The problem is (calling the above function) this works but looks way too ugly to keep on checking if the fields are available or not at every level by calling the isPresent() funtion.

The User can entirely skip the OnError Part, or action Part, or just the alert part, or the alert.isEnabled part. There has to be a better way to acieve this! Open to suggestions or improvements or try a different approach alltogether.

Upvotes: 1

Views: 916

Answers (1)

Tushar Kesarwani
Tushar Kesarwani

Reputation: 596

What you should do is create default values for the fields like

private Optional<Boolean> isEnabled = Optional.empty();
private Optional<String> name = Optional.empty();

public Alert(Optional<Boolean> isEnabled , Optional<String> name){
    this.isEnabled=isEnabled;
    this.name=name;
}

And for every Object like this -

private final Alert alertDetail = new Alert(Optional.empty(), Optional.empty());
    private final AlertWrapper alertWrapper = new AlertWrapper(alertDetail);


    private AlertWrapper onSuccess = alertWrapper;
    private AlertWrapper onWarning = alertWrapper;
    private AlertWrapper onError = alertWrapper;

You will have to create constructor so you will have to change your lombok to @NoArgsConstructor also use @Getter @Setter so you can call your objects like below -

jobConfig.getAction().getOnWarning().getAlert().getIsEnabled().orElse(true)

Upvotes: 1

Related Questions