簡體   English   中英

Protobuf-net與Java UUID和C#Guid互操作

[英]Protobuf-net interop with Java UUID and C# Guid

因此protobuf-net將這個原型內容用於.NET guid:

message Guid {
  optional fixed64 lo = 1; // the first 8 bytes of the guid
  optional fixed64 hi = 2; // the second 8 bytes of the guid
}

...當我將該proto編譯成Java類並創建此Java UUID實例時:

UUID uid = UUID.fromString("2ac9f438-f555-40b0-8880-02226b81285c");

...然后我使用uid.getMostSignificantBits()或uid.getLeastSignificantBits()作為Guid.setHi()(或Guid.setLo())的參數無關緊要。

無論我選擇哪種組合,當C#反序列化包含Java生成的guid的類型,並且我測試guid的值時,我得到的似乎是字節排序問題:

expected:<2ac9f438-f555-40b0-8880-02226b81285c>
 but was:<f55540b0-f438-2ac9-5c28-816b22028088>

...要么:

expected:<2ac9f438-f555-40b0-8880-02226b81285c>
 but was:<6b81285c-0222-8880-b040-55f538f4c92a>

這個問題有一個簡單的解決方法嗎?

應該指出我是protobuf的新手,所以對這里的可能性有點朦朧。

編輯:

為了它的價值,我還在將結果提供給Guid.setLo / Hi之前,對一個或兩個uid.getLeast / MostSignificantBits()的結果嘗試了Long.reverseBytes(),並交換了這些命令,但是唉。 ..

編輯,第二個:難怪兩個長片上的簡單字節順序交換不起作用(摘自此處 ):

開始的四字節組和接下來的兩個雙字節組的順序相反,而最后兩個字節組和結束六字節組的順序相同。

有關一種可能性,請參閱此問題的答案。 如果兩種語言都在應用程序代碼中使用其本機二進制guid / uuid類型,那么不確定是否還有其他方法。 任何其他建議(除了發送guid作為字符串)?

好的,所以一個解決方法是首先定義包含Guid的C#類,使Guid類型不參與序列化/反序列化,而是使用字節數組。 這可能看起來像這樣:

[ProtoContract]
public class Entity
{
    private bool _idInitialized = false;
    private Guid _id;

    public Guid id
    {
        get
        {
            if ( !_idInitialized )
            {
                _id = new Guid( idBytes );
                _idInitialized = true;
            }

            return _id;
        }
    }

    [ProtoMember( 1, IsRequired = true )]
    public byte[] idBytes;

    [ProtoMember( 2, IsRequired = true )]
    public String name;

    // For application code, sending side
    public Entity( Guid theId, String theName )
    {
        if ( String.IsNullOrEmpty( theName ) )
        {
            throw new ArgumentNullException( "theName" );
        }

        idBytes = theId.ToByteArray();
        _id = theId;
        _idInitialized = true;
        name = theName;
    }

    // For protobuf-net, receiving side
    public Entity() { }
}

然后使用GetProto為該類型生成proto文件:

Serializer.GetProto<Entity>()

產生這個:

message Entity {
   required bytes idBytes = 1;
   required string name = 2;
}

使用protoc將其編譯為Java類。 我整理了一個包裝類,它在內部使用生成的protobuf類。 這個包裝類使用下面的轉換方法來代表包裝類重新排序進出的字節。 ByteBuffer和Apache Commons的ArrayUtils.reverse()完成了所有工作。

如果需要與另一種語言互操作,可以使用類似的方法。 通過該語言的一些等效實用程序,每種語言都符合.NET字節排序方案。

import org.apache.commons.lang3.ArrayUtils;

public class Utilities {

    public static UUID getUuidFromDotNetGuidBytes(byte[] guidBytes) {
        ByteBuffer bb = ByteBuffer.wrap(guidBytes);

        byte[] first4 = new byte[4];
        bb.get(first4);
        ArrayUtils.reverse( first4 );

        byte[] second2 = new byte[2];
        bb.get(second2);
        ArrayUtils.reverse( second2 );

        byte[] third2 = new byte[2];
        bb.get(third2);
        ArrayUtils.reverse( third2 );

        long lsb = bb.getLong();

        bb = ByteBuffer.wrap(new byte[8]);
        bb.put( first4 );
        bb.put( second2 );
        bb.put( third2 );

        bb.rewind();
        long msb = bb.getLong();

        return new UUID(msb, lsb);
    }

    public static byte[] getDotNetGuidBytes(UUID theUuid) {

        ByteBuffer first8 = ByteBuffer.allocate(8);
        first8.putLong(theUuid.getMostSignificantBits());
        first8.rewind();

        byte[] first4 = new byte[4];
        first8.get(first4);
        ArrayUtils.reverse( first4 );

        byte[] second2 = new byte[2];
        first8.get(second2);
        ArrayUtils.reverse( second2 );

        byte[] third2 = new byte[2];
        first8.get(third2);
        ArrayUtils.reverse( third2 );

        ByteBuffer converted16 = ByteBuffer.allocate(16);
        converted16.put(first4);
        converted16.put(second2);
        converted16.put(third2);

        ByteBuffer last8 = ByteBuffer.allocate(8);
        last8.putLong(theUuid.getLeastSignificantBits());        
        last8.rewind();

        converted16.put(last8);

        return converted16.array();
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM