srini
srini

Reputation: 213

Generic POJO for JSON Object that can take different type of values

I have a json payload (request payload of a rest api) with a defined schema, but there is one property that can take an array of unknown key value pairs. The value for each property can be of different type like number, string, array, range, date, etc. How do i create a POJO for this property and make deserialization work for the same?

I am currently thinking about writing a custom deserializer for my Property class, where i check the type of value and do some custom logic accordingly.

This looks like a typical requirement. I feel that there should be something available in Jackson or Gson that i am missing. I would love to reuse if it already exist. I looked around in SO, but couldnt find a good answer so far. Any suggestions would be appreciated.

{
  "id": 1234,
  "name": "test name 1",
  "properties": [
    {
      "key_a": 100
    },
    {
      "key_b": [
        "string1",
        "string2",
        "string3"
      ]
    },
    {
      "key_c": {
        "range": {
          "min": 100,
          "max": 1000
        }
      }
    }
  ]
}

I am thinking my POJO for property object would look something like this.

class Property {
   private String key;
   private Value value; 
}

Upvotes: 0

Views: 1233

Answers (2)

mntviews
mntviews

Reputation: 11

It is possible to use inheritance for that. This is the classes for your example with Jackson

public class Sample {

    @JsonProperty(value = "id")
    Integer id;
    @JsonProperty(value = "name")
    String name;
    @JsonProperty(value = "properties")
    List<Property> properties;
}


@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({
        @JsonSubTypes.Type(value = KeyA.class, name = "key_a"),
        @JsonSubTypes.Type(value = KeyB.class, name = "key_b"),
        @JsonSubTypes.Type(value = KeyC.class, name = "key_c")
})
public abstract class Property {
}

public class KeyA extends Property{
    Integer value;

    public KeyA(Integer value) {
        this.value = value;
    }
    @JsonValue
    public Integer getValue() {
        return value;
    }
}

public class KeyB  extends Property {

    List<String> valueList;


    @JsonCreator
    public KeyB( List<String> valueList) {
        this.valueList = valueList;
    }

    @JsonValue
    public List<String> getValueList() {
        return valueList;
    }

}

public class KeyC  extends Property {
   @JsonProperty(value = "range")
    Range value;

}

public class Range {
    @JsonProperty(value = "min")
    Integer min;
    @JsonProperty(value = "max")
    Integer max;
}

Upvotes: 1

Paul
Paul

Reputation: 1160

If I understand correctly you want to change to JSON and back. I wrote a small class for my own SpringBoot project, using ObjectMapper

@Component
public final class JsonUtils {

    private final ObjectMapper mapper;

    @Autowired
    public JsonUtils(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    public String asJsonString(final Object object) {
        try {
            return mapper.registerModule(new JavaTimeModule())
                    .writeValueAsString(object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /*
     * Customized Objectmapper for reading values compatible with this class' other methods
     * @Return the desired object you want from a JSON
     * IMPORTANT! -your return object should be a class that has a @NoArgsConstructor-
     */
    public Object readValue(final String input, final Class<?> classToRead) {
        try {
            return mapper
                    .readValue(input, classToRead);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}`

Perhaps it can be of some use to you.

Upvotes: 0

Related Questions