格森Java-尝试序列化java.lang.Class:.....忘记注册类型适配器? [英] Gson & Java - Attempted to serialize java.lang.Class: ..... Forgot to register a type adapter?

查看:63
本文介绍了格森Java-尝试序列化java.lang.Class:.....忘记注册类型适配器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个抽象类来定义配置类.我希望在需要时将这些类从JSON导出和导入.我正在尝试使用Gson实现这一目标.

I'm trying to create an abstract class for defining configuration classes. I wish to export and import these classes from and to JSON whenever I want to. I'm trying to achieve this using Gson.

写入JSON时报错:

无法序列化java.lang.Class-忘记注册类型适配器了?

can't serialize java.lang.Class - Forgot to register a type adapter?

我的主班: https://hastebin.com/pogohodovi.scala
抽象配置类: https://hastebin.com/adeyawubuy.cs

子类的示例:

public class DyescapeCOREConfiguration extends DyescapeConfiguration {

    private static transient DyescapeCOREConfiguration i = new DyescapeCOREConfiguration();
    public static DyescapeCOREConfiguration get() { return i; }

    @Expose public static String ServerID = UUID.randomUUID().toString();

}

请注意:我需要将子配置类中的变量保持静态.我尝试创建一些适配器/序列化器,但它们似乎不起作用.

Please note: I need to keep the variables in the child configuration classes static. I tried to create some adapters/serializers, but they don't seem to work.

推荐答案

您可能正在做:

gson.toJson(DyescapeCOREConfiguration.class)

为了序列化此类,您仍然必须创建 DyescapeCOREConfiguration 的实例.由于 static 默认情况下不进行反序列化,因此您必须启用它们(恕我直言,启用这样的修饰符确实不是一个好主意):

In order to serialize this class, you still must create an instance of DyescapeCOREConfiguration. Since statics are not (de)serialized by default, you have to enable them (IMHO, enabling such modifier is really not a good idea):

    final Gson gson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .excludeFieldsWithModifiers(TRANSIENT) // STATIC|TRANSIENT in the default configuration
            .create();
    final String json = gson.toJson(new DyescapeCOREConfiguration());
    System.out.println(json);

输出:

{"ServerID":"37145480-64b9-4beb-b031-2d619f14a44b"}

{"ServerID":"37145480-64b9-4beb-b031-2d619f14a44b"}


更新

如果由于某种原因无法获得实例,请编写一个自定义的 Class<?> 类型适配器(我在实践中不会使用它):


Update

If obtaining an instance is not possible for whatever reason, write a custom Class<?> type adapter (I would never use it in practice):

final class StaticTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeAdapterFactory staticTypeAdapterFactory = new StaticTypeAdapterFactory();

    private StaticTypeAdapterFactory() {
    }

    static TypeAdapterFactory getStaticTypeAdapterFactory() {
        return staticTypeAdapterFactory;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final Type type = typeToken.getType();
        if ( type.equals(Class.class) ) {
            @SuppressWarnings("unchecked")
            final TypeAdapter<T> castStaticTypeAdapter = (TypeAdapter<T>) getStaticTypeAdapter(gson);
            return castStaticTypeAdapter;
        }
        return null;
    }

}

StaticTypeAdapter.java

final class StaticTypeAdapter<T>
        extends TypeAdapter<Class<T>> {

    private static final String TARGET_CLASS_PROPERTY = "___class";

    private final Gson gson;

    private StaticTypeAdapter(final Gson gson) {
        this.gson = gson;
    }

    static <T> TypeAdapter<Class<T>> getStaticTypeAdapter(final Gson gson) {
        return new StaticTypeAdapter<>(gson);
    }

    @Override
    @SuppressWarnings("resource")
    public void write(final JsonWriter out, final Class<T> value)
            throws IOException {
        try {
            final Iterator<Field> iterator = Stream.of(value.getFields())
                    .filter(f -> isStatic(f.getModifiers()))
                    .iterator();
            out.beginObject();
            while ( iterator.hasNext() ) {
                final Field field = iterator.next();
                out.name(field.getName());
                field.setAccessible(true);
                final Object fieldValue = field.get(null);
                @SuppressWarnings({ "unchecked", "rawtypes" })
                final TypeAdapter<Object> adapter = (TypeAdapter) gson.getAdapter(field.getType());
                adapter.write(out, fieldValue);
            }
            out.name(TARGET_CLASS_PROPERTY);
            out.value(value.getName());
            out.endObject();
        } catch ( final IllegalAccessException ex ) {
            throw new IOException(ex);
        }
    }

    @Override
    public Class<T> read(final JsonReader in)
            throws IOException {
        try {
            Class<?> type = null;
            in.beginObject();
            final Map<String, JsonElement> buffer = new HashMap<>();
            while ( in.peek() != END_OBJECT ) {
                final String property = in.nextName();
                switch ( property ) {
                case TARGET_CLASS_PROPERTY:
                    type = Class.forName(in.nextString());
                    break;
                default:
                    // buffer until the target class name is known
                    if ( type == null ) {
                        final TypeAdapter<JsonElement> adapter = gson.getAdapter(JsonElement.class);
                        final JsonElement jsonElement = adapter.read(in);
                        buffer.put(property, jsonElement);
                    } else {
                        // flush the buffer
                        if ( !buffer.isEmpty() ) {
                            for ( final Entry<String, JsonElement> e : buffer.entrySet() ) {
                                final Field field = type.getField(e.getKey());
                                final Object value = gson.getAdapter(field.getType()).read(in);
                                field.set(null, value);
                            }
                            buffer.clear();
                        }
                        final Field field = type.getField(property);
                        if ( isStatic(field.getModifiers()) ) {
                            final TypeAdapter<?> adapter = gson.getAdapter(field.getType());
                            final Object value = adapter.read(in);
                            field.set(null, value);
                        }
                    }
                    break;
                }
            }
            in.endObject();
            // flush the buffer
            if ( type != null && !buffer.isEmpty() ) {
                for ( final Entry<String, JsonElement> e : buffer.entrySet() ) {
                    final Field field = type.getField(e.getKey());
                    final Object value = gson.fromJson(e.getValue(), field.getType());
                    field.set(null, value);
                }
                buffer.clear();
            }
            @SuppressWarnings({ "unchecked", "rawtypes" })
            final Class<T> castType = (Class) type;
            return castType;
        } catch ( final ClassNotFoundException | NoSuchFieldException | IllegalAccessException ex ) {
            throw new IOException(ex);
        }
    }

}

示例用法:

final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(getStaticTypeAdapterFactory())
        .create();
final String json = gson.toJson(DyescapeCOREConfiguration.class);
out.println("DyescapeCOREConfiguration.ServerID=" + DyescapeCOREConfiguration.ServerID);
// ---
DyescapeCOREConfiguration.ServerID = "whatever";
out.println("DyescapeCOREConfiguration.ServerID=" + DyescapeCOREConfiguration.ServerID);
// ---
@SuppressWarnings("unchecked")
final Class<DyescapeCOREConfiguration> configurationClass = gson.fromJson(json, Class.class);
//    ^--- this is awful, omitting a useless assignment is even worse
out.println("DyescapeCOREConfiguration.ServerID=" + DyescapeCOREConfiguration.ServerID);

输出:

DyescapeCOREConfiguration.ServerID = 012fa795-abd8-4b91-b6f5-bab67f73ae17
DyescapeCOREConfiguration.ServerID =任何
DyescapeCOREConfiguration.ServerID = 012fa795-abd8-4b91-b6f5-bab67f73ae17

DyescapeCOREConfiguration.ServerID=012fa795-abd8-4b91-b6f5-bab67f73ae17
DyescapeCOREConfiguration.ServerID=whatever
DyescapeCOREConfiguration.ServerID=012fa795-abd8-4b91-b6f5-bab67f73ae17

但是,我仍然建议您避免使用静态字段(反序列化)的想法.

However, I still recommend you to avoid the idea of static fields (de)serialization.

这篇关于格森Java-尝试序列化java.lang.Class:.....忘记注册类型适配器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆