【问题标题】:Gson: serializing a java.nio.Path causes a StackOverflowErrorGson:序列化 java.nio.Path 会导致 StackOverflowError
【发布时间】:2016-02-18 22:39:35
【问题描述】:

对此进行序列化,会导致 StackOverFlowError :

import java.nio.file.Path;
import java.nio.file.Paths;

public class Tmp{
    private Path path=null;
    public Tmp() {
        path=Paths.get("c:\\temp\\");
    }
}

对我来说它看起来像一个错误!或者我做错了什么? 是否有解决方法(期望编写一些将路径转换为字符串的自定义序列化程序)

java.lang.StackOverflowError
    at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:372)

    at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:381)
    at com.google.gson.internal.$Gson$Types.resolve($Gson$Types.java:376)
    ...
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:128)

    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:75)
    at com.google.gson.Gson.getAdapter(Gson.java:358)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:109)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.access$100(ReflectiveTypeAdapterFactory.java:46)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:84)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:83)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:129)
    ...

序列化方法是:

public static void saveTo(BatchLogging logging, Path path) throws IOException {
    Gson gson=new GsonBuilder().setPrettyPrinting().create();
    // String json = gson.toJson(logging);
    String json = gson.toJson(new Tmp());
    List<String> lines = Arrays.asList(json.split(System.lineSeparator()));
    Files.write(path, lines, StandardCharsets.UTF_8);
}

【问题讨论】:

  • stackoverflow.com/q/36964995/1032167 更多信息。创建自定义class PathConverter implements JsonDeserializer&lt;Path&gt;, JsonSerializer&lt;Path&gt;并注册为.registerTypeHierarchyAdapter(Path.class, new MyPathConverter())

标签: java serialization gson


【解决方案1】:

在调试器中检查Paths.get("c:\\temp\\"); 返回的对象。在我的机器上,它有一个名为fs 的字段,其中包含WindowsFileSystem。这又具有一个字段provider,其中包含一个WindowsFileSystemProvider - 并且provider 具有一个字段theFileSystem,其中包含与原始WindowsFileSystem 相同的WindowsFileSystem 字段。瞧,循环引用。

Gson 使用反射来递归地检查和序列化你给它的对象中的每个非瞬态字段。像这样的循环引用将其发送到无限递归中,以StackOverflowError 结束。要解决此问题,您将需要实现自定义序列化或序列化 Path 的特定属性而不是整个对象。将循环中涉及的任何或所有字段标记为transient 也可以,但这需要对库代码的写入权限。

【讨论】:

  • 我明白这一点。但同时,这个类是Java 7以来的核心Java类,应该由Gson正确处理。我不认为每个开发人员都必须为这个类实现自己的序列化器/反序列化器。这应该是 Gson 的核心特性。
  • @lvr123 它没有实现Serializable,它的主要目的是解析、验证、操作和以其他方式使用数据,而不是存储它。 Gson 和任何其他序列化库都没有充分的理由对其进行特殊处理,因为序列化不是 Path 的用途。 Map 和 Collection 的许多子接口都以数据存储为主要目的,Gson 确实对这些进行了特殊处理。
  • 你建议如何序列化这种类型的 Object ?
【解决方案2】:

您可以使用ExclusionStrategy 排除某些类型的类,也可以使用GsonBuilder.registerTypeAdapter 实现自定义序列化/反序列化。
check out the docs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    相关资源
    最近更新 更多