[英]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.