¿Cómo usar correctamente Gson para deserializar un objeto de tipo genérico a través de un método de utilidad estática?

He visto varias otras preguntas similares, pero creo que hay un nivel de abstracción además de las que marcan la diferencia. A saber, tengo una clase de utilidad con un método envoltorio genérico estático para deserializar un objeto de tipo genérico (desconocido en el momento de la compilación):

public final class Utils {

    public static final Gson sGson = new Gson();

    public static synchronized <T> T fromJson(String doc) {
        return sGson.fromJson(doc, new TypeToken<T>(){}.getType());
    }
}

Una clase simple para probarlo:

public class TestDocument {
    public TestDocument(String test) {
        this.test = test;
    }

    public String test;
}

Esto funciona bien:

assertEquals(
   new TestDocument("test").test, 
   ((TestDocument) Utils.sGson.fromJson(
                      "{\"test\": \"test\"}", 
                      new TypeToken<TestDocument>(){}.getType())).test);

Pero lo que parece una forma equivalente de llamar a esto, aunque el método de utilidad genérico estático no:

assertEquals(
   new TestDocument("test").test, 
   Utils.<TestDocument>fromJson("{\"test\": \"test\"}").test);

Lanza la siguiente excepción:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap no se puede transmitir a TestDocument

¿Hay alguna manera de hacerlo funcionar a través del método genérico?

Respuesta 1

Si fuera posible, Gsonprobablemente ya agregaría este método y podría verse así:

TestDocument document = gson.<TestDocument>fromJson(json);

Método con esta firma:

public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException

ha incluido JavaDoc:

Este método deserializa el Json especificado en un objeto de la clase especificada. No es adecuado si la clase especificada es de tipo genérico, ya que no tendrá la información de tipo genérico debido a la función de borrado de tipo de Java . Por lo tanto, este método no debe usarse si el tipo deseado es un tipo genérico. Tenga en cuenta que este método funciona bien si alguno de los campos del objeto especificado son genéricos, solo el objeto en sí no debería ser de tipo genérico. Para los casos en que el objeto es de tipo genérico, invoque fromJson(String, Type). Si tiene el Json en Readerlugar de a String, use fromJson(Reader, Class)en su lugar.

Incluso el segundo nombre del parámetro classOfTtiene significado the class of T.

Respuesta: 2

Hay algunas sugerencias de uso de tipo:

  • Usar <T>sin pasar un tipo real es un engaño debido a la eliminación de tipos genéricos.
  • Pasar el tipo como Class<T>no es una muy buena idea porque ###.classsimplemente representa una clase cargada por JVM (excepto los tipos primitivos). Teniendo eso, Class<List<String>>y Class<List<Map<Integer, ?>>>son totalmente la misma List.classparametrización de tipo perdedor, por lo tanto, Gson (des) serializa el trabajo sin tener en cuenta los tipos adecuados (LinkedHashTreeMap, por ejemplo, es un buen ejemplo, si recuerdo).
  • Gson trabaja principalmente con Typeesa es una interfaz de tipo súper para cualquier tipo que pueda ser representado por el sistema de tipos Java (incluidas las clases ParameterizedType, etc.). Ver https://google.github.io/gson/apidocs/com/google/gson/Gson.html#fromJson-java.lang.String-java.lang.reflect.Type-
  • TypeTokenes un buen ejemplo de un titular de tipo genérico en Java, incluido que produce información de tipo adecuada según cómo se compiló. Puede ser utilizado para hacer el tipo de método seguro: public static <T> T fromJson(String doc, TypeToken<? extends T> typeToken) { return sGson.fromJson(doc, typeToken.getType()); }. Los tokens de tipo se pueden almacenar en caché en campos finales estáticos públicos (sí) que contienen una parametrización real debido a que son inmutables y seguros para subprocesos entre subprocesos.

Prima:

  • No synchronizedes necesario allí: las Gsoninstancias también son seguras para subprocesos.
Respuesta: 3

Quiero hacer un sistema de inicio de sesión simple en Java sin usar databses. (PS. No hay datos confidenciales) Quiero hacer algo como esto: -1) Creo un archivo .txt -2) pon el nombre de usuario y la contraseña como ... .

Algunas cosas básicas que debería incluir incluyen ... Debe admitir la optimización local del tráfico http / https. Debe admitir la limitación de la cantidad de ejecución de JavaScript.

¿Cómo puedo obtener la identificación de un documento en Firestore? Final String PostKey = db.collection ("Anuncio"). document (). getId (); Estoy intentando de esta manera, pero devuelve una nueva identificación. ¿Cómo puede obtener la identificación de la a ...

Estoy tratando de iniciar una aplicación jws (usando el archivo jnlp) en Windows 7 de 64 bits y obtengo el siguiente problema. ERROR [L: org.apache.catalina.startup.ContextConfig F: T: 'javawsApplicationMain'] Excepción ...