2011-03-20 15 views
26

Estoy tratando de crear una clase genérica para usar con Google Gson. Creé la clase GsonJsonConverterImplementation<T>. Esta clase tiene el siguiente método:Usando un tipo genérico con Gson

public T deserialize(String jsonString) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 

    Gson gson = builder.create(); 
    return gson.fromJson(jsonString, T); // T.class etc. what goes here 
} 

El objetivo es que este método debe ser capaz de trabajar con cualquier tipo que he puesto mi GsonJsonConverterImplementation a trabajar. Desafortunadamente, gson.fromJson(jsonString, T) no funciona, ni tampoco usa T.class en lugar de T. Estoy seguro de que el problema se debe a mi falta de comprensión de los tipos genéricos de Java. ¿Cuál es la forma correcta de usar un genérico con Gson?

Editar
Usando Kris's answer yo supongo que esto debería funcionar. Desafortunadamente, clazz no se puede usar de esta manera y causa un error de compilación. ¿Cuáles son mis opciones para trabajar con una colección y un tipo genérico con Gson?

public List<T> deserializeList(String jsonString, Class<T> clazz) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 
    Gson gson = builder.create(); 

    Type listType = new TypeToken<clazz>(){}.getType(); // compiler error 

    return gson.fromJson(jsonString, listType); 
} 
+2

No sé si se puede hacer esto (Lista - es ok) trabajar con Gson, ya que TypeToken sigue siendo esencialmente una c estática onstruct (que es por qué tu código no puede funcionar). Pero si no tiene que usar absolutamente Gson, Jackson admite la creación programática de tipos (a través de métodos TypeFactory) y permite lo que está tratando de lograr. – StaxMan

+0

Pregunta duplicada: http://stackoverflow.com/questions/4226738/using-generics-with-gson?rq=1 –

Respuesta

36

El método más sencillo de lo que está intentando es definir el tipo de clase que ha de ser devuelto en la misma firma del método. Puede hacerlo pasando una instancia de 'T' al método o la Clase del valor que se devolverá. El segundo enfoque es el más típico en los casos en los que espera generar un valor de retorno. He aquí un ejemplo de este enfoque utilizando Gson:

public <T> T deserialize(String jsonString, Class<T> clazz) { 
    GsonBuilder builder = new GsonBuilder(); 
    builder.setDateFormat("MM/dd/yy HH:mm:ss"); 

    Gson gson = builder.create(); 
    return gson.fromJson(jsonString, clazz); 
} 

Uso:

MyClass mc = deserialize(jsonString, MyClass.class); 
+1

Kris mientras esto funciona, ¿cuál es el punto de establecer el tipo generica para la clase? Me parece que 'GsonJsonConverterImplementation ' debería ser suficiente. ¿Qué me estoy perdiendo? – ahsteele

+1

En mi ejemplo, no habría un punto a menos que lo use en otro lugar. Ese es uno de los problemas con Generics y es la razón principal por la que ve frameworks que inicializan instancias utilizando el método que he mostrado en lugar de configurar el tipo genérico en el nivel de clase.En la mayoría de los casos, no puede recuperar y utilizar el tipo de clase realmente genérico que se define en el nivel de clase. Como resultado, no puede usarlo para crear nuevas instancias o para realizar cualquier otra operación donde se necesite la instancia de Clase. –

+1

Como seguimiento, si tiene subclases de una clase con un tipo genérico, entonces hay formas de recuperar ese tipo, sin embargo, también hay problemas con ese método. Aquí hay un ejemplo básico (como implementado desde la clase padre con tipo genérico) de cómo recuperaría la instancia de clase en ese caso: (Clase) ((ParameterizedType) this.getClass(). getGenericSuperclass()). GetActualTypeArguments() [ 0] –

5

para obtener el tipo de tiempo de ejecución de List<T>, teniendo en cuenta la clase de T, sería chupar porque JDK no creo que se lo necesito así que no hay soporte. Puede subclase ParameterizedType, pero realmente apesta.

Type typeListT = new ParameterizedType() 
    { 
     public Type[] getActualTypeArguments() 
     { 
      return new Type[]{clazz}; 
     } 
     public Type getRawType() 
     { 
      return List.class; 
     } 
     public Type getOwnerType() 
     { 
      return null; 
     } 
     public boolean equals(Object obj) 
     { 
      // must implement equals per spec. this sucks 
     } 
     public int hashCode() 
     { 
      // this blows! Java forgot to specific it! 
      // since we override equals, we should override hashCode 
      // we have no idea what value should be returned here! 
      // note we are co-existing with other ParameterizedType impls 
     } 
    }; 
+3

Esta es una respuesta pobre, tal vez en lugar de despotricar sobre las deficiencias de una API que podría centrarse en los detalles técnicos. Tal como está, ni siquiera veo por lo que has publicado cómo usar la técnica. –

1

estoy usando estos métodos para leer & objeto de escritura usando GSON.

public static <T> void saveAnyTypeOfObject(String key, T value){ 
     Gson gson = new Gson(); 
     String json = gson.toJson(value); 
     SharedPref.save(key, json); 
    } 
    //Type listType = new TypeToken<YourClass>(){}.getType(); 
    public static <T> T readAnyTypeOfObject(String key, Type tt) { 
     Gson gson = new Gson(); 
     String json = SharedPref.read(key, "{}"); 
     T obj = gson.fromJson(json, tt); 
     return obj; 
    } 

lo leen como

TypeToken<YourClassName> typeToken= new TypeToken<YourClassName>() {}; 
    YourClassName yourClassName = ListSharedPref.readAnyTypeOfObject("keyForSavingClass", typeToken.getType()); 

y guárdelo como

YourClassName yourClassName = gson.fromJson(objJsonObject.toString(),YourClassName.class);    
ListSharedPref.saveAnyTypeOfObject("keyForSavingClass",yourClassName); 
Cuestiones relacionadas