Search code examples
javamysqlprotocol-buffersprimitive

How do I convert MySQL unsigned ints to Protocol Buffer uint32s in Java?


I'm working on converting a bunch of old tab-separated MySQL database dump files into Protocol Buffers and have run into a snag. The MySQL table includes a field of type int(11) unsigned, which I have mapped to protobuf uint32 in the .proto file. When parsing the MySQL records and trying to convert them to a protobuf message, it's tempting to parse that field using Integer.valueOf(String) (or Long.valueOf(String) to avoid overflows). However, the Protocol Buffers Language Guide indicates here that in Java, uint32s are represented using the int datatype, but with the first bit being reinterpreted as the highest-order bit rather than as the sign bit.

So before I go write my own String->uint32-flavored-int parser, I thought it was worth asking whether anyone else has already solved this particular problem. What's the correct way of converting a String representation of MySQL int unsigned to a Protocol Buffers uint32 in Java?


Solution

  • String to int representing uint32

    I'd try parsing as long and then converting to int:

    int i = (int)Long.parseLong(str);
    

    Using long for the conversion avoids a NumberFormatException due to an exceeded range. The subsequent narrowing conversion will drop the more significant half of the resulting bits, leaving you exactly with the representation required by the protocol buffer.

    String to long representing uint64

    A similar conversion for uint64 using BigInteger could probably be written as follows (untested code):

    long l = (new BigInteger(str)).longValue();
    

    This relies on an implicit truncation, just like in the above case. The documentation states:

    If this BigInteger is too big to fit in a long, only the low-order 64 bits are returned.

    Int representing uint to long

    If you want to convert such an int which actually represents an uint32 to a long with positive sign, you should make sure to clear the 32 most significant bits, as these will be filled with copies of the most significant bit of the int value, due to the sign-extending nature of the widening conversion.

    long uintValue = intValue & 0xffffffffL;