2016-02-18 6 views
5

の原因シリアライズ、にStackOverflowErrorが発生します。Gsonは:java.nio.Pathはこれをシリアル化に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\\"); 
    } 
} 

それは私にはバグのように見えます!または私は何か間違っている? は(Stringにパスを変換し、いくつかのカスタム・シリアライザを書く期待)

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); 
} 
+0

http://stackoverflow.com/q/36964995/1032167詳細カスタムクラス 'PathConverterがJsonDeserializer 、JsonSerializer 'を実装し、 '.registerTypeHierarchyAdapter(Path.class、new MyPathConverter()) 'として登録してください。 – varren

答えて

3

は、デバッガでPaths.get("c:\\temp\\");によって返されたオブジェクトを調べます。私のマシンではを含むfsというフィールドがあります。これにはWindowsFileSystemProvider - とproviderを含むフィールドproviderがフィールドtheFileSystemにあり、元のfsと同じWindowsFileSystemを含んでいます。 Voila、循環参照。

Gsonは、リフレクションを使用して、与えられたオブジェクト内のすべての非過渡フィールドを再帰的に調べ、シリアライズします。このような循環参照は、それをStackOverflowErrorで終わる無限再帰に送ります。これを修正するには、カスタムシリアル化を実装するか、オブジェクト全体ではなくPathの特定のプロパティをシリアル化する必要があります。サイクルに含まれるフィールドのいずれかまたはすべてをtransientとしてマークすることもできますが、これにはライブラリのコードへの書き込みアクセスが必要です。

+1

私はそれを理解しています。しかし同時に、このクラスはJava 7以降のコアJavaクラスであり、Gsonによって正しく処理される必要があります。すべての開発者がこのクラスのために独自のシリアライザ/デシリアライザを実装する必要があるとは思えません。これはGsonの核となる機能です。 – lvr123

+1

5 @ lvr123これは 'Serializable'を実装しておらず、その目的はデータを解析、検証、操作し、それ以外の方法でデータを保存するのではなく、保存することです。 Gsonも他のシリアライゼーションライブラリも、シリアライゼーションは 'Path'のためのものではないので特別な取り扱いをするのに十分な理由はありません。 MapとCollectionの多くのサブインタフェースにはデータストレージが主目的であり、Gsonには特別な処理があります。 – Douglas

+2

このタイプのオブジェクトをシリアル化するためにあなたは何を提案しますか? – lvr123

関連する問題