如何用Gson处理具有相同属性名称的不同数据类型? [英] How to handle different data types with same attribute name with Gson?

查看:399
本文介绍了如何用Gson处理具有相同属性名称的不同数据类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Gson在Java中编写一个RSS提要解析器。我将RSS的XML转换为JSON,然后使用Gson将JSON反序列化为Java POJO(有点迂回,但有其原因)。对于下面列出的Feed#1( BBC )的反序列化,一切正常,但对于下面列出的Feed#2( NPR ),我开始收到异常抛出。



我想我已经发现了这个问题,但我不确定如何解决它:



< hr>

问题在于这两个RSS源(例如):


  1. < a href =http://feeds.bbci.co.uk/news/rss.xml =noreferrer> http://feeds.bbci.co.uk/news/rss.xml

  2. http://www.npr.org /rss/rss.php?id=1001



  3. 对于这些不同的RSS订阅源,名为guid的字段是作为带有2个字段(如 BBC RSS Feed)或b)字符串对象返回(如 NPR RSS Feed)。

    以下是相关JSON的一些转述版本:

    BBC RSS Feed

      //正在返回'guid'对象
    item:
    [
    {
    //为了简洁省略其他字段
    guid:{
    isPermalink:false,
    content:http:\ / \ / www.bbc.co.uk\ / news\ / uk-england-33745057
    },
    },
    {
    // ...
    }
    ]

    NPR RSS Feed

      //正在将'guid'作为字符串返回
    项目:
    [
    {
    //为简洁省略其他字段
    guid:http:\ / \ / www.npr.org\ / sections \ / thetwo-way\ / 2015\ / 07\ / 31\ / 428188125\ /黑猩猩功能于人身保护,语料库的情况下,将-不再视为被使用的换研究?utm_medium = RSS& utm_campaign = news

    {
    // ...
    }
    ]
    pre>




    我正在建模这在Java中是这样的:

      // RSSFeedItem.java 
    private Guid guid;

    // GUID.java
    private boolean isPermalink;
    私人字符串内容;






    所以在这种情况下,

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

    BBC RSS 供稿,但它在解析 NPR RSS 提要。



    导致我得出这是一个类型错误的具体错误如下(当试图反序列化 NPR RSS 供稿):

     严重:com.google.gson.JsonSyntaxException:java.lang。 IllegalStateException:
    期望的BEGIN_OBJECT,但是在第1行的STRING 673路径
    $ .rss.channel.item [0] .guid






    因此,无论如何,至关重要:我如何处理这种情况与Gson,其中一个字段被返回为潜在的不同的数据类型?我猜可能有某种技巧或注释可以用于这种效果,但我不确定,在检查Gson的文档后,我无法找到现成的答案。

    解决案

    下面是我的示例代码,希望大家能有所帮助。



     公众< T>列表与LT; T> readData(InputStream inputStream,Class< T> clazz)抛出异常{
    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();
    休息;
    case BEGIN_OBJECT:
    T data = clazz.cast(gson.fromJson(jsonReader,clazz));
    arrayList.add(data);
    休息;
    case NUMBER:
    Integer number = Integer.parseInt(jsonReader.nextString());
    arrayList.add(number);
    休息;
    默认值:
    jsonReader.close();
    inputStream.close();
    返回Collections.emptyList();
    }
    jsonReader.close();
    inputStream.close();
    return(List< T>)arrayList;
    }

    另一个是 parseRecursive in Streams.java (您可以谷歌搜索)如下:

      private static JsonElement parseRecursive(JsonReader reader)
    throws IOException {
    switch(reader.peek()){
    case STRING:
    return new JsonPrimitive(reader.nextString()) ;
    case NUMBER:
    String number = reader.nextString();
    返回新的JsonPrimitive(JsonPrimitive.stringToNumber(number));
    case BOOLEAN:
    返回新的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();
    返回数组;
    case BEGIN_OBJECT:
    JsonObject object = new JsonObject();
    reader.beginObject(); (reader.hasNext()){
    object.add(reader.nextName(),parseRecursive(reader));
    while
    }
    reader.endObject();
    返回对象;
    case END_DOCUMENT:
    case NAME:
    case END_OBJECT:
    case END_ARRAY:
    default:
    throw new IllegalArgumentException();




    $ b $ p $ UPDATE:你也可以参考 parse(JsonReader reader) in Streams class(gson-2.3.1.jar)



    像这样

      JsonElement jsonElement = Streams.parse(jsonReader); 


    I'm currently writing an RSS feed parser in Java utilizing Gson. I'm converting the RSS' XML into JSON, and then subsequently using Gson to deserialize the JSON into Java POJOs (somewhat roundabout but there's a reason for it). Everything was working fine as far as deserializing for the feed #1 (BBC) listed below, but for the feed #2 (NPR) listed below, I started getting exceptions being thrown.

    I think I have identified the problem, but I'm uncertain as to how to resolve it:


    The issue is arising with these two RSS Feeds (for example):

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

    For these different RSS feeds, a field called "guid" is being returned as either a) an object with 2 fields (as in the BBC RSS Feed) or b) a string (as in the NPR RSS Feed).

    Here's some paraphrased versions of the relevant JSON:

    BBC RSS Feed

    // 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 Feed

    // 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"
        },
        {
          // ...
        }
    ]
    


    I'm modeling this in Java like this:

    // RSSFeedItem.java
    private Guid guid;
    
    // GUID.java
    private boolean isPermalink;
    private String content;
    


    So in this case, it works perfectly fine calling

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

    for the BBC RSS feed, but it throws an exception when parsing the NPR RSS feed.

    The specific error that led me to the conclusion that this is a type error was the following (when trying to deserialize the 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
    


    So anyway, to the point: how can I handle this situation with Gson, where a field is being returned as potentially different data types? I'm guessing there might be some sort of trick or annotation I could use to this effect, but I'm not certain and after checking the documentation for Gson I couldn't find a readily available answer.

    解决方案

    Here is my sample code, hope you find it helpful

    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;        
        }
    

    Another one is parseRecursive in Streams.java (you can Google search) as below:

    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();
            }
        }
    

    UPDATE: you can also refer to parse(JsonReader reader) in Streams class (gson-2.3.1.jar)

    Like this

    JsonElement jsonElement = Streams.parse(jsonReader);
    

    这篇关于如何用Gson处理具有相同属性名称的不同数据类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆