从 LinkedHashMap 构建有序 JSON 字符串
Posted
技术标签:
【中文标题】从 LinkedHashMap 构建有序 JSON 字符串【英文标题】:Building ordered JSON String from LinkedHashMap 【发布时间】:2015-06-12 00:45:41 【问题描述】:我需要按插入顺序排列键/值对,因此我选择使用LinkedHashMap
而不是HashMap
。但我需要将LinkedHashMap
转换为JSON 字符串,其中LinkedHashMap
中的顺序保留在字符串中。
但目前我正在通过以下方式实现它:
-
首先将 LinkedHashMap 转换为 JSON。
然后将 JSON 转换为字符串。
import java.util.LinkedHashMap;
import java.util.Map;
import org.json.JSONObject;
public class cdf
public static void main(String[] args)
Map<String,String > myLinkedHashMap = new LinkedHashMap<String, String>();
myLinkedHashMap.put("1","first");
myLinkedHashMap.put("2","second");
myLinkedHashMap.put("3","third");
JSONObject json = new JSONObject(myLinkedHashMap);
System.out.println(json.toString());
输出是:
"3":"third","2":"second","1":"first" .
但我希望它按插入键的顺序,如下所示:
"1":"first","2":"second","3":"third"
一旦我将LinkedHashMap
转换为 JSON,它就会失去它的顺序(很明显 JSON 没有顺序的概念),因此字符串也是无序的。现在,如何生成一个顺序与LinkedHashMap
相同的JSON字符串?
【问题讨论】:
如果您在一个简短但完整的程序中向我们展示这个问题,这将真的有所帮助...(代码、预期输出、实际输出。)跨度> 您可以为每个 JSON 对象添加一个元素order
,这样您就可以在接收和解析 JSON 后跟踪字符串排序。
@JonSkeet:我现在已经编辑了这个问题..希望这已经足够清楚了。
嗯。我机器上的输出只是
- 但无论如何它都没有编译开始。请使用您编译并运行的实际代码更新问题...
@MrPolywhirl:我已经回滚到修订版 4,因为虽然文本可能不太好,但它至少包含一个(有缺陷的)示例......
【参考方案1】:
为有序对创建 JsonArray...
JSONArray orderedJson=new JSONArray();
Iterator iterator= ;
while (iterator.hasNext())
Map.Entry me = (Map.Entry)iteratornext();
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
JSONObject tmpJson=new JSONObject ();
tmpJson.put(me.getKey(),me.getValue());//add key/value to tmpjson
orderedJson.add(tmpJson);//add tmpjson to orderedJson
【讨论】:
但是如何在保持顺序的情况下转换成一个 JSON 字符串呢? 把这个 JSONArray 简单地放入一个 JSONObject 中......例如。 JSONObject jObject=new JSONObject();jObject.put(orderedJson);【参考方案2】:由于linkedhashmap 参数都是字符串,JSON 没有采用插入顺序。像下面提到的代码一样将第一个参数更改为整数是否可以:
Map<Integer,String > myLinkedHashMap = new LinkedHashMap<>();
myLinkedHashMap.put(1,"first");
myLinkedHashMap.put(2,"second");
myLinkedHashMap.put(3,"third");
System.out.println(myLinkedHashMap);
JSONObject json = new JSONObject(myLinkedHashMap);
System.out.println(json.toString());
【讨论】:
但是如何在保持顺序的情况下转换成一个 JSON 字符串呢? 我建议的代码是有序维护的。无法理解您的问题。 不,这样不行 - 问题是JSONObject
在幕后使用了一个普通的HashMap
,你不能改变它:(
@Jon Skeet - 这有什么问题?这个输出错了吗?正在获取上述程序的输出:1=first, 2=second, 3=third "1":"first","2":"second","3":"third"
@Subbu:我怀疑这是巧合而不是保证。 (您仍然依赖HashMap
的排序,这是一个非常糟糕的主意。)【参考方案3】:
Gson 如果你的朋友。这会将有序的地图打印成有序的 JSON 字符串。
如果您想保留插入顺序,请使用LinkedHashMap
。
我使用的是最新版本的Gson(2.8.5),您可以通过本文底部的以下选项进行下载。
import java.util.*;
import com.google.gson.Gson;
public class OrderedJson
public static void main(String[] args)
// Create a new ordered map.
Map<String,String> myLinkedHashMap = new LinkedHashMap<String, String>();
// Add items, in-order, to the map.
myLinkedHashMap.put("1", "first");
myLinkedHashMap.put("2", "second");
myLinkedHashMap.put("3", "third");
// Instantiate a new Gson instance.
Gson gson = new Gson();
// Convert the ordered map into an ordered string.
String json = gson.toJson(myLinkedHashMap, LinkedHashMap.class);
// Print ordered string.
System.out.println(json); // "1":"first","2":"second","3":"third"
如果您希望项目始终插入正确的位置,请改用TreeMap
。
import java.util.*;
import com.google.gson.Gson;
public class OrderedJson
public static void main(String[] args)
// Create a new ordered map.
Map<String,String> myTreeHashMap = new TreeMap<String, String>();
// Add items, in any order, to the map.
myTreeHashMap.put("3", "third");
myTreeHashMap.put("1", "first");
myTreeHashMap.put("2", "second");
// Instantiate a new Gson instance.
Gson gson = new Gson();
// Convert the ordered map into an ordered string.
String json = gson.toJson(myTreeHashMap, TreeMap.class);
// Print ordered string.
System.out.println(json); // "1":"first","2":"second","3":"third"
依赖选项
Maven
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
分级
compile 'com.google.code.gson:gson:2.8.5'
或者您可以访问Maven Central 了解更多下载选项。
【讨论】:
非常感谢 :) 它有效 :) 也感谢 Maven 依赖项,它帮助了 :) 非常有用。 . . :) 杰克逊不能做到这一点真是太糟糕了。 @goat Jackson 做得很好,看看我的回答。 OP 只是不必要地复杂代码......上面的 GSON 示例也得到了纠正。 这个例子不起作用,因为 GSON 使用 TreeMap,所以正确的例子是做 myLinkedHashMap.put("3", "third");和 myLinkedHashMap.put("1", "one"),所以你会看到 GSON 翻转了结果..【参考方案4】:要按字母顺序排序,这是 Jackson 2.* 的正确方法:
Map<String, String> myLinkedHashMap = new LinkedHashMap<String, String>();
myLinkedHashMap.put("1", "first");
myLinkedHashMap.put("2", "second");
myLinkedHashMap.put("3", "third");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
try
System.out.println(mapper.writeValueAsString(myLinkedHashMap));
//prints "1":"first","2":"second","3":"third"
catch (JsonProcessingException e)
e.printStackTrace();
【讨论】:
也可以使用TreeMap
进行排序。序列化器使用Map
的遍历顺序。我不太清楚为什么答案声称杰克逊不保留排序:确实如此。【参考方案5】:
JSONObject
暗示使用org.json
库。不要那样做;它是旧原型,并且有更好的选择,例如 Jackson 和 GSON。
对于 Jackson,您只需使用:
String json = new ObjectMapper().writeValueAsString(myLinkedHashMap);
并以您的 Map 使用的任何遍历顺序获取带有条目的 JSON 字符串。
【讨论】:
【参考方案6】:我遇到了同样的问题。我必须使用这个特定的库,并且第一个元素必须带有键“$type”。 这是我的决定:
import org.json.JSONObject;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
class TypedJSONObject extends JSONObject
private static final String KEY = "$type";
@Override
public Set<Map.Entry<String, Object>> entrySet()
Set<Map.Entry<String, Object>> superSet = super.entrySet();
Set<Map.Entry<String, Object>> returnSet = new LinkedHashSet<>();
HashMap<String, Object> map = new HashMap<>();
for (Map.Entry<String, Object> entry : superSet)
if (entry.getKey().equals(KEY))
map.put(KEY, entry.getValue());
break;
Set<Map.Entry<String, Object>> entries = map.entrySet();
returnSet.addAll(entries);
returnSet.addAll(superSet);
return returnSet;
如你所见,我重写了方法 entrySet,它在方法 toString 中使用
【讨论】:
【参考方案7】:我创建了一个 hacky 解决方案,不应该用于生产,我只是用它来手动生成 json 文件
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import org.json.JSONObject;
public class SortedJSONObject extends JSONObject
public SortedJSONObject()
super();
try
Field mapField = JSONObject.class.getDeclaredField("map");
mapField.setAccessible(true);
mapField.set(this, new LinkedHashMap());
mapField.setAccessible(false);
catch (Exception e)
throw new RuntimeException(e);
【讨论】:
以上是关于从 LinkedHashMap 构建有序 JSON 字符串的主要内容,如果未能解决你的问题,请参考以下文章