Gson & Java - 尝试序列化 java.lang.Class: ..... 忘记注册类型适配器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41937303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Gson & Java - Attempted to serialize java.lang.Class: ..... Forgot to register a type adapter?
提问by Dennis van der Veeke
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 导出和导入这些类。我正在尝试使用 Gson 来实现这一点。
I'm getting an error when writing to JSON that states it:
写入 JSON 时出现错误,说明它:
can't serialize java.lang.Class - Forgot to register a type adapter?
无法序列化 java.lang.Class - 忘记注册类型适配器?
My main class: https://hastebin.com/pogohodovi.scala
Abstract config class: https://hastebin.com/adeyawubuy.cs
我的主类:https: //hastebin.com/pogohodovi.scala
抽象配置类:https: //hastebin.com/adeyawubuy.cs
An example of a child class:
一个子类的例子:
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.
请注意:我需要将子配置类中的变量保持为静态。我尝试创建一些适配器/序列化器,但它们似乎不起作用。
采纳答案by Lyubomyr Shaydariv
You're probably doing:
你可能正在做:
gson.toJson(DyescapeCOREConfiguration.class)
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 enablethem (IMHO, enabling such modifier is really not a good idea):
为了序列化这个类,你仍然必须创建一个DyescapeCOREConfiguration. 由于statics 默认情况下没有(反)序列化,因此您必须启用它们(恕我直言,启用此类修饰符确实不是一个好主意):
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);
The output:
输出:
{"ServerID":"37145480-64b9-4beb-b031-2d619f14a44b"}
{"ServerID":"37145480-64b9-4beb-b031-2d619f14a44b"}
Update
更新
If obtaining an instance is not possible for whatever reason, write a custom Class<?>type adapter (I would never use it in practice):
如果由于某种原因无法获取实例,请编写自定义Class<?>类型适配器(我永远不会在实践中使用它):
StaticTypeAdapterFactory.java
静态类型适配器工厂.java
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
静态类型适配器.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);
}
}
}
Example use:
使用示例:
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);
Output:
输出:
DyescapeCOREConfiguration.ServerID=012fa795-abd8-4b91-b6f5-bab67f73ae17
DyescapeCOREConfiguration.ServerID=whatever
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.
但是,我仍然建议您避免使用静态字段(反)序列化的想法。

