[英]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考慮了類型信息:您正在嘗試混合Class
和Class<?>
,它們分別代表原始類型和通配符參數化類型的不同類型 。 從這個角度來看,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
實例不包含類型參數化(請參閱TypeToken
和ParameterizedType
的用途),您可能希望使用其所有類型參數化對類型進行編碼(易於toString(...)
但不容易解析 - 我曾經遇到過這樣的問題並通過在JParsec中實現解析器來解決它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.