Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use dynamic property names for a Json object

How can we make the JSON property name dynamic. For example

public class Value {
    @JsonProperty(value = "value")
    private String val;

    public void setVal(String val) {
        this.val = val;
    }

    public String getVal() {
        return val;
    }
}

when serializing this object it's saved as {"value": "actual_value_saved"} but I want to make the key also dynamic like {"new_key": "actual_value_saved"}. Any help is much appreciated.

like image 337
Prasad Avatar asked Apr 15 '19 07:04

Prasad


2 Answers

You can use JsonAnySetter JsonAnyGetter annotations. Behind you can use Map instance. In case you have always one-key-object you can use Collections.singletonMap in other case use HashMap or other implementation. Below example shows how easy you can use this approach and create as many random key-s as you want:

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        DynamicJsonsFactory factory = new DynamicJsonsFactory();
        ObjectMapper mapper = new ObjectMapper();

        System.out.println(mapper.writeValueAsString(factory.createUser("Vika")));
        System.out.println(mapper.writeValueAsString(factory.createPhone("123-456-78-9")));
        System.out.println(mapper.writeValueAsString(factory.any("val", "VAL!")));
    }
}

class Value {

    private Map<String, String> values;

    @JsonAnySetter
    public void put(String key, String value) {
        values = Collections.singletonMap(key, value);
    }

    @JsonAnyGetter
    public Map<String, String> getValues() {
        return values;
    }

    @Override
    public String toString() {
        return values.toString();
    }
}

class DynamicJsonsFactory {

    public Value createUser(String name) {
        return any("name", name);
    }

    public Value createPhone(String number) {
        return any("phone", number);
    }

    public Value any(String key, String value) {
        Value v = new Value();
        v.put(Objects.requireNonNull(key), Objects.requireNonNull(value));

        return v;
    }
}

Above code prints:

{"name":"Vika"}
{"phone":"123-456-78-9"}
{"val":"VAL!"}
like image 172
Michał Ziober Avatar answered Oct 29 '22 05:10

Michał Ziober


You could have all the possible names as variables, and annotate them so they are ignored if null. This way you only get in your JSON the one that has a value

Then change your setter to feed into the variable mapped to the key you want.

class Value {

    @JsonProperty("val")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String val;

    @JsonProperty("new_key")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String newKey;

    @JsonProperty("any_random_string")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String anyRandomString;

    public void setVal(String s) {
        if(/* condition1 */)
            this.val = s;
        else if (/* condition2 */) {
            this.newKey = s;
        } else  if (/* condition3 */) {
            this.anyRandomString = s;
        }
    }

}
like image 32
Bentaye Avatar answered Oct 29 '22 05:10

Bentaye