osheroff / mysql-binlog-connector-java

MySQL Binary Log connector
641 stars 161 forks source link

Deserialization trouble with BINARY(16) columns for UUID #139

Open bobdaly opened 6 months ago

bobdaly commented 6 months ago

Library version: 0.27.5 This UUID string value ab9d25e0-64e6-469f-9873-8621910ed300 came from: java.util.UUID.randomUUID().toString() (JDK version 11)

It was persisted to a MySQL 8.0 database column of type BINARY(16) using the UUID_TO_BIN() function. Here is the relevant code relying on the binlog library:

WriteRowsEventData eventData = event.getData(); List<Serializable[]> rowData = eventData.getRows(); (iterate over rowData) Object obj = (value from UUID/BINARY column which will come back as a byte[])

For the vast majority of UUIDs, the byte[] is of the expected length - 16. But some, like the value included above, have a length of 15.

The following conversion will fail with only 15 bytes: ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); long high = byteBuffer.getLong(); long low = byteBuffer.getLong(); java.util.UUID uuid = new UUID(high, low);

The exception is: java.nio.BufferUnderflowException at java.base/java.nio.Buffer.nextGetIndex(Buffer.java:650) at java.base/java.nio.HeapByteBuffer.getLong(HeapByteBuffer.java:452)

If the incorrectly sized byte[] has a 16th byte added as follows: bin2[15] = Byte.valueOf("00"); The conversion works.

I should also state that interacting with the persisted UUID using BIN_TO_UUID works as expected (i.e there is no problem from MySQL's perspective).

BTW, the CHAR_AND_BINARY_AS_BYTE_ARRAY compatibility mode is being set as well: EventDeserializer eventDeserializer = new EventDeserializer(); eventDeserializer.setCompatibilityMode( EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY ); binaryLogClient.setEventDeserializer(eventDeserializer);