2012-02-14 18 views
14

Tôi có một mô hình dữ liệu nội bộ hiện tại cho một Picture, như sau:Làm việc với Nghị định thư Buffers và các mô hình dữ liệu nội bộ

package test.model; 
public class Picture { 

    private int height, width; 
    private Format format; 

    public enum Format { 
    JPEG, BMP, GIF 
    } 

    // Constructor, getters and setters, hashCode, equals, toString etc. 
} 

bây giờ tôi muốn serialize nó bằng cách sử protocol buffers. Tôi đã viết một tập tin Picture.proto phản ánh các lĩnh vực của lớp Picture và biên soạn mã theo gói test.model.protobuf với classname của PictureProtoBuf:

package test.model.protobuf; 

option java_package = "test.model.protobuf"; 
option java_outer_classname = "PictureProtoBuf"; 

message Picture { 
    enum Format { 
    JPEG = 1; 
    BMP = 2; 
    GIF = 3; 
    } 
    required uint32 width = 1; 
    required uint32 height = 2; 
    required Format format = 3; 
} 

Bây giờ tôi bây giờ giả định rằng nếu tôi có một Picture rằng tôi muốn serialize và gửi ở đâu đó tôi có để tạo ra một đối tượng PictureProtoBuf và bản đồ tất cả các lĩnh vực trên, như vậy:

Picture p = new Picture(100, 200, Picture.JPEG); 
PictureProtoBuf.Picture.Builder output = PictureProtoBuf.Picture.newBuilder(); 
output.setHeight(p.getHeight()); 
output.setWidth(p.getWidth()); 

tôi đến lột khi tôi có một điều tra trong mô hình dữ liệu của tôi. Cách xấu xí mà tôi đang sử dụng ngay bây giờ là:

output.setFormat(PictureProtoBuf.Picture.Format.valueOf(p.getFormat().name()); 

Tuy nhiên, điều này là dễ bị vỡ và dựa vào tên liệt kê là nhất quán giữa các mô hình dữ liệu nội bộ của tôi và mô hình dữ liệu giao thức đệm (mà không phải là một giả định tuyệt vời là tên liệt kê trong tệp .proto cần phải là duy nhất). Tôi có thể thấy tôi phải báo cáo chuyển đổi thủ công trên danh sách nếu cuộc gọi .name() từ mô hình nội bộ không khớp với tên điều tra được tạo bởi protobuf.

Tôi đoán câu hỏi của mình là liệu tôi có đi đúng hướng không? Tôi có phải loại bỏ mô hình dữ liệu nội bộ của mình (test.model.Picture) có lợi cho mô hình dữ liệu được tạo bởi protobuf (test.model.protobuf.PictureProtoBuf) không? Nếu có, làm cách nào để tôi có thể triển khai một số tính năng mà tôi đã thực hiện trong mô hình dữ liệu nội bộ của mình (ví dụ: hashCode(), equals(Object), toString(), v.v ...)?

+0

Tôi chưa thử nó (hoàn toàn là vì tôi chủ yếu là người .NET), nhưng tôi * tin * [người bảo vệ] (http://code.google.com/p/protostuff/) cho phép bạn tiếp tục làm việc với mô hình hiện tại của mình .. –

+0

Cảm ơn, tôi sẽ kiểm tra! – Catchwa

+0

@MarcGravell - Cảm ơn bạn đã đề xuất. Linh cảm của bạn là chính xác; protostuff thực hiện chính xác những gì tôi đã làm sau nhưng vẫn giữ lại các bộ đệm giao thức trên back-end (chưa thử nghiệm khả năng tương thích với thư viện protobuf của Google). – Catchwa

Trả lời

3

Mặc dù các câu trả lời hiện có là tốt, tôi quyết định tiến xa hơn một chút với đề xuất của Marc Gravell để xem xét tính năng bảo vệ.

Bạn có thể sử dụng protostuff runtime module cùng với ObjectSchema năng động để tạo ra lược đồ trong thời gian chạy cho mô hình dữ liệu nội bộ của bạn

Mã của tôi hiện nay giảm xuống còn:

// Do this once 
private static Schema<Picture> schema = RuntimeSchema.getSchema(Picture.class); 
private static final LinkedBuffer buffer = LinkedBuffer.allocate(DEFAULT_BUFFER_SIZE); 

// For each Picture you want to serialize... 
Picture p = new Picture(100, 200, Picture.JPEG); 
byte[] result = ProtobufIOUtil.toByteArray(p, schema, buffer); 
buffer.clear(); 
return result; 

Đây là một cải tiến lớn so với Google thư viện protobuf (xem câu hỏi của tôi) khi bạn có rất nhiều và nhiều thuộc tính trong mô hình dữ liệu nội bộ của bạn. Cũng không có hình phạt tốc độ nào mà tôi có thể phát hiện (với trường hợp sử dụng của tôi!)

4

Nếu bạn có quyền kiểm soát mô hình dữ liệu nội bộ, bạn có thể sửa đổi test.model.Picture để các giá trị enum biết tương ứng protobuf tương ứng của chúng, có thể chuyển qua thư từ với các nhà thầu enum của bạn.

Ví dụ, sử dụng Guava'sBiMap (bản đồ hai chiều với giá trị duy nhất), chúng tôi nhận một cái gì đó giống như

enum ProtoEnum { // we don't control this 
    ENUM1, ENUM2, ENUM3; 
} 

enum MyEnum { 
    ONE(ProtoEnum.ENUM1), TWO(ProtoEnum.ENUM2), THREE(ProtoEnum.ENUM3); 

    static final ImmutableBiMap<MyEnum, ProtoEnum> CORRESPONDENCE; 

    static { 
    ImmutableBiMap.Builder<ProtoEnum, MyEnum> builder = ImmutableBiMap.builder(); 
    for (MyEnum x : MyEnum.values()) { 
     builder.put(x.corresponding, x); 
    } 
    CORRESPONDENCE = builder.build(); 
    } 

    private final ProtoEnum corresponding; 

    private MyEnum(ProtoEnum corresponding) { 
    this.corresponding = corresponding; 
    } 
} 

và sau đó nếu chúng ta muốn tìm kiếm các MyEnum tương ứng với một ProtoEnum, chúng tôi chỉ làm MyEnum.CORRESPONDENCE.get(protoEnum), và để đi theo cách khác, chúng tôi chỉ thực hiện MyEnum.CORRESPONDENCE.inverse().get(myEnum) hoặc myEnum.getCorresponding().

+0

Cảm ơn câu trả lời của bạn. Tôi nghĩ rằng tôi nắm bắt được khái niệm nhưng tôi không chắc chắn làm thế nào tôi sẽ thực hiện nó. Bạn có phiền khi đưa ra một số mã? – Catchwa

+2

Có một nhánh cho bạn; nó có đủ rõ ràng không? –

+0

Đúng, có ý nghĩa - cảm ơn. – Catchwa

1

Một cách là chỉ giữ enum tạo:

package test.model; 
public class Picture { 

    private int height, width; 
    private PictureProtoBuf.Picture.Format format; 

// Constructor, getters and setters, hashCode, equals, toString etc. 
} 

Tôi đã sử dụng này một vài lần, nó có thể hoặc có thể không có ý nghĩa trong trường hợp của bạn. Sử dụng các lớp tạo protobuf như mô hình dữ liệu của bạn (hoặc mở rộng chúng để thêm chức năng), không bao giờ được khuyến khích.

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