所以protobuf-net将这个原型内容用于.NET指南:
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(),并交换这些命令,但是唉......
编辑,第二个: 难怪两个长片上的简单字节顺序交换不起作用(摘自here):
开始的四字节组和接下来的两个双字节的顺序 组被颠倒,而最后两个字节组的顺序和 关闭的六字节组是相同的。
有关一种可能性,请参阅此问题的答案。如果两种语言都在应用程序代码中使用其本机二进制guid / uuid类型,那么不确定是否还有其他方法。任何其他建议(除了将guid作为字符串发送)?
答案 0 :(得分:2)
好的,所以解决这个问题的方法是首先定义包含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();
}
}