Gson을 사용하여 JSON을 HashMap으로 변환하는 방법은 무엇입니까?


286

JSON 형식으로 데이터를 반환하는 서버에서 데이터를 요청하고 있습니다. 요청을 할 때 HashMap을 JSON으로 캐스팅하는 것은 전혀 어렵지 않지만 다른 방법은 약간 까다로워 보입니다. JSON 응답은 다음과 같습니다.

{ 
    "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"
}

이 데이터에 가장 쉽게 액세스 할 수있는 방법은 무엇입니까? GSON 모듈을 사용하고 있습니다.


23
Map<String,Object> result = new Gson().fromJson(json, Map.class);gson 2.6.2에서 작동합니다.
Ferran Maylinch 23.38에

1
다시 변환하는 방법? Map에서 Json Array까지 의미합니다.
K.Sopheak

답변:


471

여기 있습니다 :

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
좋은 것이지만 사용하는 것을 좋아하지 않습니다 TypeToken. 내부 캐스팅을 수행합니다.
AlikElzin-kilaka 15:57에

Map <>로 캐스팅하면 좌절의 시간이 끝났습니다!
Dexter

1
예제에서 유효한 json입니까?
Evan Kairuz 19 :

@EvanKairuz 아니오, 그렇지 않습니다. 그것은해야한다{"k1":"apple","k2":"orange"}
바딤 Kotov

실제로 배열 인 문자열을 변환해야하는 경우
Ravi Yadav

111

이 코드는 작동합니다 :

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
이것은 int를 문자열로 변환하기 전에 float로 변환하지만 비교를 위해 JSON을 맵으로 변환합니다.
louielouie

12
Map<String, Object>json이 문자열 일뿐만 아니라 오류가 발생 하기 때문에 지도를 변경했습니다.
Moshe Shaham

5
이것은 잘못된 인상을줍니다. 매개 변수화 된 유형에 대한 올바른 솔루션은 TypeToken입니다.
Sotirios Delimanolis

이것은 모든 유형에 대한 일반적인 솔루션이지만 조금 드문 경우입니다.
레온

76

나는 이것이 상당히 오래된 질문이라는 것을 알고 있지만 중첩 된 JSON을 a로 직렬화 해제하는 솔루션을 찾고 있었고 Map<String, Object>아무것도 찾지 못했습니다.

내 yaml deserializer가 작동 Map<String, Object>하는 방식으로 유형을 지정하지 않으면 JSON 객체가 기본으로 설정되지만 gson 은이 작업을 수행하지 않는 것 같습니다. 다행히 사용자 지정 디시리얼라이저를 사용하여이 작업을 수행 할 수 있습니다.

나는 다음 deserializer를 사용하여 모든 자식을 비슷하게 deserialize하는 기본적으로 JsonObjects Map<String, Object>JsonArrays를 기본값으로 Object[]deserialize했습니다.

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;
  }
}

handlePrimitive방법 의 혼란 은 Double 또는 Integer 또는 Long 만 얻도록하는 것입니다. BigDecimals를 얻는 것이 괜찮다면 더 좋거나 최소한 단순화 될 수 있습니다. 이것이 기본값이라고 생각합니다.

다음과 같이이 어댑터를 등록 할 수 있습니다.

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

그리고 다음과 같이 호출하십시오.

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

이것이 대부분의 다른 반 구조화 직렬화 라이브러리에 있기 때문에 왜 이것이 gson의 기본 동작이 아닌지 잘 모르겠습니다 ...


1
... 나는 내가 얻는 Objects로 지금 무엇을 해야할지 확실하지 않지만. 문자열임을 알고 있어도 문자열로 캐스팅 할 수 없음
Matt Zukowski

1
아하! 트릭은 context.deserialize () 호출 대신 deserializer를 재귀 적으로 호출하는 것입니다.
매트 Zukowski

1
코드 매트 좀 주 시겠어요? 디시리얼라이저에서 변경을 시도하고 있지만 실제로 요점을 볼 수 없습니다
Romain Piel

5
현재 Gson은 기본적으로 Kevin Dolan이 코드 스 니펫에서 작동하는 것처럼 보입니다.
eleotlecram

1
@SomeoneSomewhere 수락 된 답변은 여기를 참조하십시오 stackoverflow.com/questions/14944419/gson-to-hashmap
MY

32

Google의 Gson 2.7 (아마도 이전 버전이지만 현재 버전 2.7로 테스트)을 사용하면 다음과 같이 간단합니다.

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

어느 것이 Map 유형을com.google.gson.internal.LinkedTreeMap 중첩 된 객체, 배열 등에서 재귀 적으로 작동합니다.

OP 예제를 다음과 같이 실행했습니다 (작은 따옴표로 작은 따옴표를 바꾸고 공백을 제거했습니다).

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);

그리고 다음과 같은 결과를 얻었습니다.

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

새로운 Gson lib 업데이트 :
이제 중첩 된 Json을 Map으로 직접 구문 분석 할 수 있지만 Json을 Map<String, Object>유형 으로 구문 분석하려고 시도하는 경우 예외가 발생합니다. 이 문제를 해결하려면 결과를 LinkedTreeMap유형으로 선언하십시오 . 아래 예 :

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

LinkedTreeMap은 어디에서 가져 오나요? Gson 코드에서 찾을 수 없습니다.
HelpMeStackOverflowMyOnlyHope

내가 기억하는 것처럼 LinkedTreeMap은 새로운 Gson lib에 정의되어 있습니다. code.google.com/p/google-gson/source/browse/trunk/gson/src/main/…에서
Hoang Nguyen Huu 2016 년

1
나를 위해 그것은 또한 작동합니다 Map<String,Object> result = gson.fromJson(json , Map.class);. gson 사용하기 2.6.2.
Ferran Maylinch 23.36에

12

나는 똑같은 질문을했고 여기서 끝났습니다. 훨씬 더 간단한 것처럼 보이는 다른 접근법이 있습니다 (아마도 새로운 버전의 gson입니까?).

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

다음 json으로

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

다음과 같은

    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);

출력

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

jsonObject를 탐색 할 때 instanceof를 사용하여 동적으로 확인할 수 있습니다. 같은 것

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");
} ...

그것은 나를 위해 작동하므로 그것은 당신을 위해 작동해야합니다 ;-)


6

아래는 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

이것을 시도하면 효과가 있습니다. 나는 그것을 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;
}

교체 KioskStatusResource를 클래스와에 정수 키 클래스.


이것은 HashMap이 LinkedTreeMap 예외를 던진 후에 나를 위해 일했습니다.
newfivefour

2

다음은 내가 사용한 것입니다.

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

여기에 하나의 라이너가 있습니다.

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

네, 그것은 한 new TypeToken<HashMap<String, Object>>(){}
줄이지 만

1

Custom JsonDeSerializer와 비슷한 문제를 극복했습니다. 나는 그것을 조금 일반적으로 만들려고했지만 여전히 충분하지 않습니다. 그것은 내 요구에 맞는 솔루션입니다.

우선 Map 객체를위한 새로운 JsonDeserializer를 구현해야합니다.

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

deserialize 방법은 다음과 유사합니다.

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;
    }

이 솔루션의 단점은 내지도의 키가 항상 "문자열"유형이라는 것입니다. 그러나 어떤 것을 노래함으로써 누군가가 그것을 일반으로 만들 수 있습니다. 또한 값의 클래스가 생성자에 전달되어야한다고 말해야합니다. 따라서 getMyType()내 코드 의 메소드 는 생성자에 전달 된 Map 값의 유형을 반환합니다.

이 게시물을 참조 할 수 있습니다 .Gson 용 사용자 정의 JSON deserializer를 작성하는 방법은 무엇입니까? 커스텀 디시리얼라이저에 대해 더 배우기 위해.


1

대신이 클래스를 사용할 수 있습니다 :) (list, nested list 및 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;
    }
}

JSON 문자열을 해시 맵으로 변환하려면 다음 사용하십시오.

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

0

이것은 완전한 답변보다 Kevin Dolan의 답변 에 대한 추가 사항 이지만, Number에서 유형을 추출하는 데 문제가있었습니다. 이것은 내 솔루션입니다.

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는 일반적으로 HashMap내부적으로 데이터를 저장하는 데 사용합니다. 따라서 코드에서 맵으로 사용할 수 있습니다.

예,

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
이것은 gson이 아닌 json-lib에서 온 것입니다!
Ammar

-3

나는이 코드를 사용했다 :

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

이것은 확인되지 않은 변환 경고를 제공합니다.
Line
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.