Java 用复数键表示映射的JSON
我想将以下(java)数据结构序列化为JSON:Java 用复数键表示映射的JSON,java,javascript,json,serialization,Java,Javascript,Json,Serialization,我想将以下(java)数据结构序列化为JSON: class Machine { String name; Map<PartDescriptor, Part> parts; } class PartDescriptor { String group; String id; hashCode() equals() } class Part { String group; String id; String description; Stri
class Machine {
String name;
Map<PartDescriptor, Part> parts;
}
class PartDescriptor {
String group;
String id;
hashCode()
equals()
}
class Part {
String group;
String id;
String description;
String compat;
...
...
}
类机器{
字符串名;
地图部分;
}
类部件描述符{
字符串组;
字符串id;
hashCode()
等于()
}
班级部分{
字符串组;
字符串id;
字符串描述;
字符串兼容;
...
...
}
一台机器的JSON表示是什么
另外(可选),给我指出一个JSON-to-Java序列化程序/反序列化程序,它将支持您的表示
{
"name": "machine name",
"parts": [
{ "group": "part group", "id": "part id", "description": "...", ... },
{ "group": "part group", "id": "part id", "description": "...", ... },
// ...
]
}
如果每个部分的“id”是唯一的,那么“parts”属性可以是对象而不是数组,每个部分的“id”作为键
{
"name": "machine name",
"parts": {
"1st part id": { "group": "part group", "description": "...", ... },
"2nd part id": { "group": "part group", "description": "...", ... },
// ...
}
}
我会这么做的。顶级对象的
部分键将是JSONObject
的JSONArray
,该对象具有键和值。键
将是一个对象,它是您的零件描述符
,值
将是您的零件
{
"name":"theName",
"parts":[
{
"key":{
"group":"theGroup",
"id":"theId"
},
"value":{
"group":"theGroup",
"id":"theId",
"description":"theDescription",
"compat":"theCompat",
...
}
},
...
]
}
假设group+id提供唯一的组合,并且“:”是允许的分隔符:
{
"name": "machine name",
"parts": {
"somegroup:01465": {
"group":"somegroup",
"id": "01465",
...
},
"othergroup:32409": {
"group":"othergroup",
"id": "32409",
...
}
}
}
它可以呈现为下表:
<table class="machine" name="">
<tr>
<th class="partdescriptor" colspan="2">
<th class="part" colspan="4">
</tr>
<tr>
<td class="partdescriptor group"></td>
<td class="partdescriptor" id=""></td>
<td class="part group"></td>
<td class="part" id=""></td>
<td class="description"></td>
<td class="compat"></td>
</tr>
</table>
或者,Unicode可以简化映射:
{"name":"","[{\u0022group\u0022:\u0022\u0022},{\u0022id\u0022:\u0022\u0022}]":
[
{"group":""},
{"id":""},
{"description":""},
{"compat":""}
]
}
可以将其字符串化:
JSON.stringify({"name":"","[{\u0022group\u0022:\u0022\u0022},{\u0022id\u0022:\u0022\u0022}":[{"group":""},{"id":""},{"description":""},{"compat":""}]})
制作:
"{\"name\":\"\",\"[{\\\"group\\\":\\\"\\\"},{\\\"id\\\":\\\"\\\"}]\":[{\"group\":\"\"},{\"id\":\"\"},{\"description\":\"\"},{\"compat\":\"\"}]}"
可以解析为:
JSON.parse("{\"name\":\"\",\"[{\\\"group\\\":\\\"\\\"},{\\\"id\\\":\\\"\\\"}]\":[{\"group\":\"\"},{\"id\":\"\"},{\"description\":\"\"},{\"compat\":\"\"}]}")
要生成对象文字,请执行以下操作:
({name:"", '[{"group":""},{"id":""}]':[{group:""}, {id:""}, {description:""}, {compat:""}]})
参考资料
您不需要注释或自定义序列化程序。假设您已经为
Part
和Machine
中的所有字段设置了getter,那么真正缺少的就是PartDescriptor
上的toString()
。如果出于某种原因,您没有getter函数,则需要使用@JsonProperty
注释感兴趣的字段,以便Jackson知道序列化输出中要包含哪些字段。然而,更可取(也更容易)的做法是简单地创建getter
PartDescriptor
上的toString()
应该返回要在映射中使用的键。如另一个答案所示,您可以简单地将相关字段连接起来:
@Override
public String toString() {
return group + "|" + id;
}
然后,当您尝试使用Jackson的ObjectMapper对机器
进行序列化时,您将神奇地获得此表单:
{
"name" : "Toaster",
"parts" : {
"Electrical|Descriptor1" : {
"group" : "Electrical",
"id" : "Part1",
"description" : "Heating Element",
"compat" : "B293"
},
"Exterior|Descriptor2" : {
"group" : "Exterior",
"id" : "Part2",
"description" : "Lever",
"compat" : "18A"
}
}
}
JSON要求键是字符串,因此如果您确实需要将数据表示为键(例如,您不想使用数组,如Pointy的答案中所示,因为您希望在合同中保证没有相同键的重复条目)然后,您需要自行决定将复杂键序列化为字符串的方法
如果使用带分隔符的串联方法(例如group1 | part1
),需要注意两件事:
- 您需要一个本身不能出现在关键部件中的分隔符,或者在序列化时需要将其转义(例如,将其加倍)。这样做所防止的问题可能很少发生,但如果这是用可重用的通用代码编写的,那么根据墨菲定律,应该更好地保证这一点——如果出现问题,最终会出现问题李>
- 要真正防止“多个值具有相同的复合键”,您需要保持键的顺序相同,例如按字母顺序排序键
鉴于:
另外(可选),请指向支持您的表示的JSON-to-Java序列化程序/反序列化程序
一个值得注意的例子可能是——Google的Java JSON序列化程序库——它使用以下表示:
{
"(group1,part1)": { description: ... },
"(group1,part2)": { description: ... },
"(group2,part1)": { description: ... },
...
"(groupX,partX)": {description: ... },
}
注意:需要通过设置(默认情况下为off)来启用该功能因为PartDescriptor是java映射的关键,我认为我们可以安全地假设group+id组合是唯一的,所以请使用第二个示例。因为JSON在表示类型细节方面的能力非常有限,通用序列化程序通常令人沮丧,并且不适合特定用途。只为自己的数据结构实现自己的序列化程序可能会容易得多。@Pointy谢谢Pointy,我以前没有使用JSON来实现这种目的,我意识到了你的观点。我问这个问题是想听听一些想法,因为我浪费了几个令人沮丧的小时在jackson的未记录和奇怪的API上,结果是一个JavaScript对象文本,而不是JSONobject@PaulSweatte什么意思?这是。事实上,所有的JSON都是JavaScript对象文字…对不起,我的代码复制/粘贴遗漏了一个括号。然而,JSON语法比对象文字语法更具限制性。例如,不允许使用注释或单引号,并且必须引用关键字名称。@Paulste,所以介意删除您的否决票吗?是的,虽然所有JSON都是一个对象文本,但反过来不是真的(我编辑了前面的注释以澄清)。您的解决方案不能反序列化为原始类型。在这种特定情况下,它可能会在json反序列化之后进行一些后处理来反序列化。但我建议不要走这条路,除非json是严格为人类使用的,而且永远不需要进行反序列化。
{
"(group1,part1)": { description: ... },
"(group1,part2)": { description: ... },
"(group2,part1)": { description: ... },
...
"(groupX,partX)": {description: ... },
}