Java 建模一个类来表示JSON数据的理由是什么?我需要这样做吗?
我在StackOverflow上遇到了这个问题,这个问题的答案是,另一个类被建模来表示JSON数据和正在创建的对象,我不明白为什么 Gson读取内容后,该对象现在包含所有信息还是仅包含一个键/值对?如果它只包含1个键/值对,我假设我需要为下面的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
{
"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;
}
}