Java 建模一个类来表示JSON数据的理由是什么?我需要这样做吗?

Java 建模一个类来表示JSON数据的理由是什么?我需要这样做吗?,java,json,gson,java-8,Java,Json,Gson,Java 8,我在StackOverflow上遇到了这个问题,这个问题的答案是,另一个类被建模来表示JSON数据和正在创建的对象,我不明白为什么 Gson读取内容后,该对象现在包含所有信息还是仅包含一个键/值对?如果它只包含1个键/值对,我假设我需要为下面的JSON创建多个对象,我可以使用循环来迭代并将值添加到下拉菜单中 { "1": "Annie", "2": "Olaf", "3": "Galio", "4": "TwistedFate", "5": "XinZha

我在StackOverflow上遇到了这个问题,这个问题的答案是,另一个类被建模来表示JSON数据和正在创建的对象,我不明白为什么

Gson读取内容后,该对象现在包含所有信息还是仅包含一个键/值对?如果它只包含1个键/值对,我假设我需要为下面的JSON创建多个对象,我可以使用循环来迭代并将值添加到下拉菜单中

{
    "1": "Annie",
    "2": "Olaf",
    "3": "Galio",
    "4": "TwistedFate",
    "5": "XinZhao",
    "6": "Urgot",
    "7": "Leblanc",
    "8": "Vladimir",
    "9": "FiddleSticks",
    "10": "Kayle",
    "11": "MasterYi",
    "12": "Alistar",
    "13": "Ryze",
    "14": "Sion",
    "15": "Sivir",
    "16": "Soraka",
    "17": "Teemo",
    "18": "Tristana",
    "19": "Warwick",
    "20": "Nunu"
}
基本上,我的目标是:

1) 创建包含值的名称列表

2) 按字母顺序对名称列表(未排序时)排序

3) 循环浏览列表并将每个名称添加到下拉菜单中

4) 选择下拉菜单中的名称时,与该值关联的键将传递给另一个接收更多数据的url


如果不清楚,很抱歉。我花了几个小时试图了解如何从JSON中获取元素并显示它,还试图创建一个列表,在该列表中我可以使用键来显示名称信息,但除了使用for each循环外,我没有运气。

Gson Bean映射解决方案

好的,对于JSON对象来说,您所拥有的有点不寻常;键(在您的例子中是数字)本质上表示它们所包含对象的属性。这是可行的,但您必须理解,例如,当在JSON对象中查找“Annie”时,如果您使用Gson映射到一个“bean”类,我们称之为
Data
(如链接示例所示),那么您必须创建一个如下所示的数据对象:

class Data {
    private String _1;
    // ...
    private String _20;

    public String get1() { return _1; }
    public void set1(String _1) { this._1 = _1; }
    // ...
    public String get20() { return _20; }
    public void set20(String _20) { this._20 = _20; }
}
通过使用
Data Data=new Gson().fromJson(myJsonString,Data.class)data.get1()

显然,这不是一个好的解决方案

更好的解决方案

由于数据不遵循JSON对象的典型格式,因此有两个选项:

  • 如果可以,将JSON表示重构为更详细但更好的解析表示
  • 使用不同的方法来解析现有的JSON
  • 解决方案1:更改JSON表示形式

    重构JSON将产生一个(最好)如下所示的对象:

    {
        "champions" : [
            {
                "index" : 1,
                "name" : "Annie"
            },
            {
                "index" : 2,
                "name" : "Olaf"
            },
            // ...
        ]
    }
    
    class Data {
        private List<Champion> champions;
        // TODO getters and setters
    }
    class Champion {
        private int index;
        private String name;
        // TODO getters and setters
    }
    
    这可以很容易地映射到如下几个bean:

    {
        "champions" : [
            {
                "index" : 1,
                "name" : "Annie"
            },
            {
                "index" : 2,
                "name" : "Olaf"
            },
            // ...
        ]
    }
    
    class Data {
        private List<Champion> champions;
        // TODO getters and setters
    }
    class Champion {
        private int index;
        private String name;
        // TODO getters and setters
    }
    
    然后,该类的bean类将是:

    class Data {
        private List<String> champions;
        // TODO getters and setters
    }
    
    当然,在此之后您必须检查
    index
    是否为null,并进行适当的处理,但这很容易实现

    编辑:通过反转地图提供更清晰、更高效的查找策略(尽管答案是为Jackson而不是Gson编写的);Gson对此的修改如下(是的,中有一个非常优秀的版本,为了可用性而省略):

    公共地图(地图输入){
    Map newMap=newlinkedtreemap();//选择最佳存储类
    for(Map.Entry:input.entrySet()){
    newMap.put(entry.getValue(),entry.getKey());
    }
    返回newMap;
    }
    // ...
    Map mappedValues=invertMap(新的Gson().fromJson(myJsonString,Map.class));
    字符串annieIndex=mappedValues.get(“Annie”);//"1"
    字符串olafIndex=mappedValues.get(“Olaf”);//"2"
    

    值得注意的是,这牺牲了构建映射的效率,因为它有效地构建了两次映射(一次由Gson构建,另一次用于反转),但它使值查找更加高效。

    让我们使用Jackson的功能,它允许您将任何属性映射到单个方法(我相信您在这里并不需要getter)。只需交换这个通用setter中的键和值,并添加到一个树状图,该树状图已经按键(名称)排序。然后,您可以按字母顺序输出键(名称),并轻松地按名称获取ID

    public static void main(String[] args) throws IOException {
    
        String json = "....."; // your JSON string here
    
        com.fasterxml.jackson.databind.ObjectMapper mapper = 
            new com.fasterxml.jackson.databind.ObjectMapper();
        ReverseMap pairs = mapper.readValue(json, ReverseMap.class);
        for (Map.Entry<Object, String> entry : pairs.getValues().entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
    
    public class ReverseMap {
    
        private TreeMap<Object, String> mapping = new TreeMap<>();
    
        @com.fasterxml.jackson.annotation.JsonAnySetter
        public void add(String name, Object value) {
            mapping.put(value, name);
        }
    
        public Map<Object, String> getValues() {
            return mapping;
        }
    }
    
    publicstaticvoidmain(字符串[]args)引发IOException{
    String json=“…”;//此处是您的json字符串
    com.fasterxml.jackson.databind.ObjectMapper映射器=
    新建com.fasterxml.jackson.databind.ObjectMapper();
    ReverseMap pairs=mapper.readValue(json,ReverseMap.class);
    for(Map.Entry:pairs.getValues().entrySet()){
    System.out.println(entry.getKey()+“:”+entry.getValue());
    }
    }
    公共类反向映射{
    私有树映射=新树映射();
    @com.fasterxml.jackson.annotation.JsonAnySetter
    public void add(字符串名称、对象值){
    mapping.put(值、名称);
    }
    公共映射getValues(){
    回归映射;
    }
    }
    
    什么,没有Sona?来吧有相当多的冠军,所以我只是从列表中挑选了一些:)我猜你误用了JSON。在什么意义上我错过了使用JSON?这就是数据是如何给出的,我真的不知道解析后应该如何处理它。我知道我想如何使用它,但我不知道如何使用它。因为这里真正拥有的是一个字符串数组,所以正确的JSON应该是:
    {'names':['name1','name2','name3'…]}
    这样你就可以轻松地将它映射到一个类
    类名持有者{List names;}
    。两件事:1)我为什么需要一个bean类?它的目的是什么?2) 我宁愿不改变JSON,也不使用我得到的东西,因为我相信这会让事情变得更复杂。我之前尝试实现TypeToken,但由于某种原因,我的Java找不到它,并给了我一个错误。它是一个外部库还是我的eclipse只是有缺陷?我会用你所给的,很快就回来报到。我感谢你为我所做的一切@正如我在对问题的直接评论中提到的,似乎您误用了json,它有一种奇怪的格式来提供您想要/需要的数据。无论如何,看起来您只需要
    Map
    的值,在使用
    Map m之后
    
    String index = null;
    for (Map.Entry<String, String> entry : mappedValues.entrySet()) {
        if (champ.equals(entry.getValue())) {
            index = entry.getKey();
            break;
        }
    }
    
    public Map<String, String> invertMap(Map<String, String> input) {
        Map<String, String> newMap = new LinkedTreeMap<String, String>(); // TODO Pick optimal storage class
        for (Map.Entry<String, String> entry : input.entrySet()) {
            newMap.put(entry.getValue(), entry.getKey());
        }
        return newMap;
    }
    
    // ...
    
    Map<String, String> mappedValues = invertMap(new Gson().fromJson(myJsonString, Map.class));
    String annieIndex = mappedValues.get("Annie");   // "1"
    String olafIndex = mappedValues.get("Olaf");     // "2"
    
    public static void main(String[] args) throws IOException {
    
        String json = "....."; // your JSON string here
    
        com.fasterxml.jackson.databind.ObjectMapper mapper = 
            new com.fasterxml.jackson.databind.ObjectMapper();
        ReverseMap pairs = mapper.readValue(json, ReverseMap.class);
        for (Map.Entry<Object, String> entry : pairs.getValues().entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
    
    public class ReverseMap {
    
        private TreeMap<Object, String> mapping = new TreeMap<>();
    
        @com.fasterxml.jackson.annotation.JsonAnySetter
        public void add(String name, Object value) {
            mapping.put(value, name);
        }
    
        public Map<Object, String> getValues() {
            return mapping;
        }
    }