[java] Google Gson-목록 <class> 객체를 직렬화 해제 하시겠습니까? (일반 타입)

Google Gson을 통해 목록 객체를 전송하고 싶지만 일반 유형을 역 직렬화하는 방법을 모르겠습니다.

이것을 보고 난 후에 시도한 것 (BalusC의 답변) :

MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());

그러나 “새 List () {} 형식은 상속 된 추상 메소드를 구현해야합니다 …”라는 식의 오류가 발생합니다. 빠른 수정을 사용하면 20 개가 넘는 메소드 스텁의 몬스터가 생깁니다.

더 쉬운 해결책이 있다고 확신하지만 찾을 수없는 것 같습니다!

편집하다:

지금 나 한테있어

Type listType = new TypeToken<List<MyClass>>()
                {
                }.getType();

MyClass mc = new Gson().fromJson(result, listType);

그러나 “fromJson”줄에서 다음 예외가 발생합니다.

java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)

내가 캐치 JsonParseExceptions 및 “결과를”null이 아닙니다.

디버거로 listType을 확인하고 다음을 얻었습니다.

  • 목록 유형
    • args = ListOfTypes
      • 목록 = null
      • resolvedTypes = 유형 [1]
    • 로더 = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = 클래스 (java.util.ArrayList)
    • rawTypeName = “java.util.ArrayList”

“getClass”호출이 제대로 작동하지 않은 것 같습니다. 어떤 제안 …?

Edit2 : Gson User Guide 에서 확인했습니다 . 제네릭 형식을 Json으로 구문 분석하는 동안 발생하는 런타임 예외에 대해 설명합니다. 예제에서와 같이 “잘못된”(위에 표시되지 않음)을 수행했지만 예외는 전혀 얻지 못했습니다. 따라서 사용자 안내서에서 제안한대로 직렬화를 변경했습니다. 그래도 도움이되지 않았습니다.

편집 3 : 해결되었습니다. 아래 답변을 참조하십시오.



답변

일반 컬렉션을 역 직렬화하는 방법 :

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

...

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);

의견에 여러 사람들이 언급 했으므로 다음은 TypeToken수업이 어떻게 사용 되는지에 대한 설명입니다 . 구조는 new TypeToken<...>() {}.getType()컴파일 시간 유형 (사이 캡처 <>런타임으로) java.lang.reflect.Type객체. Class원시 (삭제 된) 유형 만 나타낼 수 있는 객체 와 달리 객체 Type는 일반 유형의 매개 변수화 된 인스턴스화를 포함하여 Java 언어의 모든 유형을 나타낼 수 있습니다.

TypeToken당신이 직접 구성 안하고 있기 때문에 클래스 자체는, public 생성자가 없습니다. 대신 항상 익명 서브 클래스를 구성합니다 (따라서이 {}표현식의 필수 부분입니다).

유형 삭제로 인해 TypeToken클래스는 컴파일 타임에 완전히 알려진 유형 만 캡처 할 수 있습니다. 즉, new TypeToken<List<T>>() {}.getType()type 매개 변수 는 수행 할 수 없습니다 T.

자세한 내용 은 해당 TypeToken클래스설명서를 참조하십시오 .


답변

또 다른 방법은 배열을 유형으로 사용하는 것입니다. 예 :

MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class);

이렇게하면 Type 객체로 인한 번거 로움을 피할 수 있으며 실제로 목록이 필요한 경우 항상 다음을 통해 배열을 목록으로 변환 할 수 있습니다.

List<MyClass> mcList = Arrays.asList(mcArray);

IMHO 이것은 훨씬 더 읽기 쉽습니다.

그리고 실제 목록 (수정 가능, 제한 사항 참조 Arrays.asList())으로 만들려면 다음을 수행하십시오.

List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray));


답변

이 게시물을 참조하십시오.
GSON의 인수로 Java 유형 일반

이에 대한 더 나은 해결책이 있습니다. 다음은 목록에 대한 래퍼 클래스입니다. 래퍼가 정확한 유형의 목록을 저장할 수 있습니다.

public class ListOfJson<T> implements ParameterizedType
{
  private Class<?> wrapped;

  public ListOfJson(Class<T> wrapper)
  {
    this.wrapped = wrapper;
  }

  @Override
  public Type[] getActualTypeArguments()
  {
      return new Type[] { wrapped };
  }

  @Override
  public Type getRawType()
  {
    return List.class;
  }

  @Override
  public Type getOwnerType()
  {
    return null;
  }
}

그런 다음 코드는 간단 할 수 있습니다.

public static <T> List<T> toList(String json, Class<T> typeClass)
{
    return sGson.fromJson(json, new ListOfJson<T>(typeClass));
}


답변

이후 Gson 2.8, 우리는 다음과 같은 util 함수를 만들 수 있습니다

public <T> List<T> getList(String jsonArray, Class<T> clazz) {
    Type typeOfT = TypeToken.getParameterized(List.class, clazz).getType();
    return new Gson().fromJson(jsonArray, typeOfT);
}

사용 예

String jsonArray = ...
List<User> user = getList(jsonArray, User.class);


답변

같은 결과를 얻는 또 다른 방법 인 Wep. 가독성을 위해 사용합니다.

이 읽기 어려운 문장을 수행하는 대신 :

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> list = new Gson().fromJson(jsonArray, listType);

객체의 목록을 확장하는 빈 클래스를 만듭니다.

public class YourClassList extends ArrayList<YourClass> {}

JSON을 파싱 할 때 사용하십시오.

List<YourClass> list = new Gson().fromJson(jsonArray, YourClassList.class);


답변

코 틀린의 경우 :

import java.lang.reflect.Type
import com.google.gson.reflect.TypeToken
...
val type = object : TypeToken<List<T>>() {}.type

또는 다음은 유용한 기능입니다.

fun <T> typeOfList(): Type {
    return object : TypeToken<List<T>>() {}.type
}

그런 다음 사용하십시오.

val type = typeOfList<YourMagicObject>()


답변

public static final <T> List<T> getList(final Class<T[]> clazz, final String json)
{
    final T[] jsonToObject = new Gson().fromJson(json, clazz);

    return Arrays.asList(jsonToObject);
}

예:

getList(MyClass[].class, "[{...}]");