循环引用-Gson StackOverflowError

时间:2019-12-27 15:53:21

标签: java gson

我很难弄清楚为什么使用 Gson 将以下对象保存到.json文件中会引发 StackOverflowError 。我在某处有循环引用吗?

这是我要用Gson保存的对象:

public class LocationConfig {

    private HashSet<Warp> warps = new HashSet<>();

    public LocationConfig() {
        warps.add(new Warp("placeholder", false, new Location(Bukkit.getWorld("world"), 0, 0, 0)));
    }

    // getter and setter

}

LocationConfig在其HashSet Warp中使用以下warps类:

public class Warp {

    private String name;
    private boolean ifListed;
    private Location loc;

    public Warp(String name, boolean ifListed, Location loc) {
        this.name = name;
        this.ifListed = ifListed;
        this.loc = loc;
    }

    // getter and setter

}

我正在使用以下内容保存LocationConfig对象:

// config is an object of the type LocationConfig
if (config != null) {

    Gson gson = new GsonBuilder().setPrettyPrinting().create();

    try (FileWriter writer = new FileWriter(path)) {
        gson.toJson(config, writer);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

执行gson.toJson(config, writer)时出现错误:

[16:12:42] [Server thread/WARN]: java.lang.StackOverflowError
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:383)
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:378)
repeating very often
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:158)
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:100)
[16:12:42] [Server thread/WARN]:    at com.google.gson.Gson.getAdapter(Gson.java:423)
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:115)
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:164)
[16:12:42] [Server thread/WARN]:    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:100)
[16:12:42] [Server thread/WARN]:    at com.google.gson.Gson.getAdapter(Gson.java:423)
repeating very often

谢谢!

1 个答案:

答案 0 :(得分:0)

问题是,我正在使用名为Spigot的Minecraft Server API的Location类。为了解决该问题,我必须使用比提供的对象简单得多的Location对象。

comments中所述:

  

通常会对此错误进行怀疑的是循环引用或在不知不觉中放置了复杂对象

对我来说,解决方案是此类SimpleLocation,因为它不包含任何复杂的引用:

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.util.Vector;

public class SimpleLocation {

    private double x;
    private double y;
    private double z;
    private Vector direction;
    private String worldname;

    public SimpleLocation(String worldname, double x, double y, double z, Vector direction) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.direction = direction;
        this.worldname = worldname;
    }

    public SimpleLocation(Location loc) {
        this.x = loc.getX();
        this.y = loc.getY();
        this.z = loc.getZ();
        this.direction = loc.getDirection();
        if (loc.getWorld() != null) {
            this.worldname = loc.getWorld().getName();
        } else {
            throw new NullPointerException("The locations world is null!");
        }
    }

    public Location getLocation() {
        return new Location(Bukkit.getWorld(worldname), x, y, z).setDirection(direction);
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public double getZ() {
        return z;
    }

    public void setZ(double z) {
        this.z = z;
    }

    public Vector getDirection() {
        return direction;
    }

    public void setDirection(Vector direction) {
        this.direction = direction;
    }

    public String getWorldname() {
        return worldname;
    }

    public void setWorldname(String worldname) {
        this.worldname = worldname;
    }

}