Cómo leer un .NET Guid en un UUID de Java

Necesito comunicar un Guid que se generó en .NET a una aplicación Java. Yo uso Guid.ToByteArray() para almacenarlo en el disco como un byte[] , luego lo leo en Java y lo convierto en un UUID. Para este propósito copié la implementación del constructor (privado) de UUID que toma un byte[] :

 private UUID(byte[] data) { long msb = 0; long lsb = 0; assert data.length == 16; for (int i=0; i<8; i++) msb = (msb << 8) | (data[i] & 0xff); for (int i=8; i<16; i++) lsb = (lsb << 8) | (data[i] & 0xff); this.mostSigBits = msb; this.leastSigBits = lsb; } 

Sin embargo, cuando inspecciono el UUID usando toString() , el UUID de Java es diferente del .NET Guid.

Por ejemplo, el .NET Guid

 888794c2-65ce-4de1-aa15-75a11342bc63 

se convierte en el UUID de Java

 c2948788-ce65-e14d-aa15-75a11342bc63 

Parece que el orden de bytes de los primeros tres grupos se invierte, mientras que el orden en los dos últimos grupos es el mismo.

Dado que esperaría que toString() tanto del GUID como del UUID produjera el mismo resultado, ¿alguien sabe cómo debo leer correctamente el .NET Guid en un UUID de Java?

Editar: para aclarar, la implementación no es mía. Es el constructor privado de la clase java.util.UUID que toma un byte[] , que he copiado para usarlo con el fin de leer un byte [] del disco en un UUID.

No quiero usar cadenas para almacenar los Guids ya que los estoy almacenando y parece una pérdida de espacio.

El enlace de Russell Troywest al menos aclara por qué los primeros dos grupos del Guid salen invertidos, mientras que la segunda mitad se mantiene en el mismo orden. La pregunta es, ¿puedo depender de .NET siempre generando estos bytes en el mismo orden?

En respuesta a su edición, no, no puede depender constantemente de los bytes que se generan en el mismo orden. El tiempo de ejecución determina la endianidad. Sin embargo, C # ofrece BitConverter.isLittleEndian por esta misma razón.

Sé que no se puede cambiar la endianidad de la implementación de Java y el cambio de bit. Pero puede cambiar los bits en el extremo C # después del almacenamiento y antes de enviarlos a Java.

Actualizar:

Artículo de MSDN en IsLittleEndian

Editar: Para ser práctico, PROBABLEMENTE puedes contar con que siempre es pequeño endian en su diseño del primer trozo de bytes, pero técnicamente no puedes.

¿No podría simplemente almacenar .Net Guid como una cadena y leerlo en Java? De esta forma, no necesita preocuparse por el orden de los bytes ni nada.

Si no, entonces esto explica cómo los bytes se presentan en C #

http://msdn.microsoft.com/en-us/library/fx22893a.aspx

Editar 2017-08-30 : elementos de matriz intercambiados 6 y 7 por comentarios.

Tengo que leer y escribir Guids desde / a MySQL (almacenado como binario (16)) en una aplicación C #, pero la base de datos también es utilizada por aplicaciones Java. Aquí están los métodos de extensión que uso para convertir entre .NET little-endian y Java big-endian byte order:

 public static class GuidExtensions { ///  /// A CLSCompliant method to convert a Java big-endian Guid to a .NET /// little-endian Guid. /// The Guid Constructor (UInt32, UInt16, UInt16, Byte, Byte, Byte, Byte, /// Byte, Byte, Byte, Byte) is not CLSCompliant. ///  [CLSCompliant(true)] public static Guid ToLittleEndian(this Guid javaGuid) { byte[] net = new byte[16]; byte[] java = javaGuid.ToByteArray(); for (int i = 8; i < 16; i++) { net[i] = java[i]; } net[3] = java[0]; net[2] = java[1]; net[1] = java[2]; net[0] = java[3]; net[5] = java[4]; net[4] = java[5]; net[6] = java[7]; net[7] = java[6]; return new Guid(net); } ///  /// Converts little-endian .NET guids to big-endian Java guids: ///  [CLSCompliant(true)] public static Guid ToBigEndian(this Guid netGuid) { byte[] java = new byte[16]; byte[] net = netGuid.ToByteArray(); for (int i = 8; i < 16; i++) { java[i] = net[i]; } java[0] = net[3]; java[1] = net[2]; java[2] = net[1]; java[3] = net[0]; java[4] = net[5]; java[5] = net[4]; java[6] = net[7]; java[7] = net[6]; return new Guid(java); } } 

El GUID.toByteArray es bastante extraño en C #. La primera mitad está en little-endian y la segunda mitad está en big-endia.

Un comentario en esta página toma nota de este hecho: http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

el orden de los bytes en la matriz de bytes devueltos es diferente de la representación de cadena de un valor Guid. El orden del grupo de cuatro bytes inicial y de los dos grupos de dos bytes siguientes se invierte, mientras que el orden del último grupo de dos bytes y el grupo de seis bytes de cierre es el mismo.

Creo que tu problema aquí es que .NET es little-endian pero JAVA es big-endian , así que cuando lees un entero de 128 bits (un GUID) escrito por una aplicación C # desde una aplicación JAVA tienes que hacer la conversión de little- endian endian a big-endian.

Como ya se mencionó, la encoding binaria de GUID en .NET tiene bytes en los primeros tres grupos colocados en el orden little-endian (invertido) – Método Guid.ToByteArray . Para crear java.util.UUID desde él, puede usar el siguiente código:

 import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.UUID; public UUID toUUID(byte[] binaryEncoding) { ByteBuffer source = ByteBuffer.wrap(binaryEncoding); ByteBuffer target = ByteBuffer.allocate(16). order(ByteOrder.LITTLE_ENDIAN). putInt(source.getInt()). putShort(source.getShort()). putShort(source.getShort()). order(ByteOrder.BIG_ENDIAN). putLong(source.getLong()); target.rewind(); return new UUID(target.getLong(), target.getLong()); } 

Este código funciona para mí.

 var msb: Long = 0 var lsb: Long = 0 for(i <- Seq(3, 2, 1, 0, 5, 4, 7, 6)) { msb = (msb << 8) | (data(i) & 0xFF) } for(i <- 8 until 16) { lsb = (lsb << 8) | (data(i) & 0xFF) } new UUID(msb, lsb)