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 static
s are not (de)serialized by default, you have to enablethem (IMHO, enabling such modifier is really not a good idea):
为了序列化这个类,你仍然必须创建一个DyescapeCOREConfiguration
. 由于static
s 默认情况下没有(反)序列化,因此您必须启用它们(恕我直言,启用此类修饰符确实不是一个好主意):
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.
但是,我仍然建议您避免使用静态字段(反)序列化的想法。