2016-02-18 18 views
5

Serializing này, gây ra một StackOverflowError:Gson: serializing một java.nio.Path gây ra một 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\\"); 
    } 
} 

Nó trông giống như một lỗi cho tôi! Hay tôi đang làm gì sai? Có workaround (hy vọng viết một số serializer tùy chỉnh có thể chuyển đổi các đường dẫn đến chuỗi)

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) 
    ... 

phương pháp Serializing là:

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 thông tin khác. Tạo tùy chỉnh 'lớp PathConverter thực hiện JsonDeserializer , JsonSerializer ' và đăng ký nó như '.registerTypeHierarchyAdapter (Path.class, new MyPathConverter())' – varren

Trả lời

3

Kiểm tra đối tượng được trả về bởi Paths.get("c:\\temp\\"); trong một trình gỡ lỗi. Trên máy của tôi, nó có một trường có tên là fs có chứa một WindowsFileSystem. Điều này, đến lượt nó, có một trường provider có chứa một WindowsFileSystemProvider - và provider có một trường theFileSystem có chứa cùng một trường WindowsFileSystem làm trường gốc fs. Voila, tham khảo tuần hoàn.

Gson sử dụng phản chiếu để kiểm tra và tuần tự hóa, đệ quy, mọi trường không phải là thoáng qua trong đối tượng bạn cung cấp. Một tham chiếu chu kỳ như thế này sẽ gửi nó vào đệ quy vô hạn, kết thúc bằng StackOverflowError. Để khắc phục điều này, bạn sẽ cần thực hiện tuần tự hóa tùy chỉnh hoặc tuần tự hóa một thuộc tính cụ thể của Path thay vì toàn bộ đối tượng. Đánh dấu bất kỳ hoặc tất cả các trường liên quan đến chu kỳ là transient cũng sẽ hoạt động, nhưng điều đó sẽ yêu cầu quyền ghi vào mã của thư viện.

+1

Tôi hiểu điều đó. Nhưng đồng thời, lớp này là một lớp Java cốt lõi từ Java 7 và nên được xử lý một cách chính xác bởi Gson. Tôi không tìm thấy nó âm thanh mà mỗi nhà phát triển phải thực hiện serializer của riêng mình/deserializer cho lớp này. Đây sẽ là một tính năng cốt lõi của Gson. – lvr123

+1

@ lvr123 Nó không thực hiện 'Serializable' và mục đích của nó chủ yếu là phân tích cú pháp, xác thực, thao tác và sử dụng dữ liệu, không lưu trữ dữ liệu. Cả Gson lẫn bất kỳ thư viện tuần tự hóa nào khác đều có lý do chính đáng để xử lý đặc biệt vì việc tuần tự hóa không phải là những gì 'Đường dẫn' là cho. Bản đồ và nhiều giao diện con của Bộ sưu tập có lưu trữ dữ liệu là mục đích chính của chúng và Gson không có xử lý đặc biệt cho những mục đích đó. – Douglas

+2

Bạn đề xuất gì để sắp xếp loại đối tượng này? – lvr123

Các vấn đề liên quan