【问题标题】:Building ordered JSON String from LinkedHashMap从 LinkedHashMap 构建有序 JSON 字符串
【发布时间】:2015-06-12 00:45:41
【问题描述】:

我需要按插入顺序排列键/值对,因此我选择使用LinkedHashMap 而不是HashMap。但我需要将LinkedHashMap 转换为JSON 字符串,其中LinkedHashMap 中的顺序保留在字符串中。

但目前我正在通过以下方式实现它:

  1. 首先将 LinkedHashMap 转换为 JSON。
  2. 然后将 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,因为虽然文本可能不太好,但它至少包含一个(有缺陷的)示例......

标签: java json string hashmap linkedhashmap


【解决方案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);
              }
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2014-05-17
        • 2021-12-25
        • 2014-10-13
        • 2017-03-06
        • 1970-01-01
        • 1970-01-01
        • 2013-11-28
        • 2018-03-07
        • 1970-01-01
        相关资源
        最近更新 更多