2013-07-17 2 views
7

JSON을 반환하는 Api가 있습니다. 응답은 ApiResult라는 객체에 들어갈 수있는 형식으로되어 있으며 Context <T>과 int 코드가 들어 있습니다.JSON 문자열을 JAVA의 일반 객체로 변환합니다 (GSON 사용)

ApiResult는 일반적인 방식으로 선언됩니다. ApiResult<SomeObject>

내가 GSON이 ApiResult<T>

에 들어오는 JSON 문자열을 변환하는 얻는 방법을 알고 싶습니다

지금까지 내가 가진 :

Type apiResultType = new TypeToken<ApiResult<T>>() { }.getType(); 
ApiResult<T> result = gson.fromJson(json, apiResultType); 

하지만 여전히 반환이 대신의 LinkedHashMap에 컨텍스트 변환 (나는 그 GSON이 다시 추락하는 것으로 가정한다.)

답변

1

Gson에게 T의 유형을 제공해야한다. gson은 어떤 어댑터를 적용해야할지 모르기 때문에 단순히 데이터 구조 만 반환합니다.

귀하와 같은 일반를 제공해야합니다 :

static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception { 
    Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class); 
    constr.setAccessible(true); 
    ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[] { gen }, null); 

    return TypeToken.get(paramType); 
    } 

귀하의 호출이 될 것이다 (그러나 String.class 교체 :

T의 유형이 런타임에만 알려진 경우
Type apiResultType = new TypeToken<ApiResult<String>>() { }.getType(); 

, 나는 까다로운 것을 사용 변수가있는 경우) :

Type apiResultType = getGenToken(ApiResult.class, String.class); 
+0

그래서 내가 T는 귀하의 예제에서 String 형의 것을 가지고 :

String data = getJsonString(); ObjectMapper mapper = new ObjectMapper(); List<AndroidPackage> packages = mapper.readValue(data, List.class); 

어쩌면 이것은 귀하의 경우 GSON와 올바른 방법입니다 . 하지만 String은 없지만 T. 마지막 문장 (과제)은 어떻게 바뀌나요? – Yannis

+0

네,'getGenToken'에서'String.class' 대신'Class 'var을 사용할 것으로 가정하고있었습니다. 하지만 어쩌면 그건 당신 사건에 적용되지 않을 수도 있습니다. – PomPom

4

T가 무엇인지 알고 있어야합니다. 들어오는 JSON은 근본적으로 텍스트입니다. GSON은 어떤 대상이되고 싶은지 전혀 모른다. 당신의 T 인스턴스를 만들 떨어져 단서, 당신은 같은 것을 할 수 JSON에 뭔가가 있다면 당신이 할 수 있습니다 : 내 X를 할 필요가 무엇인지를 결정하는 필드 "_class"를 사용하고

public static class MyJsonAdapter<X> implements JsonDeserializer<ApiResult<X>> 
{ 
    public ApiResult<X> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) 
     throws JsonParseException 
    { 
     String className = jsonElement.getAsJsonObject().get("_class").getAsString(); 
     try 
     { 
     X myThing = context.deserialize(jsonElement, Class.forName(className)); 
     return new ApiResult<>(myThing); 
     } 
     catch (ClassNotFoundException e) 
     { 
     throw new RuntimeException(e); 
     } 
    } 
} 

및 리플렉션 (PomPom의 예와 유사)을 통해 인스턴스화합니다. 당신은 아마 그런 명백한 분야가 없지만, JsonElement를보고 어떤 종류의 X가되어야하는지에 따라 결정할 수있는 방법이 있어야합니다. https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java

+0

나는 코드를 점검 할 것이고 나는 당신이 제안한 것과 같은 것을해야만한다고 생각하지만 .NET에서 같은 (또는 비슷한) 코드가 작동한다. 그렇다면 특정 API에 맞게 일반 API를 변경해야합니다. .NET은 json에서 특별한 _class 필드를 가질 필요없이 런타임에 T를 찾을 수 있습니다. – Yannis

+0

.NET 코드를 몰라도 어떻게 작동하는지 알 수 없습니다. T는 클래스 값을 가지지 않으므로 .NET은 어떤 것을 말하지 않는 한 사용할 클래스를 알지 못합니다. –

0

내가 GSON 매우 유사 JacksonJson 라이브러리를 사용

이 코드는 내가 한참 GSON했던 비슷한의 해킹 버전, 라인 184+에서를 참조하십시오. 몇 가지 일반적인 유형의 객체에이 방법을 JSON 문자열을 변환 할 수있다 :

ApiResult<T> result = gson.fromJson(json, ApiResult.class); 
관련 문제