Gson:反序列化链接对象的列表

时间:2018-01-18 14:28:31

标签: java json jackson kotlin gson

我有两个描述所有数据的类和一个描述数据类型的枚举

class Category(val name: String,
               val id: String,
               val type: CategoryType,
               val items: List<Item>)

class Item(val name: String,
           val id: String,
           val type: CategoryType,
           val data: Any?,
           val categoryIds: Array<String>)

enum class CategoryType {
    TYPE_A,
    TYPE_B,
    TYPE_C
}

并遵循JSON输入

{
  "categories": [
    {
      "id": "category_id_1",
      "name": "Category 1",
      "type1": "TYPE_A",
      "type2": "TYPE_C"
    },
    {
      "id": "category_id_2",
      "name": "Category 2",
      "type1": "TYPE_B"
    },
    {
      "id": "category_id_3",
      "name": "Category 3",
      "type1": "TYPE_A"
    },
    {
      "id": "category_id_4",
      "name": "Category 4",
      "type1": "TYPE_C"
    }
  ],
  "items": [
    {
      "id": "item_id_1",
      "name": "Item 1",
      "type2": "TYPE_A",
      "categoryIds": [
        "category_id_4",
        "category_id_3"
      ]
    },
    {
      "id": "item_id_2",
      "name": "Item 2",
      "type1": "TYPE_C",
      "categoryIds": [
        "category_id_1"
      ]
    }
  ]
}

有两个主要要求:

  1. 我需要创建两个Category的实例,如果有的话id 在那里列出了type1type2
  2. 如果项目具有相同的Item和/或Categorytype1的{​​{},我需要在每个type2个实例中放置Category的相同实例1}}列在id的{​​{1}}。
  3. 对于每个Item,我可以使用任何类型的容器,例如categoryIds

    所以问题是:如果不使用庞大的CategoryType构造,我怎么能这样做呢?是否可以使用val typedAsTYPE_A: List<Category>完成,或者我应该使用类似com.google.gson.JsonDeserializer的内容?

2 个答案:

答案 0 :(得分:0)

这适用于您提供的Json。

Gson gson = new Gson();
String json = YOURJSON
ContainerObject myObj = gson.fromJson(json, ContainerObject.class);
//above code is placed where you want to deserialize the object

import java.util.ArrayList;

public class ContainerObject {
    private ArrayList<Categories> categories;
    private ArrayList<Item> items;

    public ContainerObject(){

    }

    public ArrayList<Categories> getCategories() {
        return categories;
    }

    public void setCategories(ArrayList<Categories> categories) {
        this.categories = categories;
    }

    public ArrayList<Item> getItems() {
        return items;
    }

    public void setItems(ArrayList<Item> items) {
        this.items = items;
    }

}

import java.util.List;

public class Categories {
    private String id;
    private String name;
    private CategoryType type1;
    private CategoryType type2;

    public Categories(){

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public CategoryType getType1() {
        return type1;
    }

    public void setType1(CategoryType type1) {
        this.type1 = type1;
    }

    public CategoryType getType2() {
        return type2;
    }

    public void setType2(CategoryType type2) {
        this.type2 = type2;
    }

}


import java.util.ArrayList;

public class Item {
    private String id;
    private String name;
    private CategoryType type1;
    private CategoryType type2;
    private ArrayList<String> categoryIds;

    public Item(){

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public CategoryType getType1() {
        return type1;
    }

    public void setType1(CategoryType type1) {
        this.type1 = type1;
    }

    public CategoryType getType2() {
        return type2;
    }

    public void setType2(CategoryType type2) {
        this.type2 = type2;
    }

    public ArrayList<String> getCategoryIds() {
        return categoryIds;
    }

    public void setCategoryIds(ArrayList<String> categoryIds) {
        this.categoryIds = categoryIds;
    }
}


public enum CategoryType {
    TYPE_A,
    TYPE_B,
    TYPE_C
}

答案 1 :(得分:0)

免责声明:我对Gson并不熟悉,但既然你想使用它,我就试着把它放在一起。最有可能有更好的方法来实现相同的结果。代码可能不健壮,可能包含错误。

我希望我的代码足够可理解。基本上就是这些步骤:

  1. 使用Gson解析com.google.gson.JsonObject
  2. 使用JsonObject迭代每个项目并将其添加到适当的列表中(如果不存在则创建列表)
  3. 遍历每个类别并使用已生成的列表添加项目
  4. 以下是代码:

    // Helper extension property for easily mapping Strings
    // to their enum CategoryType
    val String.catType: CategoryType?
        get() = CategoryType.values().find { it.toString() == this }
    
    fun deserialize(json: String): Map<CategoryType, List<Category>> {
        // initialize the return value
        val categories = CategoryType.values().map { it to (mutableListOf<Category>()) }.toMap()
        // parse json
        val input = Gson().fromJson(json, com.google.gson.JsonObject::class.java)
    
    
        // accumulate itemLists for constructing Categories later
        // those lists will be looked up via CategoryType and CategoryId
        val itemLists = CategoryType.values().map { it to (mutableMapOf<String, MutableList<Item>>()) }.toMap()
        input["items"].asJsonArray.map { it.asJsonObject }.forEach { item ->
            // read properties for item
            val types = item.entrySet().filter { it.key.startsWith("type") }.map { it.value.asString.catType }
            val ids = item.getAsJsonArray("categoryIds").map { it.asString }
            val name = item["name"].asString
            val item_id = item["id"].asString
            val data = item["data"]
            //
            types.forEach { type ->
                type?.let {
                    val itemObj = Item(name, item_id, type, data, ids.toTypedArray())
                    ids.forEach { id ->
                        with(itemLists[type]!!) {
                            if (!this?.containsKey(id)) this[id] = mutableListOf(itemObj)
                            else this[id]?.add(itemObj)
                        }
                    }
                }
            }
        }
    
        // go through all categories and create appropriate objects
        input["categories"].asJsonArray.map { it.asJsonObject }.forEach { cat ->
            val id = cat["id"].asString
            val name = cat["name"].asString
            val types = cat.entrySet().filter { it.key.startsWith("type") }.map { it.value.asString.catType }
            types.forEach { type ->
                type?.let {
                    categories[type]
                            ?.add(Category(
                                    name = name,
                                    id = id,
                                    type = type,
                                    items = itemLists[type]?.get(id) ?: listOf()))
                }
            }
        }
    
        return categories
    }