2012-04-08 25 views
9

Mam ten fragment kodu:GSON konwertuje do LinkedHashMap zamiast mojego obiektu

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()) ; 
    } 
} 

Kiedy próbuję zrobić foreach moje podmioty obiekt jest już typu Entity ale LinkedHashMap i otrzymuję ten wyjątek: Java .lang.ClassCastException: java.util.LinkedHashMap nie mogą być oddane do com.tranca.bookstore.domain.shared.BaseObject

Tu jest klasa JSONObject (tworzone przez mnie)

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++; 
} 

}

może obiekt bazowy jest istotne tak położę kod tutaj:

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

Używasz Gson 2.1? –

Odpowiedz

1

wreszcie to!

Problem polegał na tym, że:.

nowy TypeToken < JSONObject < jednostki >>() {} gettype();

zwraca typ JSONObject < T> nie na konkretny podmiot podklasy, które było zwiększenie bazy danych (np UserRepository rozciąga repozytorium < użytkownik>).

Sztuką było stworzenie abstrakcyjnej metody wymuszenia na podklasach ustawienia Typu w celu deserializacji.

Podsumowując, jeśli otrzymasz ten błąd, upewnij się, że masz odpowiedni typ klasy (w przypadku, gdy korzystasz z podklas, upewnij się, że zwraca on typ twojej podklasy, która nie jest nadklasą).

+6

Niestety, mam podobny problem, ale nie rozumiem Twojej odpowiedzi. Czy mógłbyś wyjaśnić? Dzięki! –

+1

@ JonathanLeung: Jeśli rozumiem poprawnie, problem polega na tym, że każde wykonanie wyrażenia 'new TypeToken >() {}' tworzy instancję tej samej anonimowej klasy. 'Entity' nie jest tak naprawdę klasą, jest po prostu parametrem-typem' Repository', więc w tym momencie jest całkowicie wymazane, nawet nie do zaakceptowania. (Składnik 'TypeToken' używa refleksji do zbadania hierarchii klas, aby pominąć wymazanie, ale nie działa, gdy sama klasa odwołuje się do parametru typu.) – ruakh

+1

Przepraszam. Znowu twoja odpowiedź nie jest jasna. Byłoby dobrze, gdybyś mógł dostarczyć sensownego rozwiązania. –

3

Miałem ten sam/podobny problem. Aby nadać bardziej jasną odpowiedź w nieco innym kontekście:

miałem następującą metodę, który spowodował błąd „com.google.gson.internal.LinkedTreeMap nie może być rzutowany na 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; 
    } 

chciałem prosty ogólny sposób na łączenie się z hashapami do odczytu/zapisu. Powyższe rozwiązanie nie działa, ponieważ informacja o typie TypToken z TKey a TValue zostanie utracona po kompilacji, o ile rozumiem. I to jest problem. Jeśli zmienisz kod na następujący, to działa, ponieważ teraz jawnie definiujemy token typu. Nie jestem tak bardzo w java, że ​​rozumiem, dlaczego w tym przypadku możliwe jest odczytanie informacji o typie w czasie wykonywania.

/** 
    * 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; 
    } 

A teraz nazwałbym powyższej funkcji takich jak:

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

sidenote 1: Kiedy writign połączoną hash mapę, nie trzeba podać dowolny typ tokena w ogóle. ToJson (mapa) jest wystarczająca.

Urywek 2 (do problemu, który miałem): Domyślnie gson używa toString() do serializacji klucza. Jeśli zarejestrujesz adapter typu dla typu klucza, który jest być może bardziej złożonym typem, adapter tego typu nie zostanie zastosowany podczas szeregowania, ale przy deserializacji. Prowadzi to do niespójnego, a zatem niesprawnego procesu. Poniższe opcje aktywują complex map key serialization.

gsonBuilder.enableComplexMapKeySerialization() 
+1

przede wszystkim była to 'gsonBuilder.enableComplexMapKeySerialization()', która naprawiła mój problem – CrandellWS

Powiązane problemy