【开发笔记】使用gson对一个json实体会出现object或者array不规则返回的处理

背景:聚合网址的免费天气,当有数据的时候是object,没数据的时候是array,对于这种情况,习惯于使用retrofit来说都是很痛苦的。通常我们习惯于接口数据必须是规则的,要么只是object,要么只是array。对于这种不规则的返回,还是有办法去解决的,在使用gson的条件下。解决的核心代码在最后面。

调用

主要看 testApple这个类,会有几种不同的值。

  1. { } object型

  2. [] array型

    Gson gson = new GsonBuilder().registerTypeAdapter(TestPeople.class, new MyDeserializer()).create();
    String ssArray = “{"name":"333","id":"18","testPeople":{"name":"222","testApple":[]}}”;
    System.out.println(ssArray);
    String ssArray2 = “{"name":"333","id":"18","testPeople":{"name":"222","testApple":[{"name":"111","id":"9"}]}}”;
    System.out.println(ssArray2);
    String ssObject = “{"name":"333","id":"18","testPeople":{"name":"222","testApple":{"name":"111","id":"9"}}}”;
    System.out.println(ssObject);
    TestHouse testHouseArray = gson.fromJson(ssArray, TestHouse.class);
    TestHouse testHouseArray2 = gson.fromJson(ssArray2, TestHouse.class);
    TestHouse testHouseObject = gson.fromJson(ssObject, TestHouse.class);
    System.out.println(“result=” + testHouseArray.toString());
    System.out.println(“result=” + testHouseArray2.toString());
    System.out.println(“result=” + testHouseObject.toString());

输出内容

根据testApple可以看到,确实可以根据不同的输入正确解析出来。

{"name":"333","id":"18","testPeople":{"name":"222","testApple":[]}}
{"name":"333","id":"18","testPeople":{"name":"222","testApple":[{"name":"111","id":"9"}]}}
{"name":"333","id":"18","testPeople":{"name":"222","testApple":{"name":"111","id":"9"}}}
result=TestHouse{name='333', id='18', testPeople=TestPeople{name='222', testApple=null}}
result=TestHouse{name='333', id='18', testPeople=TestPeople{name='222', testApple=TestApple{name='111', id='9'}}}
result=TestHouse{name='333', id='18', testPeople=TestPeople{name='222', testApple=TestApple{name='111', id='9'}}}

最外层实体

为了演示用,构造了一个最外层的实体。

public class TestHouse {
    private String name;
    private String id;
    private TestPeople testPeople;

    public TestHouse(String name, String id, TestPeople testPeople) {
        this.name = name;
        this.id = id;
        this.testPeople = testPeople;
    }

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

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

    public TestPeople getTestPeople() {
        return testPeople;
    }

    public void setTestPeople(TestPeople testPeople) {
        this.testPeople = testPeople;
    }

    @Override
    public String toString() {
        return "TestHouse{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", testPeople=" + testPeople +
                '}';
    }
}

第二层实体

为了演示用,构造了一个第二层的实体。这里就直接涉及到不规则实体的容器了。

public class TestPeople {
    private String name;
    private TestApple testApple;

    public TestPeople() {
    }

    public TestPeople(String name, TestApple testApple) {
        this.name = name;
        this.testApple = testApple;
    }

    public String getName() {
        return name;
    }

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

    public TestApple getTestApple() {
        return testApple;
    }

    public void setTestApple(TestApple testApple) {
        this.testApple = testApple;
    }

    @Override
    public String toString() {
        return "TestPeople{" +
                "name='" + name + '\'' +
                ", testApple=" + testApple +
                '}';
    }
}

最内层实体

不规则值的实体,有可能是object,也有可能是array。

public class TestApple {
    private String name;
    private String id;


    public TestApple(String name, String id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

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

    @Override
    public String toString() {
        return "TestApple{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                '}';
    }
}

自定义的JsonDeserializer

主要是为了解析有争议的实体,针对不同的情况去做相关的处理,最后输出同一个最外层实体。

public class MyDeserializer implements JsonDeserializer<TestPeople> {
    @Override
    public TestPeople deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        JsonElement jsonElementApple = jsonElement.getAsJsonObject().get("testApple");
        if (jsonElementApple == null) {
            return null;
        }
        if (jsonElementApple.isJsonObject()) {
            return new Gson().fromJson(jsonElement, TestPeople.class);
        } else {
            List<TestApple> testApple = jsonDeserializationContext.deserialize(jsonElementApple, new TypeToken<List<TestApple>>() {}.getType());
            Gson gson = new Gson();
            Map map = jsonDeserializationContext.deserialize(jsonElement, Map.class);
            if (map.containsKey("testApple")) {
                map.remove("testApple");
            }
            JsonElement jsonElementMixed = gson.toJsonTree(map);
            TestPeople testPeople = gson.fromJson(jsonElementMixed, TestPeople.class);
            if (testApple.size() > 0) {
                testPeople.setTestApple(testApple.get(0));
            }
            return testPeople;
        }
    }
}