2016-08-01 16 views
8

Ngôn ngữ Java được hưởng lợi nhiều từ việc thêm enums vào nó; nhưng tiếc là chúng không hoạt động tốt khi gửi các đối tượng được tuần tự hóa giữa các hệ thống có các mức mã khác nhau.Có các lựa chọn thay thế tốt để tuần tự hóa enums trong Java không?

Ví dụ: giả sử rằng bạn có hai hệ thống A và B. Cả hai đều bắt đầu bằng cùng một cấp mã, nhưng tại một số điểm bắt đầu thấy các cập nhật mã tại các thời điểm khác nhau. Bây giờ giả sử rằng có một số

public enum Whatever { FIRST; } 

Và còn có các đối tượng khác giữ tham chiếu đến các hằng số của enum đó. Các đối tượng này được tuần tự hóa và gửi từ A đến B hoặc ngược lại. Bây giờ xem xét rằng B có một phiên bản mới hơn của Dù

public enum Whatever { FIRST; SECOND } 

Sau đó:

class SomethingElse implements Serializable { ... 
    private final Whatever theWhatever; 
    SomethingElse(Whatever theWhatever) { 
    this.theWhatever = theWhatever; .. 

được instantiated ...

SomethingElse somethin = new SomethingElse(Whatever.SECOND) 

và sau đó tuần tự và gửi qua đến A (ví dụ như kết quả của một số cuộc gọi RMI). Đó là xấu, bởi vì bây giờ sẽ có một lỗi trong quá trình deserialization trên A: A biết Enum lớp bất cứ điều gì, nhưng trong một phiên bản mà không có SECOND.

Chúng tôi đã tìm ra điều này một cách khó khăn; và bây giờ tôi rất lo lắng để sử dụng enums cho các tình huống mà thực sự sẽ "hoàn hảo cho enums"; đơn giản là vì tôi biết rằng tôi không thể dễ dàng mở rộng một enum hiện có sau này.

Bây giờ tôi tự hỏi: liệu có (tốt) chiến lược để tránh các vấn đề tương thích với enums? Hay tôi thực sự phải quay trở lại với thời gian "tiền bối rối"; và không sử dụng enums, nhưng phải dựa vào một giải pháp mà tôi sử dụng dây đồng bằng khắp nơi?

Cập nhật: xin lưu ý rằng việc sử dụng serialversionuid không giúp gì cả. Điều đó chỉ giúp bạn thực hiện một thay đổi không tương thích "rõ ràng hơn". Nhưng vấn đề là: Tôi không quan tâm lý do tại sao deserialization không thành công - bởi vì tôi phải tránh nó xảy ra. Và tôi cũng không ở trong một vị trí để thay đổi cách chúng ta sắp xếp các đối tượng của mình. Chúng tôi đang làm RMI; và chúng tôi đang tuần tự hóa thành nhị phân; Tôi không có cách nào để thay đổi điều đó.

+6

Đây có phải là vấn đề với bất kỳ lớp học nào không? Nếu bạn thay đổi các trường trong một phiên bản mới hơn, thì việc deserialization sẽ thất bại đối với phiên bản cũ hơn. – 4castle

+0

Không nhất thiết. Thêm trường là một hoạt động hoàn toàn hợp lệ. Và nếu bạn làm việc với các chuỗi đơn giản, bạn rõ ràng sẽ mất thời gian kiểm tra biên dịch; nhưng nếu một trường đối tượng là String, thì trường đó có thể mang ** bất kỳ giá trị ** nào mà không bao giờ gây ra các vấn đề như vậy. – GhostCat

+1

Bạn có thể sử dụng hằng số — các chuỗi này độc đáo, và chúng có nhiều thuộc tính giống như enum –

Trả lời

0

Sau khi đi qua lại liên quan đến các giải pháp khác nhau, tôi đã tìm ra một giải pháp dựa trên những gợi ý từ @GuiSim: người ta có thể xây dựng một lớp có chứa một giá trị enum .Lớp học này có thể

  1. làm tùy chỉnh deserialization; vì vậy tôi có thể ngăn chặn sẽ không có trường hợp ngoại lệ trong quá trình deserialization
  2. cung cấp các phương pháp đơn giản như isValid()getEnumValue(): người đầu tiên cho bạn biết nếu deserialization enum làm việc thực tế; và thứ hai trả về enumialized enum (hoặc ném một ngoại lệ)
6

Như @Jesper đã đề cập trong các nhận xét, tôi sẽ đề xuất một cái gì đó như JSON cho liên lạc giữa các dịch vụ của bạn. Điều này sẽ cho phép bạn có nhiều quyền kiểm soát hơn đối với cách xử lý các giá trị Enum chưa biết.

Ví dụ: sử dụng số Jackson luôn tuyệt vời, bạn có thể sử dụng Deserialization FeaturesREAD_UNKNOWN_ENUM_VALUES_AS_NULL hoặc READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE. Cả hai sẽ cho phép logic ứng dụng của bạn xử lý các giá trị enum không xác định khi bạn thấy phù hợp.

Ví dụ (trực tiếp từ doc Jackson)

enum MyEnum { A, B, @JsonEnumDefaultValue UNKNOWN } 
... 
final ObjectMapper mapper = new ObjectMapper(); 
mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); 

MyEnum value = mapper.readValue("\"foo\"", MyEnum.class); 
assertSame(MyEnum.UNKNOWN, value); 
+0

Chắc chắn điều; nhưng ít nhất là bây giờ, kiến ​​trúc của chúng ta là như vậy; không có cơ hội cho sự thay đổi cơ bản như vậy. Chúng ta phải sống với các đối tượng được tuần tự hóa trong nhiều năm ... – GhostCat

+0

@GhostCat Tôi đoán bạn có thể sử dụng [tùy chỉnh Java Deserialization] (http://stackoverflow.com/questions/7290777/java-custom-serialization) để xác định cách enums được deserialized và cách xử lý các giá trị không xác định. – GuiSim

+2

Phụ lục: Tôi cho rằng việc tuần tự hóa tùy chỉnh sẽ ** không ** công việc - các enums được xử lý khác nhau (xem http://stackoverflow.com/questions/15521309/is-custom-enum-serializable-too) nó nói * Quá trình mà theo đó hằng số enum được tuần tự hóa không thể được tùy chỉnh * ở đó. – GhostCat

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