2

I'm having a problem while trying to create a model from a json which is formed by json arrays that have same properties but different names.

This is an example of json which i want to transform into a model:

{
    "AA": [
        {
            "t": 1605589200,
            "o": 17.37,
            "h": 18.3,
            "l": 17.11,
            "c": 18.28,
            "v": 9578592
        },
        {
            "t": 1605675600,
            "o": 18.3,
            "h": 18.85,
            "l": 18.3,
            "c": 18.575,
            "v": 9092559
        }
    ],
    "AAIC": [
        {
            "t": 1605589200,
            "o": 2.92,
            "h": 3.045,
            "l": 2.92,
            "c": 3.02,
            "v": 550468
        },
        {
            "t": 1605675600,
            "o": 3.11,
            "h": 3.1684,
            "l": 3.03,
            "c": 3.05,
            "v": 476259
        }
    ]
}

Notice that each array has the same object structure but have different names ("AA" and "AAIC"). I already wrote the following code:

@Data
public class SomeClass {

    private List<SomeClassInfo> someClassInfo;

    @Data
    public class SomeClassInfo {

        @JsonProperty(value = "t")
        private Integer time;
        @JsonProperty(value = "o")
        private Double o;
        @JsonProperty(value = "h")
        private Double h;
        @JsonProperty(value = "l")
        private Double l;
        @JsonProperty(value = "c")
        private Double c;
        @JsonProperty(value = "v")
        private Integer v;
    }

}

But it is not enough, because I don't want to make n lists with specific name such as

@JsonProperty(value = "AA")
List<SomeClassInfo> AA;
@JsonProperty(value = "AAIC")
List<SomeClassInfo> AAIC;

since the example above represents 2 of 10k arrays and each array contains n json object with the same structure.

Daesos
  • 99
  • 10
  • So you say you don't want to make lists with specific names, ok. But assuming that there are many different names like "AA", "AAIC", etc, leaving alone the Jackson, its just a mapping library, what is the preferred way to express this hierarchy in pure Java? Could you post your "goal" in Java and community could probably help with finding the best way to express that with Jackson mapping annotations – Mark Bramnik Nov 19 '20 at 07:52
  • If you don't want to manually declare 10k properties you either do sort of [code generation](https://stackoverflow.com/questions/1957406/generate-java-class-from-json) or use HashMap to store names of properties. IMHO hashmap perfectly fits in this case since using a class with 10k properties (even generated) seems to be an awful coding style – Nikolai Shevchenko Nov 19 '20 at 08:09
  • In fact, I made a working solution by using HashMap. I posted the solution below. – Daesos Nov 19 '20 at 08:24

2 Answers2

4

you can use ObjectMapper to wrap your json into

Map<String,List<SomeClassInfo>>

like that

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class test {

    public static void main(String[] args)  {
        ObjectMapper mapper = new ObjectMapper();
        String jsonInput = "{\"AA\":[{\"t\":1605589200,\"o\":17.37,\"h\":18.3,\"l\":17.11,\"c\":18.28,\"v\":9578592},{\"t\":1605675600,\"o\":18.3,\"h\":18.85,\"l\":18.3,\"c\":18.575,\"v\":9092559}],\"AAIC\":[{\"t\":1605589200,\"o\":2.92,\"h\":3.045,\"l\":2.92,\"c\":3.02,\"v\":550468},{\"t\":1605675600,\"o\":3.11,\"h\":3.1684,\"l\":3.03,\"c\":3.05,\"v\":476259}]}";
        TypeReference<HashMap<String, List<SomeClassInfo>>> typeRef
                = new TypeReference<HashMap<String, List<SomeClassInfo>>>() {
        };
        Map<String, List<SomeClassInfo>> map = null;
        try {
            map = mapper.readValue(jsonInput, typeRef);
            System.out.println(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }

    @Getter
    @Setter
    @ToString
    @Data
    public static class SomeClassInfo {

        @JsonProperty(value = "t")
        private Integer time;
        @JsonProperty(value = "o")
        private Double o;
        @JsonProperty(value = "h")
        private Double h;
        @JsonProperty(value = "l")
        private Double l;
        @JsonProperty(value = "c")
        private Double c;
        @JsonProperty(value = "v")
        private Integer v;
    }
}

and the response will be like that :

{AA=[test.SomeClassInfo(time=1605589200, o=17.37, h=18.3, l=17.11, c=18.28, v=9578592), test.SomeClassInfo(time=1605675600, o=18.3, h=18.85, l=18.3, c=18.575, v=9092559)], AAIC=[test.SomeClassInfo(time=1605589200, o=2.92, h=3.045, l=2.92, c=3.02, v=550468), test.SomeClassInfo(time=1605675600, o=3.11, h=3.1684, l=3.03, c=3.05, v=476259)]}
Hamza Slama
  • 116
  • 8
  • I prefer not to use ObjectMapper because my purpose is to make a model clean and clear without using middle operations. Is there another way to accomplish this? – Daesos Nov 19 '20 at 07:43
1

I found the solution by merging @Hamza Slama solution and others that i finally found at the following link: deserialize json using jackson with dynamic field name

My edited model is:

@Data
public class SomeClass {

    private Map<String, SomeClassInfo[]> someClassInfoMap = new HashMap<>();

    @JsonAnySetter
    public void setSomeClassInfo (String name, SomeClassInfo[] someClassInfo) {
        someClassInfoMap.put(name, someClassInfo);
    }

    @Data
    public static class SomeClassInfo {

        @JsonProperty(value = "t")
        private Integer time;
        @JsonProperty(value = "o")
        private Double o;
        @JsonProperty(value = "h")
        private Double h;
        @JsonProperty(value = "l")
        private Double l;
        @JsonProperty(value = "c")
        private Double c;
        @JsonProperty(value = "v")
        private Integer v;
    }

}

Daesos
  • 99
  • 10