2012-04-08 16 views
9

tengo este fragmento de código:GSON convierte a LinkedHashMap en lugar de mi objeto

public abstract class Repository<Entity extends BaseObject> { 

... 

public void readFromJson(){ 
    String content = "JSON content here"; 
    Gson gson = new Gson(); 
    Type entityType = new TypeToken<JSONObject<Entity>>(){}.getType(); 

    jsonObject = gson.fromJson(content, entityType); 

    for (Entity ent : jsonObject.getEntities()) ; 
    } 
} 

Cuando trato de hacer lo foreach mis entidades objeto ya no es del tipo de entidad pero LinkedHashMap y me sale esta excepción: java .lang.ClassCastException: java.util.LinkedHashMap no se puede convertir a com.tranca.bookstore.domain.shared.BaseObject

Aquí está la clase JSONObject (creado por mí)

public class JSONObject<Entity> { 

private List<Entity> entities = new ArrayList<Entity>(); 
private long lastId = -1; 
public List<Entity> getEntities() { 
    return entities; 
} 
public void setEntities(List<Entity> entities) { 
    this.entities = entities; 
} 
public long getLastId() { 
    return lastId; 
} 
public void setLastId(long lastId) { 
    this.lastId = lastId; 
} 

public void incrementLastId() { 
    this.lastId++; 
} 

}

tal vez el objeto base es relevante por lo que pondrá el código aquí:

public abstract class BaseObject implements Serializable { 

protected long id = (long) -1; 
protected int version = 0; 

protected BaseObject(){} 

public long getId() { 
    return id; 
} 
public void setId(long id) { 
    this.id = id; 
} 
public int getVersion() { 
    return version; 
} 
public void setVersion(int version) { 
    this.version = version; 
} 

} 
+0

¿Estás utilizando Gson 2.1? –

Respuesta

1

Finalmente lo consiguió!

El problema era que:.

nueva TypeToken < JSONObject < Entidad >>() {} getType();

devuelve el tipo de JSONObject < T> no la entidad específica de la subclase que se extiende repositorio (por ejemplo UserRepository extiende Repositorio < usuario>).

El truco fue crear un método abstracto para forzar a las subclases a establecer el Tipo para la deserialización.

En conclusión, si obtiene este error, asegúrese de tener el tipo correcto de clase (en caso de que use subclases, asegúrese de que devuelva el tipo de subclase no superclase).

+6

Disculpa, me encuentro con el mismo problema pero no entiendo tu respuesta, ¿podrías aclarar? ¡Gracias! –

+1

@JonathanLeung: Si entiendo correctamente, el problema es que cada ejecución de la expresión 'new TypeToken >() {}' está creando una instancia de la misma clase anónima. 'Entity' no es realmente una clase, es solo un parámetro de tipo para' Repository', por lo que está completamente borrado en este punto, ni siquiera es realmente susceptible de reflexión. (El elemento 'TypeToken' utiliza la reflexión para examinar la jerarquía de clases para eludir el borrado, pero no funciona cuando la clase misma se refiere a un parámetro de tipo). – ruakh

+1

Lo siento. De nuevo, tu respuesta no está clara. Sería bueno si puede proporcionar una solución significativa. –

3

Tuve el mismo/un problema similar. Para dar una respuesta más clara en un contexto ligeramente diferente:

Había siguiente método que produce el error "com.google.gson.internal.LinkedTreeMap no se puede convertir a MyType":

/** 
    * Reads a LinkedHashMap from the specified parcel. 
    * 
    * @param <TKey> 
    *   The type of the key. 
    * @param <TValue> 
    *   The type of the value. 
    * @param in 
    *   The in parcel. 
    * @return Returns an instance of linked hash map or null. 
    */ 
    public static <TKey, TValue> LinkedHashMap<TKey, TValue> readLinkedHashMap(Parcel in) { 
    Gson gson = JsonHelper.getGsonInstance(); 
    String content = in.readString(); 
    LinkedHashMap<TKey, TValue> result = gson.fromJson(content, new TypeToken<LinkedHashMap<TKey, TValue>>(){}.getType()); 
    return result; 
    } 

quería una forma genérica fácil de leer/escribir hashmap vinculado. La solución anterior no funciona porque la información de tipo de TypeToken con TKey y TValue se perderá después de la compilación, por lo que yo entiendo. Y este es el problema. Si cambia su código al siguiente ejemplo, entonces funciona, porque ahora definimos explícitamente el token de tipo. No estoy tan interesado en Java que entiendo por qué en este caso es posible leer la información de tipo en tiempo de ejecución.

/** 
    * Reads a LinkedHashMap from the specified parcel. 
    * 
    * @param <TKey> 
    *   The type of the key. 
    * @param <TValue> 
    *   The type of the value. 
    * @param in 
    *   The in parcel. 
    * @return Returns an instance of linked hash map or null. 
    */ 
    public static <TKey, TValue> LinkedHashMap<TKey, TValue> readLinkedHashMap(Parcel in, TypeToken<LinkedHashMap<TKey, TValue>> typeToken) { 
    Gson gson = JsonHelper.getGsonInstance(); 
    Type type = typeToken.getType(); 
    String content = in.readString(); 
    LinkedHashMap<TKey, TValue> result = gson.fromJson(content, type); 
    return result; 
    } 

Y ahora que llamarían la función anterior como:

readLinkedHashMap(in, new TypeToken<LinkedHashMap<UUID, MyObject>>(){}); 

sidenote 1: Cuando writign la correlación hash vinculado, no es necesario especificar cualquier tipo de señal en absoluto. toJson (mapa) es suficiente.

Una nota al margen 2 (a un problema que tuve): Por defecto gson usa toString() para serializar la clave. Si registra un tipo de adaptador para el tipo de clave que es quizás un tipo más complejo, este adaptador de tipo no se aplica al serializar, sino al deserializar. Esto conduce a un proceso no consistente y, por lo tanto, que falla. Las siguientes opciones activan complex map key serialization.

gsonBuilder.enableComplexMapKeySerialization() 
+1

principalmente fue 'gsonBuilder.enableComplexMapKeySerialization()' que solucionó mi problema – CrandellWS

Cuestiones relacionadas