美文网首页
Gson教程三(译):Arrays和Lists的映射

Gson教程三(译):Arrays和Lists的映射

作者: WeberLisper | 来源:发表于2017-10-23 13:37 被阅读257次

    该文章翻译自Gson Tutorial Series系列教程。该篇主要阐述了如何使用Gson映射Arrays和List集合对象。

    Arrays和Lists之间的不同

    在进入正题之前,我们想阐述一下Arrays和Lists这两种Java数据结构。他们的Java实现是不同的并且各有各的优势。在你的用例中采取哪种方式取决于软件需求以及你个人的喜好。有趣的是,什么是选择list还是array结构映射到JSON是无关紧要的。

    在JSON的数据格式中,没有lists和arrays。是的,Java的实现造成了二者之间巨大的区别,但在就高层次来说,他们都是代表相同的列表结构。在接下来的博客中,我们将他们成为对象列表,但是在Java中他们又是不同的。如果你对此感到迷惑,不用担心,一些例子将会使你更加清晰。

    Arrays或者Lists数据的序列化

    还记得前一篇博客中关于嵌套对象的restaurant模型吗?现在是时候为它增加一个菜单了。我们想要知道美味食物的价格。一个饭店的菜单可以看成是菜单项的列表结构。每一项都是可供顾客点单的。在我们的简易饭店中,每一项都包括描述和价格。

    提示:我们没有考虑菜品分类,组合套餐以及配菜,这使我们的例子足够简单。这很明显不是一个完美的模型,因此不要在你的商业饭店App中使用它……

    如果我们考虑怎样具体实现其Java模型,我们将得到接近如下的代码:

    public class RestaurantWithMenu {  
        String name;
    
        List<RestaurantMenuItem> menu;
        //RestaurantMenuItem[] menu; // alternative, either one is fine
    }
    
    public class RestaurantMenuItem {  
        String description;
        float price;
    }
    

    Java处理嵌套对象的方式和JSON是不同的。Java可以将之分离到不同的类中,并由List或者Array的来持有其引用。JSON需要保持一个本地的、嵌套的列表。这意味着在高层次,我们希望JSON像下面这样:

    {
      "name": "Future Studio Steak House",
      "menu": [
        ...
      ]
    }
    

    就像嵌套对象一样,menu并不拥有一个直接的值。相反,JSON为其值定义了一个由[]包裹着的对象列表。如上面提到的,这是array还是list是没有区别的。在JSON的数据结构中它看起来是相同的。

    menu由很多对象组成。在我们的例子中,它们是饭店菜单项。让我们运行Gson查看一个完整的JSON会是什么样子。

    我们希望你现在已经知道常规步骤了。得到你的Java对象,初始化Gson然后让Gson创建相应的JSON:

    List<RestaurantMenuItem> menu = new ArrayList<>();  
    menu.add(new RestaurantMenuItem("Spaghetti", 7.99f));  
    menu.add(new RestaurantMenuItem("Steak", 12.99f));  
    menu.add(new RestaurantMenuItem("Salad", 5.99f));
    
    RestaurantWithMenu restaurant =  
            new RestaurantWithMenu("Future Studio Steak House", menu);
    
    Gson gson = new Gson();  
    String restaurantJson = gson.toJson(restaurant);
    

    restaurantJson包含如下内容:

    {
      "menu": [
        {
          "description": "Spaghetti",
          "price": 7.99
        },
        {
          "description": "Steak",
          "price": 12.99
        },
        {
          "description": "Salad",
          "price": 5.99
        }
      ],
      "name": "Future Studio Steak House"
    }
    

    就跟通常一样,排序有点神奇,列表排在前面是因为按字母来说menu在name的前面。除了排序意外,其他一切都是我们希望的。列表(由[]包裹)包含多个对象(每一个对象由{}包裹)。

    然而,我们并不总是发送一个嵌套了列表数据的单独对象,就像上面做的那样。有时候我们也希望发送一个列表。当然,Gson同样支持JSON列表的序列化。例如,如果我们希望序列化如下菜单项列表:

    List<RestaurantMenuItem> menu = new ArrayList<>();  
    menu.add(new RestaurantMenuItem("Spaghetti", 7.99f));  
    menu.add(new RestaurantMenuItem("Steak", 12.99f));  
    menu.add(new RestaurantMenuItem("Salad", 5.99f));
    
    Gson gson = new Gson();  
    String menuJson = gson.toJson(menu);  
    

    将会得到如下结果:

    [
      {
        "description": "Spaghetti",
        "price": 7.99
      },
      {
        "description": "Steak",
        "price": 12.99
      },
      {
        "description": "Salad",
        "price": 5.99
      }
    ]
    

    让我们指出重要的不同之处:该JSON的首个字符为[,这就提示了接下来是对象列表!到目前为止,我们只看到由{开始的对象。你应该马上记住它们之间的差异。你将总是需要它并在下一章节马上回用到,如果你继续阅读的话。

    Arrays或者Lists的序列化和反序列化

    在第二部分我们学习反序列化。换句话说,我们如何使用Gson映射JSON结构中的列表到Java对象。在之前的例子中,我们看到了JSON数据中作为根列表和嵌套在对象中的列表的重要不同。

    列表作为根对象

    让我们做一个练习。考虑这样一种情况,在未来的环境中我们将会开启自己的API,并会提供一个端口GET /founders。该端口将返回三个对象的数组,每个对象包含一个name域和一个flowerCount域。该数组代表我们桌子上的植物。因此如下JSON列表:

    [
        {
          "name": "Christian",
          "flowerCount": 1
        },
        {
          "name": "Marcus",
          "flowerCount": 3
        },
        {
          "name": "Norman",
          "flowerCount": 2
        }
    ]
    

    是的,你是对的。这个想象的端口直接返回了一个列表。JSON以[]开始和结束。没错,Marcus也喜欢在绿植环绕的办公桌上工作。

    因此,我们如何使用Gson将此映射到Java对象呢?第一步是创建模型:

    public class Founder {  
        String name;
        int flowerCount;
    }
    

    第二部取决于你。你是希望使用Lists还是Arrays作为你的类型呢?

    Arrays

    如果你想要使用Arrays,那太简单了。跟之前一样直接调用fromJson()方法并且传递数组模型的class,就像:gson.fromJson(founderGson, Founder[].class);

    String founderJson = "[{'name': 'Christian','flowerCount': 1}, {'name': 'Marcus', 'flowerCount': 3}, {'name': 'Norman', 'flowerCount': 2}]";
    
    Gson gson = new Gson();  
    Founder[] founderArray = gson.fromJson(founderJson, Founder[].class); 
    

    这将会产生一个founder的Java数组对象,它们的属性都映射正确:


    Lists

    鉴于Lists可以扩展容量,因此现在的开发者更喜欢使用Java Lists。不幸的是,你不能直接传递List<Founder>给Gson。为了使Gson知道List的准确结构,你需要得到它的Type。幸运的是,Gson有一个TypeToken类帮助你正确找到任何类的Type。我们的Founder类在一个ArrayList中,让我们看一下:

    Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType(); 
    

    你可以使用该语句的结果作为type供Gson调用:

    String founderJson = "[{'name': 'Christian','flowerCount': 1}, {'name': 'Marcus', 'flowerCount': 3}, {'name': 'Norman', 'flowerCount': 2}]";
    
    Gson gson = new Gson();
    
    Type founderListType = new TypeToken<ArrayList<Founder>>(){}.getType();
    
    List<Founder> founderList = gson.fromJson(founderJson, founderListType);  
    

    结果跟使用Array得到的结果差不多:


    最后,映射你的数据到Array还是List取决于你的个人偏好和用例情况。让我们探讨另一个主题:怎样反序列化一个嵌套在一个对象中的列表:

    列表作为一个对象的一部分

    我们已经扩展了我们想象的未来环境中的API,端口为GET /info。它返回了比founder更多的信息:

    {
      "name": "Future Studio Dev Team",
      "website": "https://futurestud.io",
      "founders": [
        {
          "name": "Christian",
          "flowerCount": 1
        },
        {
          "name": "Marcus",
          "flowerCount": 3
        },
        {
          "name": "Norman",
          "flowerCount": 2
        }
      ]
    }
    

    我们希望你已经熟悉流程了。首先我们需要写一个与JSON响应匹配的模型。我们可以复用之前的Founder类:

    public class GeneralInfo {  
        String name;
        String website;
        List<Founder> founders;
    }
    

    处理嵌套在一个对象中的列表是简单的,因为Gson不用使用TypeToken就可以简单地处理了。我们可以直接传入class:

    String generalInfoJson = "{'name': 'Future Studio Dev Team', 'website': 'https://futurestud.io', 'founders': [{'name': 'Christian', 'flowerCount': 1 }, {'name': 'Marcus','flowerCount': 3 }, {'name': 'Norman','flowerCount': 2 }]}";
    
    Gson gson = new Gson();
    
    GeneralInfo generalInfoObject = gson.fromJson(generalInfoJson, GeneralInfo.class); 
    

    产生的结果是完美的:


    当然,你也可以使用Founder[]数组代替List<Founder>。Gson同样可以处理。

    注意:你注意到没有,GeneralInfo和Founder模型拥有相同的name属性,但是Gson却没有出现问题?在序列化和反序列化过程中不会出现任何问题。这真是太神奇了。

    嵌套在列表里面的列表

    如果你正好奇,在处理嵌套在列表里面的列表时会不会有问题。例如,下面的模型将不会有问题:

    public class GeneralInfo {  
        String name;
        String website;
        List<FounderWithPets> founders;
    }
    

    FounderWithPets类是由宠物列表扩展而来的:

    public class FounderWithPets {  
        String name;
        int flowerCount;
        List<Pet> pets;
    }
    

    Pet类又拥有玩具的列表

    public class Pet {  
        String name;
        List<Toy> toys;
    }
    

    Toy类又包含……好了,循环停止吧。我们希望这个推论可以带给你这样一个观点:你可以在列表中逐层的包含列表而不会有任何问题。Gson就像个冠军一样良好的处理序列化和反序列化。

    不过,Gson只能处理包含一致性的对象的列表。如果对象是完全不同的,Gson就不能映射了。尽管可以由多种类型组成列表。

    相关文章

      网友评论

          本文标题:Gson教程三(译):Arrays和Lists的映射

          本文链接:https://www.haomeiwen.com/subject/dyfauxtx.html