我在StackOverflow上遇到过这个问题,询问converting JSON to Java.答案显示另一个类被建模来表示JSON数据以及正在创建的对象,我不明白为什么。< / p>
该对象现在是否包含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循环。
答案 0 :(得分:0)
让我们使用杰克逊的功能,允许您将任何属性映射到单个方法(我相信你真的不需要吸气剂)。只需交换此通用设置器中的键和值,然后添加到已按键(名称)排序的TreeMap。然后,您可以按字母顺序输出键(名称),并轻松地按名称获取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;
}
}
答案 1 :(得分:-1)
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()
找到“Annie”?
显然,这不是良好的解决方案。
更好的解决方案
由于您的数据不符合JSON对象的典型格式,因此您有两种选择:
解决方案1:更改JSON表示
重构JSON会导致一个对象(最好)看起来像这样:
{
"champions" : [
{
"index" : 1,
"name" : "Annie"
},
{
"index" : 2,
"name" : "Olaf"
},
// ...
]
}
这可以很容易地映射到几个看起来像这样的bean:
class Data {
private List<Champion> champions;
// TODO getters and setters
}
class Champion {
private int index;
private String name;
// TODO getters and setters
}
然而,这给JSON对象增加了许多不必要的混乱,并且每个冠军只有两个字段(名称及其索引)并不是必需的。
您可以进一步简化:
{
"champions" : [
"Annie",
"Olaf",
// ...
]
}
那个bean类将是:
class Data {
private List<String> champions;
// TODO getters and setters
}
更简单,但仍需要更改您获得的JSON,这在某些情况下是不可能的。但是,如果你使用了这个,你也可以完全摆脱“bean”类,通过:
List<String> champions = (List<String>) new Gson().fromJson(myJsonString, new TypeToken<List<String>>(){}.getType());
解决方案2:更改解析JSON的方式
可以说更好更清洁的解决方案就是改变JSON的解析方式。
这里的目标(如果我理解正确的话)是解析JSON并吐出代表每个冠军名字的字符串集合,可以通过JSON表示中的冠军的数字索引访问。
因此,由于JSON对象的布局方式是字符串到字符串的简单映射,我们可以使用Gson直接管道输入Map<String, Object>
,如下所示:
Map<String, String> mappedValues = new Gson().fromJson(myJsonString, Map.class);
String anniesName = mappedValues.get("1"); // "Annie"
String olafsName = mappedValues.get("2"); // "Olaf"
boolean hasTwentyOneElements = mappedValues.containsKey("21"); // false
这个更短,不需要“bean”类,并保留原始的JSON表示。缺点是您无法轻易判断每个条目的索引是否正确和一致;即。如果有人输入错误的号码,或删除其中一个条目。
要获取所有密钥的容器,只需使用mappedValues.keySet()
,并获取所有键值对的容器,即可使用mappedValues.entrySet()
,它会为您提供Set<Map.Entry<String, String>>
。这两个都可以迭代,并且可能是随机顺序(我不确定基础Map
实现是否保留了插入顺序。)
要获取给定名称的索引(即champ
),您将使用类似于以下内容的内容:
String index = null;
for (Map.Entry<String, String> entry : mappedValues.entrySet()) {
if (champ.equals(entry.getValue())) {
index = entry.getKey();
break;
}
}
当然,在此之后你必须检查index
是否为空,并妥善处理,但它很容易实现。
编辑: @vempo's answer通过反转地图提供更清晰,更有效的查找策略(虽然答案是为杰克逊而不是Gson编写的);对Gson的改编如下(是的,在java-8中有一个非常优越的版本,为了可用性而遗漏了):
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"
值得注意的是,这会牺牲通过有效地构建地图两次来构建地图的效率(一次由Gson构建,再一次反转),但它使得值查找更有效率。