Làm cách nào tôi có thể chuyển đổi JSON thành HashMap bằng Gson?


286

Tôi đang yêu cầu dữ liệu từ máy chủ trả về dữ liệu ở định dạng JSON. Việc tạo HashMap thành JSON khi thực hiện yêu cầu hoàn toàn không khó nhưng cách khác có vẻ hơi khó. Phản hồi JSON trông như thế này:

{ 
    "header" : { 
        "alerts" : [ 
            {
                "AlertID" : "2",
                "TSExpires" : null,
                "Target" : "1",
                "Text" : "woot",
                "Type" : "1"
            },
            { 
                "AlertID" : "3",
                "TSExpires" : null,
                "Target" : "1",
                "Text" : "woot",
                "Type" : "1"
            }
        ],
        "session" : "0bc8d0835f93ac3ebbf11560b2c5be9a"
    },
    "result" : "4be26bc400d3c"
}

Cách nào dễ nhất để truy cập dữ liệu này? Tôi đang sử dụng mô-đun GSON.


23
Map<String,Object> result = new Gson().fromJson(json, Map.class);hoạt động với gson 2.6.2.
Ferran Maylinch

1
Làm thế nào để chuyển đổi trở lại? Ý tôi là từ Map đến Json Array.
K.Sopheak

Câu trả lời:


471

Ở đây bạn đi:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson("{'k1':'apple','k2':'orange'}", type);

6
Tốt nhưng tôi không thích sử dụng TypeToken- nó thực sự đúc bên trong.
AlikElzin-kilaka

Truyền tới Bản đồ <>, bạn đã kết thúc những giờ thất vọng của tôi!
Dexter

1
Là json hợp lệ trong ví dụ?
Evan Kairuz

@EvanKairuz Không, không phải vậy. Nó nên là{"k1":"apple","k2":"orange"}
Vadim Kotov

Điều gì xảy ra nếu tôi cần chuyển đổi chuỗi thực sự là một mảng
Ravi Yadav

111

Mã này hoạt động:

Gson gson = new Gson(); 
String json = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
Map<String,Object> map = new HashMap<String,Object>();
map = (Map<String,Object>) gson.fromJson(json, map.getClass());

1
Điều này sẽ chuyển đổi ints thành float trước khi nó biến chúng thành chuỗi, nhưng nó sẽ hoạt động để chuyển JSON thành bản đồ cho mục đích so sánh.
louielouie

12
làm việc rất tốt cho tôi, nhưng tôi đã thay đổi bản đồ thành Map<String, Object>bởi vì nếu json không chỉ là chuỗi bạn sẽ gặp lỗi
Moshe Shaham

5
Điều này cho ấn tượng sai. Các giải pháp chính xác cho các loại tham số là TypeToken.
Sotirios Delimanolis

Đây sẽ là một giải pháp chung cho tất cả các loại, nhưng một chút không phổ biến.
Leon

76

Tôi biết đây là một câu hỏi khá cũ, nhưng tôi đã tìm kiếm một giải pháp để khử tuần tự hóa JSON chung cho một Map<String, Object> , và không tìm thấy gì.

Cách trình giải nén yaml của tôi hoạt động, nó mặc định các đối tượng JSON là Map<String, Object>khi bạn không chỉ định một loại, nhưng gson dường như không làm điều này. May mắn thay, bạn có thể hoàn thành nó với một trình giải nén tùy chỉnh.

Tôi đã sử dụng trình giải nén sau đây để khử lưu lượng tự nhiên bất cứ thứ gì, mặc định JsonObjects thành Map<String, Object>JsonArrays thành Object[]s, trong đó tất cả các con đều được khử lưu tương tự.

private static class NaturalDeserializer implements JsonDeserializer<Object> {
  public Object deserialize(JsonElement json, Type typeOfT, 
      JsonDeserializationContext context) {
    if(json.isJsonNull()) return null;
    else if(json.isJsonPrimitive()) return handlePrimitive(json.getAsJsonPrimitive());
    else if(json.isJsonArray()) return handleArray(json.getAsJsonArray(), context);
    else return handleObject(json.getAsJsonObject(), context);
  }
  private Object handlePrimitive(JsonPrimitive json) {
    if(json.isBoolean())
      return json.getAsBoolean();
    else if(json.isString())
      return json.getAsString();
    else {
      BigDecimal bigDec = json.getAsBigDecimal();
      // Find out if it is an int type
      try {
        bigDec.toBigIntegerExact();
        try { return bigDec.intValueExact(); }
        catch(ArithmeticException e) {}
        return bigDec.longValue();
      } catch(ArithmeticException e) {}
      // Just return it as a double
      return bigDec.doubleValue();
    }
  }
  private Object handleArray(JsonArray json, JsonDeserializationContext context) {
    Object[] array = new Object[json.size()];
    for(int i = 0; i < array.length; i++)
      array[i] = context.deserialize(json.get(i), Object.class);
    return array;
  }
  private Object handleObject(JsonObject json, JsonDeserializationContext context) {
    Map<String, Object> map = new HashMap<String, Object>();
    for(Map.Entry<String, JsonElement> entry : json.entrySet())
      map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
    return map;
  }
}

Sự lộn xộn bên trong handlePrimitive phương thức là để đảm bảo bạn chỉ nhận được Double hoặc Integer hoặc Long, và có thể tốt hơn, hoặc ít nhất là đơn giản hóa nếu bạn ổn với việc nhận BigDecimals, mà tôi tin là mặc định.

Bạn có thể đăng ký bộ chuyển đổi này như:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();

Và sau đó gọi nó như:

Object natural = gson.fromJson(source, Object.class);

Tôi không chắc tại sao đây không phải là hành vi mặc định trong gson, vì nó nằm trong hầu hết các thư viện tuần tự hóa bán cấu trúc khác ...


1
... mặc dù tôi không chắc phải làm gì bây giờ với các Đối tượng tôi nhận được. Dường như không thể gọi chúng là Chuỗi mặc dù tôi biết chúng là chuỗi
Matt Zukowski

1
Aha! Thủ thuật là cuộc gọi trình giải nén đệ quy thay vì cuộc gọi context.deserialize ().
Matt Zukowski

1
Bạn sẽ có một số mã Matt? Tôi đang cố gắng thực hiện các thay đổi trên trình giải nén nhưng tôi thực sự không thể thấy quan điểm của bạn
Romain Piel

5
Gson bây giờ theo mặc định dường như có hành vi mà Kevin Dolan sẽ thực hiện trong đoạn mã của mình.
eleotlecram

1
@SomeoneSomewhere xem câu trả lời được chấp nhận tại đây stackoverflow.com/questions/14944419/gson-to-hashmap
MY

32

Với Gson 2.7 của google (có thể là các phiên bản trước đó, nhưng tôi đã thử nghiệm với phiên bản 2.7 hiện tại), nó đơn giản như:

Map map = gson.fromJson(jsonString, Map.class);

Trả về một Mapkiểu com.google.gson.internal.LinkedTreeMapvà hoạt động đệ quy trên các đối tượng lồng nhau, mảng, v.v.

Tôi đã chạy ví dụ OP như vậy (chỉ cần thay thế hai lần bằng dấu ngoặc đơn và khoảng trắng đã xóa):

String jsonString = "{'header': {'alerts': [{'AlertID': '2', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}, {'AlertID': '3', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}], 'session': '0bc8d0835f93ac3ebbf11560b2c5be9a'}, 'result': '4be26bc400d3c'}";
Map map = gson.fromJson(jsonString, Map.class);
System.out.println(map.getClass().toString());
System.out.println(map);

Và có đầu ra sau:

class com.google.gson.internal.LinkedTreeMap
{header={alerts=[{AlertID=2, TSExpires=null, Target=1, Text=woot, Type=1}, {AlertID=3, TSExpires=null, Target=1, Text=woot, Type=1}], session=0bc8d0835f93ac3ebbf11560b2c5be9a}, result=4be26bc400d3c}

25

Cập nhật cho lib Gson mới:
Bây giờ bạn có thể phân tích cú pháp Json lồng vào Bản đồ trực tiếp, nhưng bạn nên lưu ý trong trường hợp bạn cố phân tích cú pháp Json để Map<String, Object>gõ: nó sẽ đưa ra ngoại lệ. Để khắc phục điều này, chỉ cần khai báo kết quả là LinkedTreeMaploại. Ví dụ dưới đây:

String nestedJSON = "{"id":"1","message":"web_didload","content":{"success":1}};
Gson gson = new Gson();
LinkedTreeMap result = gson.fromJson(nestedJSON , LinkedTreeMap.class);

Tôi nhập LinkedTreeMap từ đâu? Tôi không thể tìm thấy nó trong mã Gson.
HelpMeStackOverflowMyOnlyITH

Theo tôi nhớ, LinkedTreeMap được định nghĩa trong lib Gson mới. Bạn có thể kiểm tra tại đây: code.google.com/p/google-gson/source/browse/trunk/gson/src/main/iêu
Hoàng Nguyễn Hữu

1
Đối với tôi nó cũng hoạt động với Map<String,Object> result = gson.fromJson(json , Map.class);. Sử dụng gson 2.6.2.
Ferran Maylinch

12

Tôi đã có cùng một câu hỏi và kết thúc ở đây. Tôi đã có một cách tiếp cận khác có vẻ đơn giản hơn nhiều (có thể là phiên bản mới hơn của gson?).

    Gson gson = new Gson();
    Map jsonObject = (Map) gson.fromJson(data, Object.class);

với json sau

{
  "map-00": {
    "array-00": [
      "entry-00",
      "entry-01"
     ],
     "value": "entry-02"
   }
}

Sau đây

    Map map00 = (Map) jsonObject.get("map-00");
    List array00 = (List) map00.get("array-00");
    String value = (String) map00.get("value");
    for (int i = 0; i < array00.size(); i++) {
        System.out.println("map-00.array-00[" + i + "]= " + array00.get(i));
    }
    System.out.println("map-00.value = " + value);

đầu ra

map-00.array-00[0]= entry-00
map-00.array-00[1]= entry-01
map-00.value = entry-02

Bạn có thể tự động kiểm tra bằng cách sử dụng instanceof khi điều hướng jsonObject của bạn. Cái gì đó như

Map json = gson.fromJson(data, Object.class);
if(json.get("field") instanceof Map) {
  Map field = (Map)json.get("field");
} else if (json.get("field") instanceof List) {
  List field = (List)json.get("field");
} ...

Nó hoạt động với tôi, vì vậy nó phải làm việc cho bạn ;-)


6

Dưới đây được hỗ trợ kể từ gson 2.8.0

public static Type getMapType(Class keyType, Class valueType){
    return TypeToken.getParameterized(HashMap.class, keyType, valueType).getType();
}

public static  <K,V> HashMap<K,V> fromMap(String json, Class<K> keyType, Class<V> valueType){
    return gson.fromJson(json, getMapType(keyType,valueType));
}

3

Hãy thử điều này, nó sẽ làm việc. Tôi đã sử dụng nó cho Hashtable .

public static Hashtable<Integer, KioskStatusResource> parseModifued(String json) {
    JsonObject object = (JsonObject) new com.google.gson.JsonParser().parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();

    Hashtable<Integer, KioskStatusResource> map = new Hashtable<Integer, KioskStatusResource>();

    while (iterator.hasNext()) {
        Map.Entry<String, JsonElement> entry = iterator.next();

        Integer key = Integer.parseInt(entry.getKey());
        KioskStatusResource value = new Gson().fromJson(entry.getValue(), KioskStatusResource.class);

        if (value != null) {
            map.put(key, value);
        }

    }
    return map;
}

Thay thế KioskStatusResource cho lớp của bạn và Integer thành lớp chính của bạn.


Điều này làm việc cho tôi sau khi HashMap ném ngoại lệ LinkedTreeMap.
newfivefour 19/03 '

2

Đây là những gì tôi đã được sử dụng:

public static HashMap<String, Object> parse(String json) {
    JsonObject object = (JsonObject) parser.parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();
    HashMap<String, Object> map = new HashMap<String, Object>();
    while (iterator.hasNext()) {
        Map.Entry<String, JsonElement> entry = iterator.next();
        String key = entry.getKey();
        JsonElement value = entry.getValue();
        if (!value.isJsonPrimitive()) {
            map.put(key, parse(value.toString()));
        } else {
            map.put(key, value.getAsString());
        }
    }
    return map;
}

2

Đây là một lớp lót sẽ làm điều đó:

HashMap<String, Object> myMap =
   gson.fromJson(yourJson, new TypeToken<HashMap<String, Object>>(){}.getType());

vâng, đó là một dòng nhưng hãy nhớ rằng new TypeToken<HashMap<String, Object>>(){}sẽ tạo ra một lớp con nội tuyến mới và tất cả các linters sẽ đưa ra cảnh báo ít nhất là tôi đoán
Martin Meeser

1

Tôi đã khắc phục một vấn đề tương tự với Trình tùy chỉnh JsonDeSerializer. Tôi đã cố gắng để làm cho nó một chút chung chung nhưng vẫn không đủ. Đó là một giải pháp mặc dù phù hợp với nhu cầu của tôi.

Trước hết, bạn cần triển khai một JsonDeserializer mới cho các đối tượng Map.

public class MapDeserializer<T, U> implements JsonDeserializer<Map<T, U>>

Và phương thức deserialize sẽ trông giống như thế này:

public Map<T, U> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {

        if (!json.isJsonObject()) {
            return null;
        }

        JsonObject jsonObject = json.getAsJsonObject();
        Set<Entry<String, JsonElement>> jsonEntrySet = jsonObject.entrySet();
        Map<T, U> deserializedMap = new HashMap<T, U>();

        for (Entry<java.lang.String, JsonElement> entry : jsonEntrySet) {
            try {
                U value = context.deserialize(entry.getValue(), getMyType());
                deserializedMap.put((T) entry.getKey(), value);
            } catch (Exception ex) {
                logger.info("Could not deserialize map.", ex);
            }
        }

        return deserializedMap;
    }

Mặt trái của giải pháp này là khóa của Bản đồ của tôi luôn có Kiểu "Chuỗi". Tuy nhiên bằng cách chan một số thứ ai đó có thể làm cho nó chung chung. Ngoài ra, tôi cần phải nói rằng lớp của giá trị phải được truyền vào hàm tạo. Vì vậy, phương phápgetMyType() trong mã của tôi trả về loại giá trị của Bản đồ, được truyền vào hàm tạo.

Bạn có thể tham khảo bài đăng này Làm cách nào để tôi viết trình giải mã JSON tùy chỉnh cho Gson? để tìm hiểu thêm về khử cặn tùy chỉnh.


1

Bạn có thể sử dụng lớp này thay thế :) (xử lý các danh sách chẵn, danh sách lồng nhau và json)

public class Utility {

    public static Map<String, Object> jsonToMap(Object json) throws JSONException {

        if(json instanceof JSONObject)
            return _jsonToMap_((JSONObject)json) ;

        else if (json instanceof String)
        {
            JSONObject jsonObject = new JSONObject((String)json) ;
            return _jsonToMap_(jsonObject) ;
        }
        return null ;
    }


   private static Map<String, Object> _jsonToMap_(JSONObject json) throws JSONException {
        Map<String, Object> retMap = new HashMap<String, Object>();

        if(json != JSONObject.NULL) {
            retMap = toMap(json);
        }
        return retMap;
    }


    private static Map<String, Object> toMap(JSONObject object) throws JSONException {
        Map<String, Object> map = new HashMap<String, Object>();

        Iterator<String> keysItr = object.keys();
        while(keysItr.hasNext()) {
            String key = keysItr.next();
            Object value = object.get(key);

            if(value instanceof JSONArray) {
                value = toList((JSONArray) value);
            }

            else if(value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            map.put(key, value);
        }
        return map;
    }


    public static List<Object> toList(JSONArray array) throws JSONException {
        List<Object> list = new ArrayList<Object>();
        for(int i = 0; i < array.length(); i++) {
            Object value = array.get(i);
            if(value instanceof JSONArray) {
                value = toList((JSONArray) value);
            }

            else if(value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            list.add(value);
        }
        return list;
    }
}

Để chuyển đổi chuỗi JSON của bạn thành hashmap, hãy sử dụng:

HashMap<String, Object> hashMap = new HashMap<>(Utility.jsonToMap(response)) ;

0

Đây là phần bổ sung cho câu trả lời của Kevin Dolan hơn là một câu trả lời hoàn chỉnh, nhưng tôi đã gặp khó khăn khi trích loại từ Số. Đây là giải pháp của tôi:

private Object handlePrimitive(JsonPrimitive json) {
  if(json.isBoolean()) {
    return json.getAsBoolean();
  } else if(json.isString())
    return json.getAsString();
  }

  Number num = element.getAsNumber();

  if(num instanceof Integer){
    map.put(fieldName, num.intValue());
  } else if(num instanceof Long){
    map.put(fieldName, num.longValue());
  } else if(num instanceof Float){
    map.put(fieldName, num.floatValue());
  } else {    // Double
     map.put(fieldName, num.doubleValue());
  }
}

-1
 HashMap<String, String> jsonToMap(String JsonDetectionString) throws JSONException {

    HashMap<String, String> map = new HashMap<String, String>();
    Gson gson = new Gson();

    map = (HashMap<String, String>) gson.fromJson(JsonDetectionString, map.getClass());

    return map;

}

-3

JSONObject thường sử dụng HashMap nội bộ để lưu trữ dữ liệu. Vì vậy, bạn có thể sử dụng nó làm Bản đồ trong mã của mình.

Thí dụ,

JSONObject obj = JSONObject.fromObject(strRepresentation);
Iterator i = obj.entrySet().iterator();
while (i.hasNext()) {
   Map.Entry e = (Map.Entry)i.next();
   System.out.println("Key: " + e.getKey());
   System.out.println("Value: " + e.getValue());
}

12
Đây là từ json-lib, không phải gson!
Ammar

-3

Tôi đã sử dụng mã này:

Gson gson = new Gson();
HashMap<String, Object> fields = gson.fromJson(json, HashMap.class);

Điều này cho tôi cảnh báo chuyển đổi không được kiểm tra.
Dòng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.