简体   繁体   English

Gson,无法序列化/反序列化类类型

[英]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考虑了类型信息:您正在尝试混合ClassClass<?> ,它们分别代表原始类型和通配符参数化类型的不同类型 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实例不包含类型参数化(请参阅TypeTokenParameterizedType的用途),您可能希望使用其所有类型参数化对类型进行编码(易于toString(...)但不容易解析 - 我曾经遇到过这样的问题并通过在JParsec中实现解析器来解决它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM