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

7 minutos de lectura

avatar de usuario
el rebanador

Necesito comunicar un Guid que se generó en .NET a una aplicación Java. yo suelo Guid.ToByteArray() para almacenarlo en el disco como un byte[], luego léalo en Java y conviértalo en un UUID. Para ello 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 Guid de .NET.

Por ejemplo, el Guid de .NET

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

se convierte en el UUID de Java

c2948788-ce65-e14d-aa15-75a11342bc63

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

Dado que esperaría la toString() de Guid y UUID para obtener el mismo resultado, ¿alguien sabe cómo debo leer correctamente .NET Guid en un UUID de Java?

Editar: Para aclarar, la implementación no es mía. Es el constructor privado de la java.util.UUID clase que toma un byte[]que copié para usar con el propósito de leer un byte[] del disco a un UUID.

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

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

  • Parece que estás cambiando los bits de forma incorrecta. ¿Por qué tratar de ser lindo con eso? Primero lea los bytes y realice las asignaciones apropiadas (usando primero un índice) y luego use un operador de desplazamiento para optimizar (si es necesario). El punto es tener un código fácil de entender.

    – casperuno

    21 de abril de 2011 a las 14:43

  • Java almacena datos estrictamente Big Endian, mientras que C # no especifica un “endianness”, pero NORMALMENTE almacena datos como Little Endian. Como dijo @casperOne, estás cambiando en la dirección equivocada.

    –Doug Stephen

    21 de abril de 2011 a las 14:48

  • He estado tratando de aplicar ingeniería inversa a un marco que usa esta construcción. Había estado mirando el extraño cambio de bits durante más de dos horas hasta que encontré este hilo.

    – Jouke Waleson

    24 de noviembre de 2012 a las 16:21

avatar de usuario
russell troywest

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

Si no, entonces Esto explica cómo se distribuyen los bytes 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 las aplicaciones Java también utilizan la base de datos. Estos son los métodos de extensión que uso para convertir entre el orden de bytes .NET little-endian y Java big-endian:

public static class GuidExtensions
{
    /// <summary>
    /// 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.
    /// </summary>
    [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);
    }

    /// <summary>
    /// Converts little-endian .NET guids to big-endian Java guids:
    /// </summary>
    [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);
    }
}

  • No estoy seguro de si esto es algo específico de Java, pero necesitaba voltear endianess para el directorio activo guid / nativeGuid y usar este código produce un error. La solución está en los últimos dos intercambios de bytes que no están en el código: java[6]=neto[7]; Java[7]=neto[6]; También tenga en cuenta que los dos métodos son idénticos y puede reducirlo a una función de volteo.

    – Inconformista

    18 de junio de 2013 a las 11:57

  • Así que estás diciendo eso en lugar de net[6] = java[6] y net[7] = java[7] ¿Debería estar intercambiando estos dos bytes? Sé que este código funcionó para mí manejando Guids en MySQL (no tengo esa base de datos a mano en este momento), pero la respuesta de @Russell Troywest a continuación podría ser la opción más segura después de todo.

    – Paul Smith

    18 de junio de 2013 a las 13:29

  • así es como parece funcionar Active Directory. ¡Cosas extrañas! Básicamente estoy cambiando entre DirectoryEntry.Guid y DirectoryEntry.NativeGuid usando su código con esa modificación. De acuerdo con la documentación de Guids, ese último byte debería intercambiarse según mi comprensión básica de ese texto

    – Inconformista

    18 de junio de 2013 a las 15:14

  • parece que hay un error tipográfico (o un error) en su código de net[6] = java[6];deberia ser net[6] = java[7];?

    – Félix

    7 dic 2016 a las 6:00

  • tuve que cambiar la red[7] a 6 y neto[6] a 7 en ToBigEndian

    – Alejandro

    30 de agosto de 2017 a las 20:49

avatar de usuario
ᄂ ᄀ

Como ya se señaló, la codificación binaria de GUID en .NET tiene bytes en los primeros tres grupos colocados en el orden little-endian (invertido); consulte Método Guid.ToByteArray. Crear java.util.UUID desde allí puedes 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());
}

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

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

Actualizar:

Artículo de MSDN sobre IsLittleEndian

Editar: para ser práctico, PROBABLEMENTE puede contar con que siempre sea little endian en su diseño de la primera porción de bytes, pero técnicamente no puede.

avatar de usuario
joey

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 señala este hecho:
http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

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

avatar de usuario
Comunidad

Creo que su problema aquí es que .NET es little-endian pero JAVA es big-endian, por lo que cuando lee un número entero de 128 bits (un GUID) escrito por una aplicación C# desde una aplicación JAVA, debe realizar la conversión desde little- endian a big-endian.

los códecs DotNetGuid1Codec y DotNetGuid4Codec puede codificar UUID a .Net Guids.

// Convert time-based (version 1) to .Net Guid
UuidCodec<UUID> codec = new DotNetGuid1Codec();
UUID guid = codec.encode(timeUuid);
// Convert random-based (version 4) to .Net Guid
UuidCodec<UUID> codec = new DotNetGuid4Codec();
UUID guid = codec.encode(randomUuid);

Ver: creador de uuid

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad