2012-04-08 18 views
9

Tôi có đoạn mã này:GSON chuyển đổi để LinkedHashMap thay vì đối tượng của tôi

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

Khi tôi cố gắng để làm foreach đơn vị của tôi đối tượng không còn các loại Entity nhưng LinkedHashMap và tôi nhận được ngoại lệ này: java .lang.ClassCastException: java.util.LinkedHashMap không thể được đúc để com.tranca.bookstore.domain.shared.BaseObject

đây là lớp JSONObject (tạo ra bởi tôi)

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

}

lẽ các đối tượng cơ sở có liên quan vì vậy tôi sẽ đặt mã ở đây:

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

Bạn đang sử dụng Gson 2.1? –

Trả lời

1

Cuối cùng đã nhận nó!

Vấn đề là:.

mới TypeToken < JSONObject < Entity >>() {} getType();

trả về kiểu của JSONObject < T> không phải là thực thể cụ thể của lớp con đã được mở rộng Repository (ví dụ UserRepository kéo dài Repository < tài khoản>).

Bí quyết là tạo một phương thức trừu tượng để buộc các lớp con thiết lập Loại cho quá trình deserialization. Nếu bạn gặp lỗi này, hãy đảm bảo rằng bạn có đúng loại lớp (trong trường hợp bạn sử dụng các lớp con, hãy chắc chắn nó trả về kiểu của lớp con của bạn không phải là siêu lớp).

+6

Xin lỗi, tôi đang gặp vấn đề tương tự nhưng tôi không hiểu câu trả lời của bạn, bạn có thể làm rõ không? Cảm ơn! –

+1

@JonathanLeung: Nếu tôi hiểu chính xác, vấn đề là mỗi lần thực hiện biểu thức 'new TypeToken >() {}' là khởi tạo một cá thể của cùng một lớp ẩn danh. 'Entity' không thực sự là một lớp, nó chỉ là một tham số kiểu cho' Repository', vì vậy nó hoàn toàn bị xóa tại thời điểm này, thậm chí không thực sự thích hợp để phản chiếu. (Công cụ 'TypeToken' sử dụng sự phản chiếu để kiểm tra phân cấp lớp để bỏ qua việc xóa, nhưng nó không hoạt động khi chính lớp đó tham chiếu đến tham số kiểu.) – ruakh

+1

Xin lỗi. Một lần nữa câu trả lời của bạn không rõ ràng. Sẽ tốt nếu bạn có thể cung cấp một giải pháp có ý nghĩa. –

3

Tôi có cùng một sự cố tương tự. Để cung cấp một câu trả lời rõ ràng hơn trong một bối cảnh hơi khác nhau:

Tôi đã theo phương pháp mà tạo ra lỗi "com.google.gson.internal.LinkedTreeMap không thể được đúc để 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; 
    } 

tôi muốn một cách chung chung dễ dàng để đọc/ghi hashmap được liên kết. Giải pháp trên không hoạt động vì thông tin loại của TypeToken với TKey một TValue sẽ bị mất sau khi biên dịch theo như tôi hiểu. Và đây là vấn đề. Nếu bạn thay đổi mã của bạn thành ví dụ sau, thì nó hoạt động, bởi vì bây giờ chúng tôi xác định rõ ràng mã thông báo loại. Tôi không quá nhiều vào java mà tôi hiểu lý do tại sao trong trường hợp này có thể đọc thông tin kiểu khi chạy.

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

Và bây giờ bạn sẽ gọi hàm trên như:

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

Một sidenote 1: Khi writign bản đồ liên kết băm, bạn không cần phải xác định bất kỳ loại thẻ nào cả. toJson (bản đồ) là đủ.

Một sidenote 2 (cho một vấn đề mà tôi đã có): Theo mặc định gson sử dụng toString() để serialize phím. Nếu bạn đăng ký bộ điều hợp kiểu cho loại khóa có thể là loại phức tạp hơn, thì bộ điều hợp kiểu này không được áp dụng khi tuần tự hóa, nhưng khi deserializing. Điều này dẫn đến một quá trình không nhất quán và do đó không thành công. Các tùy chọn sau đây kích hoạt complex map key serialization.

gsonBuilder.enableComplexMapKeySerialization() 
+1

chủ yếu là 'gsonBuilder.enableComplexMapKeySerialization()' đã sửa lỗi của tôi – CrandellWS

Các vấn đề liên quan