6

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.

Spartan
  • 339
  • 1
  • 3
  • 14
  • 2
    Possible duplicate of [Jackson dynamic property names](https://stackoverflow.com/questions/12134231/jackson-dynamic-property-names) – Arnaud Apr 15 '19 at 07:58
  • Do you want to save it only with `"new_key"` or do you want to save it sometimes with `"new_key"` and sometimes with `"value"`? and if yes on what grounds? – Bentaye Apr 15 '19 at 07:58
  • @Bentaye Yes, based the requirement the name might change. it can be ```"value"``` or ```"new_key"``` or ```"any_random_string"``` – Spartan Apr 15 '19 at 08:01
  • @Prasad Where do you get the required field name from? can you calculate it from within your Value object? – Bentaye Apr 15 '19 at 08:08
  • @Bentaye I've gone through the solutions using a custom ```JsonSerializer``` or ```JsonTypeInfo``` is allowing us to modify the value but not the key. My requirement is to have a dynamic key. I want to print something like this ```{"name": "user"} {"phone": "1234567890"}``` using this POJO as a common object. – Spartan Apr 15 '19 at 08:09
  • @Prasad yes I removed my comment, trying to get it work – Bentaye Apr 15 '19 at 08:12
  • @Bentaye Values are read from either a CSV File or Database. Actually the JSON which I'm working on is huge but this small piece of code will help me optimize the number of objects I should use in my application. – Spartan Apr 15 '19 at 08:15

3 Answers3

4

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!"}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
1

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;
        }
    }

}
Bentaye
  • 9,403
  • 5
  • 32
  • 45
  • Smart idea though but the number of fields to read are not same every time. They tend to change on a timely basis so in this approach I might need to update code every time when there is a change in field. – Spartan Apr 16 '19 at 08:22
0

Good question @Prasad, This answer is not about JAVA or SPRING BOOT, I'm just putting this answer because I searched to do this with node and hope this helps somebody somehow. In JAVASCRIPT we can add dynamic property names for JSON objects as below

var dogs = {};

var dogName = 'rocky';

dogs[dogName] = {
    age: 2,
    otherSomething: 'something'
};

dogName = 'lexy';

dogs[dogName] = {
    age: 3,
    otherSomething: 'something'
};

console.log(dogs);

But when we need to dynamically change the name we have to

  1. get that property
  2. and create another property with the same content and new name
  3. and delete the old property from JSON
  4. assign the new property to the JSON

is there a another way to dynamically change JSON name except for this method, thanks in advance