|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
java.lang.Objectcom.github.shyiko.mysql.binlog.event.deserialization.json.JsonBinary
public class JsonBinary
Utility to parse the binary-encoded value of a MySQL JSON type, translating the encoded representation into
method calls on a supplied JsonFormatter implementation.
DATE as a string of the form YYYY-MM-DD where YYYY can be positive or negativeTIME as a string of the form HH-MM-SS where HH can be positive or negativeDATETIME as a string of the form YYYY-MM-DD HH-mm-SS.ssssss where YYYY can be positive or
negativeTIMESTAMP as the number of microseconds past epoch (January 1, 1970), or if negative the number of
microseconds before epoch (January 1, 1970)
doc ::= type value
type ::=
0x00 | // small JSON object
0x01 | // large JSON object
0x02 | // small JSON array
0x03 | // large JSON array
0x04 | // literal (true/false/null)
0x05 | // int16
0x06 | // uint16
0x07 | // int32
0x08 | // uint32
0x09 | // int64
0x0a | // uint64
0x0b | // double
0x0c | // utf8mb4 string
0x0f // custom data (any MySQL data type)
value ::=
object |
array |
literal |
number |
string |
custom-data
object ::= element-count size key-entry* value-entry* key* value*
array ::= element-count size value-entry* value*
// number of members in object or number of elements in array
element-count ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
// number of bytes in the binary representation of the object or array
size ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
key-entry ::= key-offset key-length
key-offset ::=
uint16 | // if used in small JSON object
uint32 // if used in large JSON object
key-length ::= uint16 // key length must be less than 64KB
value-entry ::= type offset-or-inlined-value
// This field holds either the offset to where the value is stored,
// or the value itself if it is small enough to be inlined (that is,
// if it is a JSON literal or a small enough [u]int).
offset-or-inlined-value ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
key ::= utf8mb4-data
literal ::=
0x00 | // JSON null literal
0x01 | // JSON true literal
0x02 | // JSON false literal
number ::= .... // little-endian format for [u]int(16|32|64), whereas
// double is stored in a platform-independent, eight-byte
// format using float8store()
string ::= data-length utf8mb4-data
custom-data ::= custom-type data-length binary-data
custom-type ::= uint8 // type identifier that matches the
// internal enum_field_types enum
data-length ::= uint8* // If the high bit of a byte is 1, the length
// field is continued in the next byte,
// otherwise it is the last byte of the length
// field. So we need 1 byte to represent
// lengths up to 127, 2 bytes to represent
// lengths up to 16383, and so on...
| Nested Class Summary | |
|---|---|
protected static class |
JsonBinary.ValueEntry
Class used internally to hold value entry information. |
| Constructor Summary | |
|---|---|
JsonBinary(byte[] bytes)
|
|
JsonBinary(ByteArrayInputStream contents)
|
|
| Method Summary | |
|---|---|
protected static String |
asHex(byte b)
|
protected static String |
asHex(int value)
|
String |
getString()
|
static void |
parse(byte[] bytes,
JsonFormatter formatter)
Parse the MySQL binary representation of a JSON value and call the supplied JsonFormatter
for the various components of the value. |
void |
parse(JsonFormatter formatter)
|
protected void |
parse(ValueType type,
JsonFormatter formatter)
|
protected void |
parseArray(boolean small,
JsonFormatter formatter)
Parse a JSON array. |
static String |
parseAsString(byte[] bytes)
Parse the MySQL binary representation of a JSON value and return the JSON string representation. |
protected void |
parseBoolean(JsonFormatter formatter)
Parse a literal value that is either null, true, or false. |
protected void |
parseDate(JsonFormatter formatter)
Parse a DATE value, which is stored using the same format as DATETIME:
5 bytes + fractional-seconds storage. |
protected void |
parseDatetime(JsonFormatter formatter)
Parse a DATETIME value, which is stored as 5 bytes + fractional-seconds storage. |
protected void |
parseDecimal(int length,
JsonFormatter formatter)
Parse a DECIMAL value. |
protected void |
parseDouble(JsonFormatter formatter)
Parse a 8 byte double value. |
protected void |
parseInt16(JsonFormatter formatter)
Parse a 2 byte integer value. |
protected void |
parseInt32(JsonFormatter formatter)
Parse a 4 byte integer value. |
protected void |
parseInt64(JsonFormatter formatter)
Parse a 8 byte integer value. |
protected void |
parseObject(boolean small,
JsonFormatter formatter)
Parse a JSON object. |
protected void |
parseOpaque(JsonFormatter formatter)
Parse an opaque type. |
protected void |
parseOpaqueValue(ColumnType type,
int length,
JsonFormatter formatter)
|
protected void |
parseString(JsonFormatter formatter)
Parse the length and value of a string stored in MySQL's "utf8mb" character set (which equates to Java's UTF-8 character set. |
protected void |
parseTime(JsonFormatter formatter)
Parse a TIME value, which is stored using the same format as DATETIME:
5 bytes + fractional-seconds storage. |
protected void |
parseUInt16(JsonFormatter formatter)
Parse a 2 byte unsigned integer value. |
protected void |
parseUInt32(JsonFormatter formatter)
Parse a 4 byte unsigned integer value. |
protected void |
parseUInt64(JsonFormatter formatter)
Parse a 8 byte unsigned integer value. |
protected long |
readBigEndianLong(int numBytes)
|
protected int |
readFractionalSecondsInMicroseconds()
|
protected int |
readInt16()
|
protected int |
readInt24()
|
protected int |
readInt32()
|
protected long |
readInt64()
|
protected Boolean |
readLiteral()
|
protected int |
readUInt16()
|
protected long |
readUInt32()
|
protected BigInteger |
readUInt64()
|
protected int |
readUnsignedIndex(int maxValue,
boolean isSmall,
String desc)
|
protected ValueType |
readValueType()
|
protected int |
readVariableInt()
Read a variable-length integer value. |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Constructor Detail |
|---|
public JsonBinary(byte[] bytes)
public JsonBinary(ByteArrayInputStream contents)
| Method Detail |
|---|
public static String parseAsString(byte[] bytes)
throws IOException
JSON value and return the JSON string representation.
This method is equivalent to parse(byte[], JsonFormatter) using the JsonStringFormatter.
bytes - the binary representation; may not be null
IOException - if there is a problem reading or processing the binary representation
public static void parse(byte[] bytes,
JsonFormatter formatter)
throws IOException
JSON value and call the supplied JsonFormatter
for the various components of the value.
bytes - the binary representation; may not be nullformatter - the formatter that will be called as the binary representation is parsed; may not be null
IOException - if there is a problem reading or processing the binary representationpublic String getString()
public void parse(JsonFormatter formatter)
throws IOException
IOException
protected void parse(ValueType type,
JsonFormatter formatter)
throws IOException
IOException
protected void parseObject(boolean small,
JsonFormatter formatter)
throws IOException
The grammar of the binary representation of JSON objects are defined in the MySQL code base in the json_binary.h file:
value ::=
object |
array |
literal |
number |
string |
custom-data
object ::= element-count size key-entry* value-entry* key* value*
// number of members in object or number of elements in array
element-count ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
// number of bytes in the binary representation of the object or array
size ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
key-entry ::= key-offset key-length
key-offset ::=
uint16 | // if used in small JSON object
uint32 // if used in large JSON object
key-length ::= uint16 // key length must be less than 64KB
value-entry ::= type offset-or-inlined-value
// This field holds either the offset to where the value is stored,
// or the value itself if it is small enough to be inlined (that is,
// if it is a JSON literal or a small enough [u]int).
offset-or-inlined-value ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
key ::= utf8mb4-data
literal ::=
0x00 | // JSON null literal
0x01 | // JSON true literal
0x02 | // JSON false literal
number ::= .... // little-endian format for [u]int(16|32|64), whereas
// double is stored in a platform-independent, eight-byte
// format using float8store()
string ::= data-length utf8mb4-data
custom-data ::= custom-type data-length binary-data
custom-type ::= uint8 // type identifier that matches the
// internal enum_field_types enum
data-length ::= uint8* // If the high bit of a byte is 1, the length
// field is continued in the next byte,
// otherwise it is the last byte of the length
// field. So we need 1 byte to represent
// lengths up to 127, 2 bytes to represent
// lengths up to 16383, and so on...
small - true if the object being read is "small", or false otherwiseformatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseArray(boolean small,
JsonFormatter formatter)
throws IOException
The grammar of the binary representation of JSON objects are defined in the MySQL code base in the json_binary.h file, and are:
value ::=
object |
array |
literal |
number |
string |
custom-data
array ::= element-count size value-entry* value*
// number of members in object or number of elements in array
element-count ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
// number of bytes in the binary representation of the object or array
size ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
value-entry ::= type offset-or-inlined-value
// This field holds either the offset to where the value is stored,
// or the value itself if it is small enough to be inlined (that is,
// if it is a JSON literal or a small enough [u]int).
offset-or-inlined-value ::=
uint16 | // if used in small JSON object/array
uint32 // if used in large JSON object/array
key ::= utf8mb4-data
literal ::=
0x00 | // JSON null literal
0x01 | // JSON true literal
0x02 | // JSON false literal
number ::= .... // little-endian format for [u]int(16|32|64), whereas
// double is stored in a platform-independent, eight-byte
// format using float8store()
string ::= data-length utf8mb4-data
custom-data ::= custom-type data-length binary-data
custom-type ::= uint8 // type identifier that matches the
// internal enum_field_types enum
data-length ::= uint8* // If the high bit of a byte is 1, the length
// field is continued in the next byte,
// otherwise it is the last byte of the length
// field. So we need 1 byte to represent
// lengths up to 127, 2 bytes to represent
// lengths up to 16383, and so on...
small - true if the object being read is "small", or false otherwiseformatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseBoolean(JsonFormatter formatter)
throws IOException
true, or false.
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseInt16(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseUInt16(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseInt32(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseUInt32(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseInt64(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseUInt64(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseDouble(JsonFormatter formatter)
throws IOException
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseString(JsonFormatter formatter)
throws IOException
variable length integer length of the string.
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseOpaque(JsonFormatter formatter)
throws IOException
DATE,
TIME, and DATETIME values are
stored as opaque types, though they are to be unpacked. TIMESTAMPs are also stored as opaque types, but
converted by MySQL to
DATETIME prior to storage.
Other MySQL types are stored as opaque types and passed on to the formatter as opaque values.
See the MySQL source code for the logic used in this method.
custom-data ::= custom-type data-length binary-data
custom-type ::= uint8 // type identifier that matches the
// internal enum_field_types enum
data-length ::= uint8* // If the high bit of a byte is 1, the length
// field is continued in the next byte,
// otherwise it is the last byte of the length
// field. So we need 1 byte to represent
// lengths up to 127, 2 bytes to represent
// lengths up to 16383, and so on...
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseDate(JsonFormatter formatter)
throws IOException
DATE value, which is stored using the same format as DATETIME:
5 bytes + fractional-seconds storage. However, the hour, minute, second, and fractional seconds are ignored.
The non-fractional part is 40 bits:
1 bit sign (1= non-negative, 0= negative) 17 bits year*13+month (year 0-9999, month 0-12) 5 bits day (0-31) 5 bits hour (0-23) 6 bits minute (0-59) 6 bits second (0-59)The fractional part is typically dependent upon the fsp (i.e., fractional seconds part) defined by a column, but in the case of JSON it is always 3 bytes.
The format of all temporal values is outlined in the MySQL documentation,
although since the MySQL JSON type is only available in 5.7, only version 2 of the date-time formats
are necessary.
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseTime(JsonFormatter formatter)
throws IOException
TIME value, which is stored using the same format as DATETIME:
5 bytes + fractional-seconds storage. However, the year, month, and day values are ignored
The non-fractional part is 40 bits:
1 bit sign (1= non-negative, 0= negative) 17 bits year*13+month (year 0-9999, month 0-12) 5 bits day (0-31) 5 bits hour (0-23) 6 bits minute (0-59) 6 bits second (0-59)The fractional part is typically dependent upon the fsp (i.e., fractional seconds part) defined by a column, but in the case of JSON it is always 3 bytes.
The format of all temporal values is outlined in the MySQL documentation,
although since the MySQL JSON type is only available in 5.7, only version 2 of the date-time formats
are necessary.
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseDatetime(JsonFormatter formatter)
throws IOException
DATETIME value, which is stored as 5 bytes + fractional-seconds storage.
The non-fractional part is 40 bits:
1 bit sign (1= non-negative, 0= negative) 17 bits year*13+month (year 0-9999, month 0-12) 5 bits day (0-31) 5 bits hour (0-23) 6 bits minute (0-59) 6 bits second (0-59)The sign bit is always 1. A value of 0 (negative) is reserved. The fractional part is typically dependent upon the fsp (i.e., fractional seconds part) defined by a column, but in the case of JSON it is always 3 bytes. Unlike the documentation, however, the 8 byte value is in little-endian form.
The format of all temporal values is outlined in the MySQL documentation,
although since the MySQL JSON type is only available in 5.7, only version 2 of the date-time formats
are necessary.
formatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseDecimal(int length,
JsonFormatter formatter)
throws IOException
DECIMAL value. The first two bytes are the precision and scale, followed by the binary
representation of the decimal itself.
length - the length of the complete binary representationformatter - the formatter to be notified of the parsed value; may not be null
IOException - if there is a problem reading the JSON value
protected void parseOpaqueValue(ColumnType type,
int length,
JsonFormatter formatter)
throws IOException
IOException
protected int readFractionalSecondsInMicroseconds()
throws IOException
IOException
protected long readBigEndianLong(int numBytes)
throws IOException
IOException
protected int readUnsignedIndex(int maxValue,
boolean isSmall,
String desc)
throws IOException
IOException
protected int readInt16()
throws IOException
IOException
protected int readUInt16()
throws IOException
IOException
protected int readInt24()
throws IOException
IOException
protected int readInt32()
throws IOException
IOException
protected long readUInt32()
throws IOException
IOException
protected long readInt64()
throws IOException
IOException
protected BigInteger readUInt64()
throws IOException
IOException
protected int readVariableInt()
throws IOException
If the high bit of a byte is 1, the length field is continued in the next byte, otherwise it is the last byte of the length field. So we need 1 byte to represent lengths up to 127, 2 bytes to represent lengths up to 16383, and so on...
IOException
protected Boolean readLiteral()
throws IOException
IOException
protected ValueType readValueType()
throws IOException
IOExceptionprotected static String asHex(byte b)
protected static String asHex(int value)
|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||