Gson:序列化期间发生StackOverflowError

dojqjjoe  于 2022-11-06  发布在  其他
关注(0)|答案(2)|浏览(229)

我写了这个类,我需要序列化字段gameTimer,它的类型是接口TimerP。

public class PlayerImpl implements Player {

@Expose
private final String nickname;
@Expose
private final TimerP gameTimer;
@Expose
private final int finalScore;

为了解决这个问题,我写了一个interfaceAdapter:

public class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {

private static final String CLASSNAME = "CLASSNAME";
private static final String DATA = "DATA";

@Override
public T deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException {
    JsonObject jsonObject = json.getAsJsonObject();
    JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
    String className = prim.getAsString();
    Class<?> c = this.getObjectClass(className);
        return context.deserialize(jsonObject.get(DATA), c);
}

@Override
public JsonElement serialize(final T src, final Type typeOfSrc, final JsonSerializationContext context) {
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty(CLASSNAME, src.getClass().getName());
    jsonObject.add(DATA, context.serialize(src));
    return jsonObject;
}

/******Helper method to get the className of the object to be deserialized.*****/
private Class<?> getObjectClass(final String className) {
    try {
        return Class.forName(className);
        } catch (ClassNotFoundException e) {
            //e.printStackTrace();
            throw new JsonParseException(e.getMessage());
        }
}

但在尝试序列化对象时会出现以下异常:

Caused by: java.lang.StackOverflowError
at com.google.gson.internal.$Gson$Types.canonicalize($Gson$Types.java:104)
at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:72)
at com.google.gson.reflect.TypeToken.get(TypeToken.java:296)
at com.google.gson.Gson.toJson(Gson.java:696)
at com.google.gson.Gson.toJsonTree(Gson.java:597)
at com.google.gson.Gson.toJsonTree(Gson.java:576)
at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.serialize(TreeTypeAdapter.java:155)
at common.InterfaceAdapter.serialize(InterfaceAdapter.java:33)
at common.InterfaceAdapter.serialize(InterfaceAdapter.java:15)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.Gson.toJson(Gson.java:704)
at com.google.gson.Gson.toJsonTree(Gson.java:597)
at com.google.gson.Gson.toJsonTree(Gson.java:576)
at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.serialize(TreeTypeAdapter.java:155)

这是我读和写文件的类:

public class LeaderboardImpl implements Leaderboard {

private final File directory = new File(System.getProperty("user.home"), ".unitype");
private final File file = new File(directory, FILE_NAME);
private static final String FILE_NAME = "unitype.json";

/**
 * Returns the instance of this class.
 * 
 * @return the instance of this class
 */
public static LeaderboardImpl getLeaderboard() {
    return LazyHolderLeaderboard.SINGLETON;
}

/**
 * {@inheritDoc}
 */
@Override
public void addPlayer(final Player p) {
    final Gson gson = new GsonBuilder()
                        .excludeFieldsWithoutExposeAnnotation()
                        .registerTypeHierarchyAdapter(TimerP.class, new InterfaceAdapter<TimerP>())
                        .create();
    final List<Player> playersList = this.getPlayersList();
    playersList.add(p);
    final String json = gson.toJson(playersList);
    this.checkFile();
    try (FileWriter writer = new FileWriter(file)) {
        writer.write(json);
        writer.flush();
    } catch (JsonIOException | IOException e) {
        e.printStackTrace();
    }
}

/**
 * {@inheritDoc}
 */
@Override
public List<Player> getPlayersList() {
    final Gson gson = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .registerTypeHierarchyAdapter(TimerP.class, new InterfaceAdapter<TimerP>())
            .create();
    List<Player> playersList = new ArrayList<>();
    this.checkFile();
    try (JsonReader jsonReader = new JsonReader(new FileReader(file))) {
        final JsonElement js = JsonParser.parseReader(jsonReader);
        if (js.isJsonObject()) {
            final JsonObject jsonObject = js.getAsJsonObject();
            playersList.add(gson.fromJson(jsonObject, PlayerImpl.class));
        } else if (js.isJsonArray()) {
            playersList = gson.fromJson(js,
                    new TypeToken<List<PlayerImpl>>() { }.getType());
        }
    } catch (JsonSyntaxException | JsonIOException | IOException e) {
        e.printStackTrace();
    }
    return playersList;
}

我尝试了所有的方法,但我找不到任何解决方案,我不明白为什么它不工作

tp5buhyn

tp5buhyn1#

对海报来说太晚了,但也许对任何也跌跌撞撞地陷入这个陷阱的人(像我)来说都太晚了。互联网上的一些博客也提出了这种解决方案。然而,他们使用registerTypeAdapter而不是registerTypeHierarchyAdapter
有趣的注解:反之亦然,也有 registerTypeAdapter 导致堆栈溢出而 registerTypeHierarchyAdapter 正常工作的情况,请参阅here

kgqe7b3p

kgqe7b3p2#

使用另一个gson(new Gson())

@Override
public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
    final JsonObject wrapper = new JsonObject();
    wrapper.addProperty("type", object.getClass().getName());
    wrapper.add("data", new Gson().toJsonTree(object));
    return wrapper;
}

相关问题