简体   繁体   English

使用Gson从JSON文件中检索嵌套对象

[英]Retrieving nested objects from a JSON file using Gson

I'm trying to create a cache for a game using JSON files. 我正在尝试使用JSON文件为游戏创建缓存。 Writing and retrievng this data would be done by using GSON. 写入和检索该数据将通过使用GSON完成。 I have a JSON file containing multiple objects, within these objects other objects are stored as well. 我有一个包含多个对象的JSON文件,在这些对象内还存储了其他对象。

My question is: how do I retrieve this data the best way? 我的问题是:如何以最佳方式检索此数据?

Object 1: 对象1:

public class GameItem {

    private final int id;
    private final String name;
    private final String description;
    private final int shopValue;
    private final ItemStats stats;

    public GameItem(int id, String name, String description, int shopValue, ItemStats stats) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.shopValue = shopValue;
        this.stats = stats;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public int getShopValue() {
        return shopValue;
    }

    public ItemStats getStats() {
        return stats;
    }

}

Object 2: 对象2:

public class ItemStats {

    private final int stabAttack;
    private final int slashAttack;
    private final int crushAttack;
    private final int magicAttack;
    private final int rangeAttack;
    private final int stabDefence;
    private final int slashDefence;
    private final int crushDefence;
    private final int magicDefence;
    private final int rangeDefence;
    private final int strengthBonus;
    private final int prayerBonus;

    public ItemStats(int stabAttack, int slashAttack, int crushAttack, int magicAttack, int rangeAttack, int stabDefence, int slashDefence, int crushDefence, int magicDefence, int rangeDefence, int strengthBonus, int prayerBonus) {
        this.stabAttack = stabAttack;
        this.slashAttack = slashAttack;
        this.crushAttack = crushAttack;
        this.magicAttack = magicAttack;
        this.rangeAttack = rangeAttack;
        this.stabDefence = stabDefence;
        this.slashDefence = slashDefence;
        this.crushDefence = crushDefence;
        this.magicDefence = magicDefence;
        this.rangeDefence = rangeDefence;
        this.strengthBonus = strengthBonus;
        this.prayerBonus = prayerBonus;
    }

    public int getStabAttack() {
        return stabAttack;
    }

    public int getSlashAttack() {
        return slashAttack;
    }

    public int getCrushAttack() {
        return crushAttack;
    }

    public int getMagicAttack() {
        return magicAttack;
    }

    public int getRangeAttack() {
        return rangeAttack;
    }

    public int getStabDefence() {
        return stabDefence;
    }

    public int getSlashDefence() {
        return slashDefence;
    }

    public int getCrushDefence() {
        return crushDefence;
    }

    public int getMagicDefence() {
        return magicDefence;
    }

    public int getRangeDefence() {
        return rangeDefence;
    }

    public int getStrengthBonus() {
        return strengthBonus;
    }

    public int getPrayerBonus() {
        return prayerBonus;
    }
}

JSON data: JSON数据:

[
    {
        "id": 0,
        "name": "Dwarf_remains",
        "description": "The_body_of_a_Dwarf_savaged_by_Goblins.",
        "shopValue": 1,
        "stats": [
            "stabAttack": 0,
            "slashAttack": 0,
            "crushAttack": 0,
            "magicAttack": 0,
            "rangeAttack": 0,
            "stabDefence": 0,
            "slashDefence": 0,
            "crushDefence": 0,
            "magicDefence": 0,
            "rangeDefence": 0,
            "strengthBonus": 0,
            "prayerBonus": 0
        ]
    },
    {
        "id": 1,
        "name": "Toolkit",
        "description": "Good_for_repairing_a_broken_cannon.",
        "shopValue": 1,
        "stats": [
            "stabAttack": 0,
            "slashAttack": 0,
            "crushAttack": 0,
            "magicAttack": 0,
            "rangeAttack": 0,
            "stabDefence": 0,
            "slashDefence": 0,
            "crushDefence": 0,
            "magicDefence": 0,
            "rangeDefence": 0,
            "strengthBonus": 0,
            "prayerBonus": 0
        ]
    },
    {
        "id": 2,
        "name": "Cannonball",
        "description": "Ammo_for_the_Dwarf_Cannon.",
        "shopValue": 3000,
        "stats": [
            "stabAttack": 0,
            "slashAttack": 0,
            "crushAttack": 0,
            "magicAttack": 0,
            "rangeAttack": 0,
            "stabDefence": 0,
            "slashDefence": 0,
            "crushDefence": 0,
            "magicDefence": 0,
            "rangeDefence": 0,
            "strengthBonus": 0,
            "prayerBonus": 0
        ]
    }
]

There can be no "the best" way since it may depend on your real case. 不可能有“最佳”方法,因为这可能取决于您的实际情况。 But in order to deserialize and serialize back this object efficiently, you have to: 但是为了有效地反序列化和序列化此对象,您必须:

  • First off, fix your JSON file 首先,修复您的JSON文件

Because it's syntactically illegal: the stats property should be declared as an object enclosed with { and } (not as an array with [ and ] ): 因为它在语法上是非法的: stats属性应声明为用{}包围的对象(而不是使用[]的数组):

"stats": {
    "stabAttack": 0,
    "slashAttack": 0,
    "crushAttack": 0,
    "magicAttack": 0,
    "rangeAttack": 0,
    "stabDefence": 0,
    "slashDefence": 0,
    "crushDefence": 0,
    "magicDefence": 0,
    "rangeDefence": 0,
    "strengthBonus": 0,
    "prayerBonus": 0
}
  • Tell Gson the real type of the array elements using a proper TypeToken 使用适当的TypeToken告诉Gson数组元素的真实类型

This is a special Gson mechanism to specify the target type (various libraries use similar techniques). 这是一种特殊的Gson机制,用于指定目标类型(各种库使用类似的技术)。 Specifying List.class as the type of the source won't work and essentially results in List<Map<String, Object>> due to how Java generics work (type parameterization can only be written to classes, fields, or methods, but not directly to instances unless they have enough type information themselves or use custom deserializers that are aware of where such information can be gained from [say, a special synthetic field]). 由于Java泛型的工作方式List<Map<String, Object>>List.class指定为源类型将不起作用,并且实际上会导致List<Map<String, Object>> (类型参数化只能写入类,字段或方法,而不能写入类型参数)除非它们本身具有足够的类型信息,或者使用自定义反序列化程序,这些自定义反序列化程序可从[例如,特殊的合成字段]中获取此类信息,否则将直接指向实例。

private static final TypeToken<List<GameItem>> listOfGamesTypeToken = new TypeToken<List<GameItem>>() {
};

Note that type tokens are thread-safe (as well as Gson instances are) and can be easily shared globally (but wisely). 请注意,类型令牌是线程安全的(与Gson实例一样),并且可以轻松地在全局范围内共享(但明智地)。

  • Apply buffered reading and writing from and to I/O streams 对I / O流应用缓冲的读写操作

The best way to deserialize using Gson instances is reading from Reader or JsonReader (both work with streams perfectly). 使用Gson实例反序列化的最佳方法是从ReaderJsonReader读取(两者都可以完美地使用流)。 The same goes to Writer and JsonWriter . WriterJsonWriter

private static List<GameItem> readGameItemsFromFile(final File file)
        throws IOException {
    try ( final InputStream inputStream = new FileInputStream(file);
          final Reader reader = new BufferedReader(new InputStreamReader(inputStream)) ) {
        // Note that this .fromJson overload:
        // - does not require an intermediate string to be collected and then parsed (a common misuse of Gson parsing facilities)
        // - specifies the target list element type because List.class is just a class, 
        return gson.fromJson(reader, listOfGamesTypeToken.getType());
    }
}

private static void writeGameItemsToFile(final List<GameItem> gameItems, final File file)
        throws IOException {
    try ( final OutputStream outputStream = new FileOutputStream(file);
          final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)) ) {
        // Note that this .toJson overload:
        // - allows to "calibrate" the source list type more precisely
        // - does not require an intermediate JSON string collected into memory and then flushed to a file (another common misuse)
        gson.toJson(gameItems, listOfGamesTypeToken.getType(), writer);
    }
}

public static void main(final String... args)
        throws IOException {
    final File file = new File("gameItems.json");
    final List<GameItem> gameItems = readGameItemsFromFile(file);
    // ... process the game items here ...
    writeGameItemsToFile(gameItems, file);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM