2016-05-12 6 views
0

反射の仕組みを完全に理解できないので、GsonBuilderのカスタムタイプのアダプタを登録しようとするといくつかの問題があります。genericからのParameterizedTypeのタイプを取得

List<Something>タイプのアダプタを登録する必要があります。

これは、作業コードです:

gsonBuilder.registerTypeAdapter(
      new TypeToken<List<MyClass>>() { }.getType(), new ListDeserializer(MyClass.class) 
    ); 

事は、私は私のタイプのアダプタを登録するためのクラスがたくさんある、と私はListDeserializerSingleDeserializerアダプタを持っているということです。

私は関数を呼び出しているので、私のGsonBuilderとクラスを渡すので、行きます。

private static <T> void registerTypeAdapter(GsonBuilder gsonBuilder, T clazz) { 
    gsonBuilder.registerTypeAdapter(clazz.getClass(), new SingleDeserializer(clazz.getClass())); 
    gsonBuilder.registerTypeAdapter(
      new TypeToken<List<T>>() { 
      }.getType(), new ListDeserializer(clazz.getClass()) 
    ); 
} 

それは私のListDeserializerのために動作しません:

は、ここに私の試みです。私の推測では、は一般的なパラメータ化タイプListであるため、実行時にそれを検出することはできません。

提案がありますか?

答えて

1

new TypeToken<List<T>>() {}.getType()を実行時に使用することはできません。なぜなら、ジェネリックtype erasureのためです。 List<T>は、実行時にはList<Object>になります。

Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz.getClass()}, null); 
gsonBuilder.registerTypeAdapter(type, new ListDeserializer(clazz.getClass())); 

しかし、あなたが本当に総称性が必要なのです。しかし、何を行う可能性はParameterizedTypeを作成し、このようなものを使用するのですか?あなたはここに

private static void registerTypeAdapter2(GsonBuilder gsonBuilder, Class<?> clazz) { 
    gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer()); 
    Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null); 
    gsonBuilder.registerTypeAdapter(type, new ListDeserializer()); 
} 

を行うことができデモです:

import com.google.gson.*; 
import com.google.gson.annotations.SerializedName; 
import com.google.gson.reflect.TypeToken; 
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; 

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.ArrayList; 
import java.util.List; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     GsonBuilder gb = new GsonBuilder(); 
     registerTypeAdapter(gb, MyClass.class); 

     Gson gson = gb.create(); 
     List data = new ArrayList<>(); 
     data.add(new MyClass("Bob")); 
     data.add(new MyClass("Alice")); 

     String listString = gson.toJson(data); 
     String soloString = gson.toJson(new MyClass("Test")); 

     Object resultList = gson.fromJson(listString, new TypeToken<List<MyClass>>() {}.getType()); 
     Object resultSolo = gson.fromJson(soloString, MyClass.class); 

     System.out.println("RESULT:"); 
     System.out.println("FROM " + listString +" TO "+ resultList); 
     System.out.println("FROM " + soloString +" TO "+ resultSolo); 

    } 

    private static void registerTypeAdapter(GsonBuilder gsonBuilder, Class<?> clazz) { 
     gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer()); 
     Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null); 
     gsonBuilder.registerTypeAdapter(type, new ListDeserializer()); 
    } 

    private static class ListDeserializer implements JsonDeserializer { 
     private static Gson gson = new Gson(); 

     @Override 
     public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
      System.out.println("Used ListDeserializer: Type " + typeOfT); 

      Type t = (typeOfT instanceof ParameterizedType) ? 
        ((ParameterizedType) typeOfT).getActualTypeArguments()[0] : 
        Object.class; 

      Type type = ParameterizedTypeImpl.make(List.class, new Type[]{t}, null); 
      List list = gson.fromJson(json, type); 
      return list; 
     } 
    } 

    private static class SingleDeserializer implements JsonDeserializer { 
     private static Gson gson = new Gson(); 

     @Override 
     public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
      System.out.println("Used SingleDeserializer: Type " + typeOfT); 
      return gson.fromJson(json, typeOfT); 
     } 
    } 

    public static class MyClass { 
     @SerializedName("name") 
     private String name; 

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

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 

     @Override 
     public String toString() { 
      return "MyClass{" + 
        "name='" + name + '\'' + 
        '}'; 
     } 
    } 
} 
+0

素晴らしい@varrenです!ありがとう! –

関連する問題