Próbuję przeanalizować poniższy plik Json przy użyciu biblioteki Gson w Javie. Podczas korzystania z innych języków, takich jak C #, ten JSON jest analizowany w tablicę, jednak wydaje się, że Gson konwertuje to na zestaw atrybutów Java (co, szczerze mówiąc, ma dla mnie więcej sensu). Czy ktoś wie, czy mogę zmienić to zachowanie biblioteki Gson?

{
  "Outer": {
    "0": {
      "Attr1": 12345,
      "Attr2": 67890
    },
    "1": {
      "Attr1": 54321,
      "Attr2": 09876
    }
  }
}

Poniższy kod demonstruje, jak Gson analizuje tablicę jako JsonObject. Żeby było jasne, zdaję sobie sprawę, że odniosłem się do outer jako JsonObject, ale robiłem to tylko po to, aby zademonstrować kod. Jeśli spróbuję określić outer jako JsonArray, kod się nie powiedzie.

String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder()
            .disableHtmlEscaping()
            .setLenient()
            .serializeNulls()
            .create();

JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");

System.out.println(outer);
System.out.println(outer.isJsonArray());

Wynik:

{"0":{"Attr1":12345,"Attr2":67890},"1":{"Attr1":54321,"Attr2":"09876"}}
false

//edytować Używam tego bieżącego prostego pliku Json jako przykładu, jednak moje zastosowanie tego kodu będzie polegało na przeanalizowaniu pliku Json o różnym i nieznanym kształcie. Dlatego potrzebuję Gson, aby automatycznie przeanalizował to do tablicy, tak aby isJsonArray zwrócił true.

1
JAC2703 3 kwiecień 2020, 13:16

4 odpowiedzi

Najlepsza odpowiedź

TL;DR: Zobacz sekcję „Używanie deserializatora” na dole, aby przeanalizować prosto do tablicy.


Ten JSON nie zawiera żadnych tablic. Tablica użyłaby składni JSON [...].

Normalnie obiekt JSON odwzorowałby na POJO, z name w parach nazwa / wartość odwzorowanych na pole POJO.

Jednak obiekt JSON można również odwzorować na Map, co jest szczególnie przydatne, gdy nazwy są dynamiczne, ponieważ pola POJO są statyczne.

Korzystanie z mapy

Obiekt JSON z wartościami liczbowymi jako nazwami można zamapować na Map<Integer, ?>, np. aby przeanalizować ten JSON do POJO, zrób to w następujący sposób:

class Root {
    @SerializedName("Outer")
    public Map<Integer, Outer> outer;
    @Override
    public String toString() {
        return "Root[outer=" + this.outer + "]";
    }
}
class Outer {
    @SerializedName("Attr1")
    public int attr1;
    @SerializedName("Attr2")
    public int attr2;
    @Override
    public String toString() {
        return "Outer[attr1=" + this.attr1 + ", attr2=" + this.attr2 + "]";
    }
}

Testuj

Gson gson = new GsonBuilder().create();
Root root;
try (BufferedReader in = Files.newBufferedReader(Paths.get("test.json"))) {
    root = gson.fromJson(in, Root.class);
}
System.out.println(root);

Wyjście

Root[outer={0=Outer[attr1=12345, attr2=67890], 1=Outer[attr1=54321, attr2=9876]}]

Pobierz jako Array

Następnie możesz dodać metodę pomocniczą do klasy Root, aby uzyskać ją jako tablicę:

public Outer[] getOuterAsArray() {
    if (this.outer == null)
        return null;
    if (this.outer.isEmpty())
        return new Outer[0];
    int maxKey = this.outer.keySet().stream().mapToInt(Integer::intValue).max().getAsInt();
    Outer[] arr = new Outer[maxKey + 1];
    this.outer.forEach((k, v) -> arr[k] = v);
    return arr;
}

Testuj

System.out.println(Arrays.toString(root.getOuterAsArray()));

Wyjście

[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]

Korzystanie z deserializatora

Jednak prawdopodobnie byłoby bardziej przydatne, gdyby konwersja na tablicę była wykonywana podczas analizowania, więc musisz napisać JsonDeserializer i powiedzieć o tym Gsonowi za pomocą @JsonAdapter:

class Root {
    @SerializedName("Outer")
    @JsonAdapter(OuterArrayDeserializer.class)
    public Outer[] outer;

    @Override
    public String toString() {
        return "Root[outer=" + Arrays.toString(this.outer) + "]";
    }
}
class OuterArrayDeserializer implements JsonDeserializer<Outer[]> {
    @Override
    public Outer[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        // Parse JSON array normally
        if (json.isJsonArray())
            return context.deserialize(json, Outer[].class);

        // Parse JSON object using names as array indexes
        JsonObject obj = json.getAsJsonObject();
        if (obj.size() == 0)
            return new Outer[0];
        int maxKey = obj.keySet().stream().mapToInt(Integer::parseInt).max().getAsInt();
        Outer[] arr = new Outer[maxKey + 1];
        for (Entry<String, JsonElement> e : obj.entrySet())
            arr[Integer.parseInt(e.getKey())] = context.deserialize(e.getValue(), Outer.class);
        return arr;
    }
}

Ta sama klasa Outer i kod testu jak powyżej.

Wyjście

Root[outer=[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]]
2
Andreas 3 kwiecień 2020, 11:51

Zakładam, że Twoje JsonObject to klasa POJO, taka jak:

public Inner[] outer;

Jeśli chcesz mieć tablicę obiektów, możesz zmienić swój kod na:

Inner[] jo = gson.fromJson(json, Inner[].class);
0
Carlos López Marí 3 kwiecień 2020, 10:32

Proszę zapoznać się z poniższym kodem Aby uzyskać tablicę obiektów (externalArray) 2. Możesz wyodrębnić JsonArray (externalJsonArray) zawierający wartości obiektów wewnętrznych w Outer (na wypadek, gdyby klucze nie były istotne do dalszego użycia)

String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().serializeNulls().create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");

Object[] outerArray = outer.entrySet().toArray();
// outerArray: [0={"Attr1":12345,"Attr2":67890}, 1={"Attr1":54321,"Attr2":"09876"}]

JsonArray outerJsonArray = new JsonArray();
outer.keySet().stream().forEach(key -> {
outerJsonArray.add(outer.get(key));
});
//jsonArray=[{"Attr1":12345,"Attr2":67890},{"Attr1":54321,"Attr2":"09876"}]

System.out.println(outer);
System.out.println(outerJsonArray.isJsonArray() + " " + outerJsonArray);
0
Farhad Zamani 3 kwiecień 2020, 13:13
Jackson – Marshall String to JsonNode will be useful in your case.with following pom:- 


    //POM FILE


        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>

//JAVA CODE
    //read json file data to String


     byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));

        //create ObjectMapper instance
        ObjectMapper objectMapper = new ObjectMapper();

        //read JSON like DOM Parser
        JsonNode rootNode = objectMapper.readTree(jsonData);
        JsonNode idNode = rootNode.path("id");
        System.out.println("id = "+idNode.asInt());

        JsonNode phoneNosNode = rootNode.path("phoneNumbers");
        Iterator<JsonNode> elements = phoneNosNode.elements();
        while(elements.hasNext()){
            JsonNode phone = elements.next();
            System.out.println("Phone No = "+phone.asLong());
        }

Możesz użyć metod klasy JsonNode findParent findValue i findPath, które redukują kod w porównaniu z inną biblioteką analizującą.

0
Himanshu Dave 3 kwiecień 2020, 13:08