簡體   English   中英

Gson,無法序列化/反序列化類類型

[英]Gson, can't serialize/deserialize class type

我有一個這樣的課:

public class A {
    @serializedName("type")
    Class<?> type;
...
}

但是當我嘗試序列化它時,我收到一條錯誤,說“嘗試序列化java.lang.class:java.lang.String。忘記注冊一個TypeAdapter?”。 所以我創建了這個適配器:

public class MyTypeAdapter extends TypeAdapter<Class> {
public Class read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
    } else {
        String className = in.nextString();
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new JsonParseException("class " + className + " not found");
        }
    }
}

public void write(JsonWriter out, Class value) throws IOException {
    if (value == null) {
        out.nullValue();
    } else {
        out.value(value.getName());
    }
}

}

並注冊如下:

new GsonBuilder().registerTypeAdapter(Class.class, new MyTypeAdapter ()).create().
fromJson(value, listType);

但我仍然得到同樣的錯誤。
我究竟做錯了什么?
適配器的實現看起來不錯嗎?

我究竟做錯了什么?

Gson考慮了類型信息:您正在嘗試混合ClassClass<?> ,它們分別代表原始類型和通配符參數化類型的不同類型 從這個角度來看,Gson不會考慮Class (在您的registerTypeAdapter找到)和Class<?> (在您的DTO中找到)等效。 對於這種情況,你必須注冊類型層次結構適配器registerTypeHierarchyAdapter

適配器的實現看起來不錯嗎?

是的,但可以略微改進:

final class ClassTypeAdapter
        extends TypeAdapter<Class<?>> {

    // The type adapter does not hold state, so it can be easily made singleton (+ making the constructor private)
    private static final TypeAdapter<Class<?>> instance = new ClassTypeAdapter()
            // This is a convenient method that can do trivial null-checks in write(...)/read(...) itself
            .nullSafe();

    private ClassTypeAdapter() {
    }

    static TypeAdapter<Class<?>> get() {
        return instance;
    }

    @Override
    public void write(final JsonWriter out, final Class<?> value)
            throws IOException {
        // value is never a null here
        out.value(value.getName());
    }

    @Override
    public Class<?> read(final JsonReader in)
            throws IOException {
        try {
            // This will never be a null since nullSafe() is used above
            final String className = in.nextString();
            return Class.forName(className);
        } catch ( final ClassNotFoundException ex ) {
            // No need to duplicate the message generated in ClassNotFoundException
            throw new JsonParseException(ex);
        }
    }

}

因為它是通過@Daniel Pryden ,這是一個潛在的巨大的安全問題,因為Class.forName可以執行代碼(靜態初始化)。 在執行Class.forName(...)之前,應該針對類白名單檢查className 另請注意, Class實例不包含類型參數化(請參閱TypeTokenParameterizedType的用途),您可能希望使用其所有類型參數化對類型進行編碼(易於toString(...)但不容易解析 - 我曾經遇到過這樣的問題並通過在JParsec中實現解析器來解決它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM