使用 Gson 自定义反序列化

Custom deserialization with Gson

我一直在努力改进我的代码,但不知道如何,我得到的 json 是这样的:

{   
"name": "Jhon",
"lastName": "Smith",
"clothes": {
    "gender":"male",
    "Shirt": {
        "id": 113608,
        "name": "Green Shirt",
        "size": "Large"
    },
    "Pants": {
        "id": 115801,
        "name": "Black Leather Pants",
        "size": "Large"
       }
    }
}

到目前为止,它的工作方式是同时拥有衬衫和裤子 class,但由于它们是相同的,所以我尝试只使用一件 class 来获得两者 them.I没有人说 json 是如何生成的,所以必须在它出现时使用它。

这是我的 classes:

Class个人

public class Person{
    private String lastName;
    private String name;
    private Clothes clothes;
}

Class衣服

public class Clothes{
    private Shirt Shirt;
    private Pants pants;
    private String gender;
}

Class 衬衫

public class Shirt{
    private String id;
    private String name;
    private String size;
}

裤子和衬衫一样,问题是我不希望我的代码被破坏if/when他们决定添加另一件衣服,所以我正在尝试做这样的事情

Class衣服

public class Clothes{
    private List<Something> clothList;
    private String gender;
}

不要使用 2 个单独的 classes(ShirtPants),只需使用一个 class - 让我们说 Cloth。试了一下,效果很好:

人class:

package com.dominikangerer.q29550820;

public class Person {
    private String name;
    private String lastName;
    private Clothes clothes;
}

衣服class:

package com.dominikangerer.q29550820;

public class Clothes {
    private String gender;
    private Cloth Shirt;
    private Cloth Pants;        
}

布料class:

package com.dominikangerer.q29550820;

public class Cloth {
    private Integer id;
    private String name;
    private String size;
}

在构建这些 classes 之后,我直接在一个小的 main class 中尝试了它,这导致了一个非常好的反序列化。

Gson g = new Gson();
Person person = g.fromJson("{\"name\":\"Jhon\",\"lastName\":\"Smith\",\"clothes\":{\"gender\":\"male\",\"Shirt\":{\"id\":113608,\"name\":\"Green Shirt\",\"size\":\"Large\"},\"Pants\":{\"id\":115801,\"name\":\"Black Leather Pants\",\"size\":\"Large\"}}}", Person.class);

这里没有使用 @Expose@SerializedName("something") 因为不需要。

希望它能帮到你 - 否则请更详细地解释你的问题,我会尽力帮助你。

------------更新------------

好吧,通常很容易投出一个 Json,因为你在正常的 Object 中有它 - 但东西在地图内部 (clothes) 你也有一个正常 String 值。为此,我建议您启用 Gson 功能 @Expose 我稍后会告诉您为什么这是个好主意。

让我们开始吧: 我用 Map<String, Object> 删除了 Clothes class,Gson 可以轻松反序列化 - 这里的问题是我们在该地图中也有性别。我修改了 Person class,现在它是这样工作的:

人 v2:

package com.dominikangerer.q29550820;

public class Person {
    private String name;

    private String lastName;

    @SerializedName("clothes")
    private Map<String, Object> clothesWrapper;

    public String getGender() {
        return clothesWrapper.get("gender").toString();
    }

    public void setGender(String gender) {
        this.clothesWrapper.put("gender", gender);
    }
}

现在我们已经可以将 gender 映射为 String 并用 getter 和 setter 对其进行修改 - 上面仍然有包含 Object秒。接下来我们不想要 Map<String, Object> - 对于反序列化和序列化它完全没问题 - 但对于使用 Cloths 本身 - 它很愚蠢所以让我们用最简单的方法摆脱它:

我们像这样修改我们的 Person class:

人 v3:

package com.dominikangerer.q29550820;

public class Person {
    @Expose
    private String name;

    @Expose
    private String lastName;

    @Expose
    @SerializedName("clothes")
    private Map<String, Object> clothesWrapper;

    private Map<String, Cloth> clothes;

    public String getGender() {
        return clothesWrapper.get("gender").toString();
    }

    public void setGender(String gender) {
        this.clothesWrapper.put("gender", gender);
    }

    public Map<String, Cloth> getClothes() {
        if (clothes == null) {
            Gson g = new Gson();
            clothes = new HashMap<String, Cloth>();
            for (Entry<String, Object> entry : clothesWrapper.entrySet()) {
                if (entry.getKey().equals("gender")) {
                    continue;
                }
                String helper = g.toJson(entry.getValue());
                Cloth cloth = g.fromJson(helper, Cloth.class);
                clothes.put(entry.getKey(), cloth);
            }
        }
        return clothes;
    }
}

如您所见,我们现在间接转换所有 Clothes - 我们必须这样做,因为这是将所有 LinkedTreeMap 转换为 Cloth 的最简单方法-Object 没有 运行 变成了 ClassCastException。如您所见,我们现在有一个 Map<String,Object> clothesWrapper 让 Gson 解析对象(找不到更好的名称 - 抱歉)和没有 Expose 的 Map<String, Cloth> clothes 映射。现在您还需要使用 enableExpose 选项设置 Gson,其工作方式如下:

(在这里使用 Person v3 Class - 只需调试它 - 就像一个魅力)

public class Main {
    public static void main(String[] args) {
        Gson g = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        Person person = g.fromJson("{\"name\":\"Jhon\",\"lastName\":\"Smith\",\"clothes\":{\"gender\":\"male\",\"Shirt\":{\"id\":113608,\"name\":\"Green Shirt\",\"size\":\"Large\"},\"Pants\":{\"id\":115801,\"name\":\"Black Leather Pants\",\"size\":\"Large\"}}}", Person.class);
        System.out.println(person.getClothes());
        System.out.println(person.getGender());
    }
}

您可以在 github repository

中找到所有 class