循环引用 - Gson StackOverflowError

Circular reference - Gson StackOverflowError

我无法弄清楚为什么使用 Gson 将以下对象保存到 .json 文件会抛出 WhosebugError.我在某处有循环引用吗?

这是我试图用 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

}

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

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.WhosebugError
[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

谢谢!

问题是,我正在使用名为 Spigot 的 Minecraft 服务器 API 的位置 class。为了解决这个问题,我不得不使用一个比提供的对象简单得多的 Location 对象。

所述:

Usual suspects for this error are either circular references or unknowingly put complex objects

我的解决方案是 SimpleLocation class,因为它不包含任何复杂的引用:

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;
    }

}