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 모듈을 사용하고 있습니다.
답변
여기 있습니다 :
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);
답변
이 코드는 작동합니다 :
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());
답변
나는 이것이 상당히 오래된 질문이라는 것을 알고 있지만 중첩 된 JSON을 a로 직렬화 해제하는 솔루션을 찾고 있었고 Map<String, Object>
아무것도 찾지 못했습니다.
내 yaml deserializer가 작동 Map<String, Object>
하는 방식으로 유형을 지정하지 않으면 JSON 객체가 기본으로 설정되지만 gson 은이 작업을 수행하지 않는 것 같습니다. 다행히 사용자 지정 디시리얼라이저를 사용하여이 작업을 수행 할 수 있습니다.
나는 다음 deserializer를 사용하여 모든 자식을 비슷하게 deserialize하는 기본적으로 JsonObject
s Map<String, Object>
와 JsonArray
s를 기본값으로 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의 기본 동작이 아닌지 잘 모르겠습니다 …
답변
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}
답변
새로운 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);
답변
나는 똑같은 질문을했고 여기서 끝났습니다. 훨씬 더 간단한 것처럼 보이는 다른 접근법이 있습니다 (아마도 새로운 버전의 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");
} ...
그것은 나를 위해 작동하므로 그것은 당신을 위해 작동해야합니다 😉
답변
아래는 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));
}