2012-08-17 4 views
13

루트 요소를 건너 뛰고이 JSON의 내부 부분 만 구문 분석하려면 다음 JSON을 deserialize해야합니까? 추가, 제 3 클래스 Root을 작성하는 것을 피하고 싶습니다. 이는 MapWrapper 필드 만 포함합니다.json을 역 직렬화하는 동안 루트 요소 건너 뛰기

{ 
    "root": { 
     "language": "en", 
     "map": { 
      "k1": { 
       "name": "n1", 
      }, 
      "k2": { 
       "name": "n2", 
      } 
     } 
    } 
} 

그래서 나는 단지이 두 클래스를 가지고 싶습니다

class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 
} 

class MyMapEntry { 
    String name; 
} 

답변

10

GSON 라이브러리를 사용할 수 있습니다.

아래 코드는 문제를 해결합니다.

public class ConvertJsonToObject { 

    private static Gson gson = new GsonBuilder().create(); 

    public static final <T> T getFromJSON(String json, Class<T> clazz) { 
     return gson.fromJson(json, clazz); 
    } 

    public static final <T> String toJSON(T clazz) { 
     return gson.toJson(clazz); 
    } 
} 

String json; // your jsonString 
Map<String,Object> r = ConvertJsonToObject.getFromJSON(json,Map.class); 
String innerJson = ConvertJsonToObject.toJson(r.get("root")); 
MapWrapper _r = ConvertJsonToObject.getFromJSON(innerJson,MapWrapper.class); 
+0

깔끔한 솔루션. +1 –

+1

이 코드는 JSON을 두 번 구문 분석합니다. 그것을 피할 수 있습니까? –

+0

네, 사용자 정의 JsonDeserializer를 작성하고 GSON에 등록하여이 작업을 수행 할 수 있습니다. – Byter

0

당신은 Map<String, MapWrapper>로를 역 직렬화 할 수있다.

+0

어떻게 데이터를 역 직렬화하는 (또는 계획에) :

반복자 방법은 같다? (특정 프레임 워크?) –

2

이것은 한 번에 처리하는 데 가장 적합한 코드입니다.

MapWrapper 클래스

public class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 

    public MapWrapper(String language, Map<String, MyMapEntry> map) { 
     this.language = language; 
     this.map = map; 
    } 
} 

MyMapEntry 클래스

public class MyMapEntry { 

    String name; 

    public MyMapEntry(String name) { 
     this.name = name; 
    } 
} 

사용자 정의 디시리얼라이저

public class MyDeserialiser implements JsonDeserializer<MapWrapper> 
{ 

    @Override 
    public MapWrapper deserialize(JsonElement json, Type typeOfT, 
     JsonDeserializationContext ctx) throws JsonParseException { 

     JsonObject _global = json.getAsJsonObject(); 
     _global = _global.get("root").getAsJsonObject(); 

     JsonPrimitive lang = (JsonPrimitive) _global.get("language"); 
     JsonElement map = _global.get("map"); 
     Map<String, MyMapEntry> inMap = new LinkedHashMap<String, MyMapEntry>(); 
     for (Entry<String, JsonElement> entry : map.getAsJsonObject() 
       .entrySet()) { 
      MyMapEntry _m = new MyMapEntry(entry.getValue().toString()); 
      inMap.put(entry.getKey(), _m); 
     } 
     return new MapWrapper(lang.getAsString(), inMap); 
    } 
} 

new GsonBuilder().registerTypeAdapter(MapWrapper.class,new MyDeserialiser()).create() 
GSON

에 등록 JSON은을 사용하여 루트 요소없이이 JSON에 대한

{"authorization":{"username":"userabc", "password":"passabc"}} 

/에서

public class Authorization { 
    private String username; 
    private String password; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    // Add a container for the root element 
    public static class Container { 
     public Authorization authorization; 
    } 
} 

변환을 DTO를 :

이제 다음 JSON을 고려 코드를

String json; // your jsonString 
MapWrapper result = ConvertJsonToObject.getFromJSON(json,MapWrapper.class); 
+0

이것은 내가 처음부터 문제가 추가 클래스를 만들 수 있습니다. 그렇게함으로써 루트라는 MapWrapper 타입의 한 필드를 가진'Wraper' 클래스를 만드는 것이 더 좋다. –

+0

@Mathew Wrapper 클래스가 필요 없음 실제로는 – Byter

+0

래퍼가 없으면 null 객체를 생성하므로'ctx.deserialize'는'MyDeserializer.deserialize' 메서드를 호출하여'MapWrapper' 객체를 생성합니다. –

2

을 다음과 같이 deserialise 다음 방법 (DTO 또는 다른 도움말 클래스 내에서 유지할 수 있음)

public String toJson(Authorization authorization) { 
    Gson gson = new Gson(); 
    Authorization.Container container = new Authorization.Container(); 
    container.authorization = authorization; 
    return gson.toJson(container); 
} 

public Authorization fromJson(String json) { 
    Gson gson = new Gson(); 
    Authorization.Container container = gson.fromJson(json, Authorization.Container.class); 
    return container.authorization; 
} 
+0

좋은 해결책 wrt me – Riskhan

0

구스타프 칼슨 (Gustav Carlson)의 아이디어에서 영감을 얻어 구체적인 샘플로 확장하기로 결정했습니다. 이 JSON을 Map으로 구문 분석하는 테스트를 수행하는 junit 테스트가 있습니다.

public static class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 
} 

public static class MyMapEntry { 
    String name; 
} 

@Test 
public void testParsing() { 
    String json = "{\n" + 
      " \"root\": {\n" + 
      "  \"language\": \"en\",\n" + 
      "  \"map\": {\n" + 
      "   \"k1\": {\n" + 
      "    \"name\": \"n1\"\n" + 
      "   },\n" + 
      "   \"k2\": {\n" + 
      "    \"name\": \"n2\"\n" + 
      "   }\n" + 
      "  }\n" + 
      " }\n" + 
      "}"; 
    Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); 
    Type type = new TypeToken<Map<String, MapWrapper>>(){}.getType(); 
    Map<String, MapWrapper> parsed = gson.fromJson(json, type); 
    MapWrapper mapWrapper = parsed.get("root"); 
    Assert.assertEquals("en", mapWrapper.language); 
    Assert.assertEquals("n2", mapWrapper.map.get("k2").name); 
} 
2

내 대답이이 파티에 늦었습니다.

일단 Json을 구문 분석하면 컨테이너는 항상 JsonElement의 JsonObject 하위 클래스가됩니다. 따라서, 우리가 그것을 건너 뛰고 싶다면, 우리는 그것의 서브 클래스로 캐스팅하고 내부 클래스를 유지하는 필드를 잡을 필요가 있습니다.

String response = ....; 

    Gson gson = new Gson(); 

    JsonParser p = new JsonParser(); 
    JsonElement jsonContainer = p.parse(response); 
    JsonElement jsonQuery = ((JsonObject) jsonContainer).get("query"); 

    MyQuery query = gson.fromJson(jsonQuery, MyQuery.class); 

참고 : JsonObject와 JSONObject는 다른 클래스입니다 (com.google.Json 가져 오기 사용).

당신은 내부 클래스의 이름을 알 필요가 없도록이 대답을 더 일반화 할 수 있습니다.컨테이너 객체의 유일한 필드를 얻는 것만으로도이 작업을 수행 할 수 있습니다. 그러나 iterator를 시작하는 것 이외의 다른 방법은 없습니다. getValue (atIndex) 메서드가 없습니다. 반복기를 시작하는 것이 단순히 이름으로 필드를 찾는 것보다 효과적이라고 생각합니다. 잘못된).

JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator() 
          .next().getValue();