当前位置: 首页 > 面试题库 >

如何使用Gson处理具有相同属性名称的不同数据类型?

吕鸿文
2023-03-14
问题内容

我目前正在使用Gson用Java编写RSS feed解析器。我正在将RSS的XML转换为JSON,然后使用Gson将JSON反序列化为Java
POJO(有点回旋,但是有原因)。就下面列出的Feed#1( BBC )进行反序列化而言,一切工作正常,但是对于下面列出的Feed#2(
NPR ),我开始抛出异常。

我认为我已经确定了问题,但不确定如何解决该问题:

这是由于以下两个RSS Feed(例如)引起的:

  1. http://feeds.bbci.co.uk/news/rss.xml
  2. http://www.npr.org/rss/rss.php?id=1001

对于这些不同的RSS提要,将返回一个称为“ guid”的字段,作为a)具有2个字段 的对象 (如 BBC RSS 提要)或b) 字符串 (如
NPR RSS 提要)。

以下是相关JSON的一些释义版本:

英国广播公司RSS提要

// is returning 'guid' as an object
"item" : 
[
    {
        // omitted other fields for brevity
        "guid" : {
            "isPermalink" : false,
            "content" : "http:\/\/www.bbc.co.uk\/news\/uk-england-33745057"
        },
    },
    {
        // ...
    }
]

NPR RSS提要

// is returning 'guid' as a string
"item" : 
[
    {
      // omitted other fields for brevity
      "guid" : "http:\/\/www.npr.org\/sections\/thetwo-way\/2015\/07\/31\/428188125\/chimps-in-habeas-corpus-case-will-no-longer-be-used-for-research?utm_medium=RSS&utm_campaign=news"
    },
    {
      // ...
    }
]

我在Java中这样建模:

// RSSFeedItem.java
private Guid guid;

// GUID.java
private boolean isPermalink;
private String content;

因此,在这种情况下,它可以很好地调用

Gson gson = new Gson();
RssFeed rssFeed = gson.fromJson(jsonData, RssFeed.class);

用于 BBC RSS 提要,但在解析 NPR RSS 提要时会引发异常。

导致我得出这是类型错误的结论的特定错误如下(当尝试反序列化 NPR RSS feed时):

Severe:    com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
           Expected BEGIN_OBJECT but was STRING at line 1 column 673 path
           $.rss.channel.item[0].guid

因此,无论如何,关键点是: 我如何使用Gson处理这种情况,在该情况下,字段将作为潜在的不同数据类型返回?
我猜测可能会使用某种技巧或注释来达到这种效果,但是我不确定,在查看了Gson的文档后,我找不到一个容易得到的答案。


问题答案:

这是我的示例代码,希望对您有所帮助

public <T> List<T> readData(InputStream inputStream, Class<T> clazz) throws Exception {        
            ArrayList<Object> arrayList = new ArrayList<>();            
            GsonBuilder gsonBuilder = new GsonBuilder();
            Gson gson = gsonBuilder.create();
            JsonReader jsonReader = new JsonReader(new InputStreamReader(inputStream, "UTF_8"));
            jsonReader.setLenient(true);
            JsonToken jsonToken = jsonReader.peek();
            switch (jsonToken) {
                case BEGIN_ARRAY:
                    jsonReader.beginArray();
                    while (jsonReader.hasNext()) {
                        arrayList.add(gson.fromJson(jsonReader, clazz));
                    }
                    jsonReader.endArray();
                    break;
                case BEGIN_OBJECT:
                    T data = clazz.cast(gson.fromJson(jsonReader, clazz));
                    arrayList.add(data);
                    break;
                case NUMBER:
                    Integer number = Integer.parseInt(jsonReader.nextString());
                    arrayList.add(number);
                    break;
                default:
                    jsonReader.close();
                    inputStream.close();
                    return Collections.emptyList();
            }
            jsonReader.close();
            inputStream.close();
            return (List<T>) arrayList;        
    }

另一个parseRecursive位于Streams.java(您可以通过Google搜索),如下所示:

private static JsonElement parseRecursive(JsonReader reader)
            throws IOException {
        switch (reader.peek()) {
        case STRING:
            return new JsonPrimitive(reader.nextString());
        case NUMBER:
            String number = reader.nextString();
            return new JsonPrimitive(JsonPrimitive.stringToNumber(number));
        case BOOLEAN:
            return new JsonPrimitive(reader.nextBoolean());
        case NULL:
            reader.nextNull();
            return JsonNull.createJsonNull();
        case BEGIN_ARRAY:
            JsonArray array = new JsonArray();
            reader.beginArray();
            while (reader.hasNext()) {
                array.add(parseRecursive(reader));
            }
            reader.endArray();
            return array;
        case BEGIN_OBJECT:
            JsonObject object = new JsonObject();
            reader.beginObject();
            while (reader.hasNext()) {
                object.add(reader.nextName(), parseRecursive(reader));
            }
            reader.endObject();
            return object;
        case END_DOCUMENT:
        case NAME:
        case END_OBJECT:
        case END_ARRAY:
        default:
            throw new IllegalArgumentException();
        }
    }

更新:您也可以parse(JsonReader reader)Streams类(gson-2.3.1.jar)中引用

像这样

JsonElement jsonElement = Streams.parse(jsonReader);


 类似资料:
  • 问题内容: 我正在尝试使用RSA 7.5和Websphere 7服务器开发IBM JAX_WS Web服务。因为我是一个初学者,所以我遵循Java类优先方法,即首先创建Java类,然后生成WSDL文件。 当我尝试创建wsdl文件时,出现异常: java.security.PrivilegedActionException:com.sun.xml.internal.bind.v2.runtime.I

  • 问题内容: 我今天在另一个问题中提出了这个问题,但是 由于措辞的方式,恐怕无法解决任何问题。 我有一个json输入,其中包含以下数据: 杰森 如您所见,option_value项是一个对象中的Array和 另一个对象中的简单字符串。 我怎样才能让Gson正确处理呢?我的类将此描述为 List对象,因此它适用于option_value是 数组的前几个项目,但是当它成为字符串时,应用程序崩溃,并且我收

  • API调用 API响应equation_list字段包含整数数组或字符串。例如: 但我有个例外 com.google.gson.java.lang.IllegalStateException:预期BEGIN_ARRAY但在第1行第1586列路径$[5]处是STRING。equation_list 我如何满足我的要求?

  • 假设您有2个包,并且有名为-Test的公共类。 第一个包。测试 第二包测试 它们中的每一个都有实例变量-x。 在第一种情况下-int x=2; 在第二种情况下-int x=3; 我想导入FirstPackage。在第二个包内测试。测试并打印值为2的x。 我的代码: 但是输出是3。如何打印?

  • 我有一个PDF文件,其中包含一个表单,其中的字段具有相同的字段名。这是为了共享文档中的数据而做的。例如,我有合同,此文档的每一页都必须有公司名称,我将公司名称写在一个表单字段中,并将其复制到当前文档的所有页面,但是当我尝试使用库阅读此文档时,我没有得到此数据,因为只创建一个字段名为的字段,而另一个字段名为clean。 如何使用库读取具有相同字段名称的字段?

  • 问题内容: 我有一个REST API,它返回JSON响应为: 有时它返回: 我有一个像这样的POJO: 那么,有没有一种方法(不是写你自己的其他 自定义解串器 中)Jackson2,这将有助于我映射在JSON来时,它的A型和类型时,它是一个JSON对象? 或者换句话说,在Jackson中,有没有一种方法可以按变量而不是by 映射? 问题答案: 我可以建议您像这样使用JsonNode: 或像这样 :