[英]Gson, can't serialize/deserialize class type
I've got a class like this: 我有一个这样的课:
public class A {
@serializedName("type")
Class<?> type;
...
}
But when I tried to serialize it I get an error saying "Attempt to serialize java.lang.class: java.lang.String. Forgot to register a TypeAdapter?". 但是当我尝试序列化它时,我收到一条错误,说“尝试序列化java.lang.class:java.lang.String。忘记注册一个TypeAdapter?”。 So I created this adapter:
所以我创建了这个适配器:
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());
}
}
} }
And registered it like this: 并注册如下:
new GsonBuilder().registerTypeAdapter(Class.class, new MyTypeAdapter ()).create().
fromJson(value, listType);
But I'm still getting the same error. 但我仍然得到同样的错误。
What am I doing wrong? 我究竟做错了什么?
Does the implementation of the adapter look ok? 适配器的实现看起来不错吗?
What am I doing wrong?
我究竟做错了什么?
Gson takes type information into account: you're trying to mix Class
and Class<?>
that are different types representing a raw type and a wildcard-parameterized type respectively. Gson考虑了类型信息:您正在尝试混合
Class
和Class<?>
,它们分别代表原始类型和通配符参数化类型的不同类型 。 From this perspective, Gson does not consider Class
(found in your registerTypeAdapter
) and Class<?>
(found in your DTOs) equivalent. 从这个角度来看,Gson不会考虑
Class
(在您的registerTypeAdapter
找到)和Class<?>
(在您的DTO中找到)等效。 For this case you have to register the type hierarchy adapter with registerTypeHierarchyAdapter
. 对于这种情况,你必须注册类型层次结构适配器
registerTypeHierarchyAdapter
。
Does the implementation of the adapter look ok?
适配器的实现看起来不错吗?
Yes, but it can be improved slightly: 是的,但可以略微改进:
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);
}
}
}
As it's said by @Daniel Pryden , this is potentially a huge security issue, because Class.forName
may execute code (static initializers). 因为它是说通过@Daniel Pryden ,这是一个潜在的巨大的安全问题,因为
Class.forName
可以执行代码(静态初始化)。 You should check the className
against the classes whitelist before Class.forName(...)
is executed. 在执行
Class.forName(...)
之前,应该针对类白名单检查className
。 Also note that Class
instances do not hold type parameterization (please see what TypeToken
s and ParameterizedType
s are for) and you might want to encode the type with all of its type parameterization (easy to toString(...)
but not that easy to parse though - I faced such an issue once and resolved it by implementing a parser in JParsec). 另请注意,
Class
实例不包含类型参数化(请参阅TypeToken
和ParameterizedType
的用途),您可能希望使用其所有类型参数化对类型进行编码(易于toString(...)
但不容易解析 - 我曾经遇到过这样的问题并通过在JParsec中实现解析器来解决它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.