From 012d4547348f9cc969f053b39788d40bde0d256d Mon Sep 17 00:00:00 2001 From: Dmitriy Tverdiakov Date: Fri, 5 Jun 2026 15:09:27 +0100 Subject: [PATCH] feat(uuid): Add support for UUID and Bolt 6.1 --- neo4j-bolt-connection-bom/pom.xml | 2 +- neo4j-bolt-connection-netty/pom.xml | 2 +- .../async/connection/BoltProtocolUtil.java | 2 + .../messaging/common/CommonValuePacker.java | 6 ++ .../messaging/common/CommonValueUnpacker.java | 7 ++ .../impl/messaging/v6/MessageReaderV6.java | 7 +- .../impl/messaging/v6/ValuePackerV6.java | 2 +- .../impl/messaging/v6/ValueUnpackerV6.java | 2 +- .../impl/messaging/v61/BoltProtocolV61.java | 37 ++++++++++ .../impl/messaging/v61/MessageFormatV61.java | 34 +++++++++ .../impl/messaging/v61/MessageReaderV61.java | 27 +++++++ .../impl/messaging/v61/MessageWriterV61.java | 72 +++++++++++++++++++ .../impl/messaging/v61/ValuePackerV61.java | 33 +++++++++ .../impl/messaging/v61/ValueUnpackerV61.java | 34 +++++++++ .../netty/impl/packstream/PackStream.java | 27 ++++++- .../netty/impl/packstream/PackType.java | 1 + neo4j-bolt-connection-pooled/pom.xml | 2 +- neo4j-bolt-connection-query-api/pom.xml | 2 +- neo4j-bolt-connection-routed/pom.xml | 2 +- neo4j-bolt-connection-test-values/pom.xml | 2 +- .../test/values/impl/UUIDValue.java | 64 +++++++++++++++++ .../test/values/impl/ValueAdapter.java | 6 ++ neo4j-bolt-connection/pom.xml | 2 +- .../neo4j/bolt/connection/values/Type.java | 7 +- .../neo4j/bolt/connection/values/Value.java | 3 + pom.xml | 2 +- 26 files changed, 372 insertions(+), 15 deletions(-) create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/BoltProtocolV61.java create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageFormatV61.java create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageReaderV61.java create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageWriterV61.java create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValuePackerV61.java create mode 100644 neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValueUnpackerV61.java create mode 100644 neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/UUIDValue.java diff --git a/neo4j-bolt-connection-bom/pom.xml b/neo4j-bolt-connection-bom/pom.xml index c70d914c..4c1d5bdc 100644 --- a/neo4j-bolt-connection-bom/pom.xml +++ b/neo4j-bolt-connection-bom/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-bom diff --git a/neo4j-bolt-connection-netty/pom.xml b/neo4j-bolt-connection-netty/pom.xml index b8530cb3..dc5d7a30 100644 --- a/neo4j-bolt-connection-netty/pom.xml +++ b/neo4j-bolt-connection-netty/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-netty diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/async/connection/BoltProtocolUtil.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/async/connection/BoltProtocolUtil.java index b0d15dc6..e10ab543 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/async/connection/BoltProtocolUtil.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/async/connection/BoltProtocolUtil.java @@ -42,6 +42,7 @@ import org.neo4j.bolt.connection.netty.impl.messaging.v57.BoltProtocolV57; import org.neo4j.bolt.connection.netty.impl.messaging.v58.BoltProtocolV58; import org.neo4j.bolt.connection.netty.impl.messaging.v6.BoltProtocolV6; +import org.neo4j.bolt.connection.netty.impl.messaging.v61.BoltProtocolV61; public final class BoltProtocolUtil { public static final int BOLT_MAGIC_PREAMBLE = 0x6060B017; @@ -66,6 +67,7 @@ public final class BoltProtocolUtil { static { var map = new TreeMap(Comparator.reverseOrder()); map.putAll(Map.ofEntries( + Map.entry(BoltProtocolV61.VERSION, BoltProtocolV61.INSTANCE), Map.entry(BoltProtocolV6.VERSION, BoltProtocolV6.INSTANCE), Map.entry(BoltProtocolV58.VERSION, BoltProtocolV58.INSTANCE), Map.entry(BoltProtocolV57.VERSION, BoltProtocolV57.INSTANCE), diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValuePacker.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValuePacker.java index 90189e38..66c57cbd 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValuePacker.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValuePacker.java @@ -26,6 +26,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Map; +import java.util.UUID; import org.neo4j.bolt.connection.exception.BoltClientException; import org.neo4j.bolt.connection.exception.BoltUnsupportedFeatureException; import org.neo4j.bolt.connection.netty.impl.messaging.ValuePacker; @@ -144,6 +145,7 @@ protected void packInternalValue(Value value) throws IOException { } case VECTOR -> packVector(value.asBoltVector()); case UNSUPPORTED -> throw new BoltClientException("Unsupported type must not be sent to the server"); + case UUID -> packUUID(value.asUUID()); default -> throw new IOException("Unknown type: " + value.boltValueType().name()); } @@ -153,6 +155,10 @@ protected void packVector(Vector vector) throws IOException { throw new BoltUnsupportedFeatureException("Vector type is not supported by this Bolt protocol version"); } + protected void packUUID(UUID uuid) throws IOException { + throw new BoltUnsupportedFeatureException("UUID type is not supported by this Bolt protocol version"); + } + private void packDate(LocalDate localDate) throws IOException { packer.packStructHeader(DATE_STRUCT_SIZE, DATE); packer.pack(localDate.toEpochDay()); diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValueUnpacker.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValueUnpacker.java index 6aa118ab..49b5bef3 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValueUnpacker.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/common/CommonValueUnpacker.java @@ -156,6 +156,9 @@ protected Value unpack() throws IOException { case STRING -> { return valueFactory.value(unpacker.unpackString()); } + case UUID -> { + return unpackUUID(); + } case MAP -> { return valueFactory.value(unpackMap()); } @@ -449,6 +452,10 @@ protected Value unpackUnsupported(long size) throws IOException { throw new UnsupportedOperationException(); } + protected Value unpackUUID() throws IOException { + throw new BoltProtocolException("Unknown PackStream type: UUID"); + } + private static ZonedDateTime newZonedDateTime(long epochSecondLocal, long nano, ZoneId zoneId) { var instant = Instant.ofEpochSecond(epochSecondLocal, nano); var localDateTime = LocalDateTime.ofInstant(instant, UTC); diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/MessageReaderV6.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/MessageReaderV6.java index f78da16a..2ef76fab 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/MessageReaderV6.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/MessageReaderV6.java @@ -18,16 +18,21 @@ import java.util.Map; import org.neo4j.bolt.connection.GqlError; +import org.neo4j.bolt.connection.netty.impl.messaging.ValueUnpacker; import org.neo4j.bolt.connection.netty.impl.messaging.v57.MessageReaderV57; import org.neo4j.bolt.connection.netty.impl.packstream.PackInput; import org.neo4j.bolt.connection.values.Value; import org.neo4j.bolt.connection.values.ValueFactory; -final class MessageReaderV6 extends MessageReaderV57 { +public class MessageReaderV6 extends MessageReaderV57 { public MessageReaderV6(PackInput input, ValueFactory valueFactory) { super(new ValueUnpackerV6(input, valueFactory), valueFactory); } + public MessageReaderV6(ValueUnpacker unpacker, ValueFactory valueFactory) { + super(unpacker, valueFactory); + } + @Override protected GqlError unpackGqlError(Map params) { return super.unpackGqlError(params); diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValuePackerV6.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValuePackerV6.java index 22bfd9af..cb1997c3 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValuePackerV6.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValuePackerV6.java @@ -23,7 +23,7 @@ import org.neo4j.bolt.connection.netty.impl.packstream.PackStream; import org.neo4j.bolt.connection.values.Vector; -final class ValuePackerV6 extends CommonValuePacker { +public class ValuePackerV6 extends CommonValuePacker { public ValuePackerV6(PackOutput output) { super(output, true); } diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValueUnpackerV6.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValueUnpackerV6.java index a6592d58..514c0bb2 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValueUnpackerV6.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v6/ValueUnpackerV6.java @@ -27,7 +27,7 @@ import org.neo4j.bolt.connection.values.Value; import org.neo4j.bolt.connection.values.ValueFactory; -final class ValueUnpackerV6 extends ValueUnpackerV5 { +public class ValueUnpackerV6 extends ValueUnpackerV5 { public ValueUnpackerV6(PackInput input, ValueFactory valueFactory) { super(input, valueFactory); } diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/BoltProtocolV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/BoltProtocolV61.java new file mode 100644 index 00000000..0a7ae761 --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/BoltProtocolV61.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import org.neo4j.bolt.connection.BoltProtocolVersion; +import org.neo4j.bolt.connection.netty.impl.messaging.BoltProtocol; +import org.neo4j.bolt.connection.netty.impl.messaging.MessageFormat; +import org.neo4j.bolt.connection.netty.impl.messaging.v58.BoltProtocolV58; + +public class BoltProtocolV61 extends BoltProtocolV58 { + public static final BoltProtocolVersion VERSION = new BoltProtocolVersion(6, 1); + public static final BoltProtocol INSTANCE = new BoltProtocolV61(); + + @Override + public MessageFormat createMessageFormat() { + return new MessageFormatV61(); + } + + @Override + public BoltProtocolVersion version() { + return VERSION; + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageFormatV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageFormatV61.java new file mode 100644 index 00000000..21fcd502 --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageFormatV61.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import org.neo4j.bolt.connection.netty.impl.messaging.MessageFormat; +import org.neo4j.bolt.connection.netty.impl.packstream.PackInput; +import org.neo4j.bolt.connection.netty.impl.packstream.PackOutput; +import org.neo4j.bolt.connection.values.ValueFactory; + +final class MessageFormatV61 implements MessageFormat { + @Override + public Writer newWriter(PackOutput output, ValueFactory valueFactory) { + return new MessageWriterV61(output, valueFactory); + } + + @Override + public Reader newReader(PackInput input, ValueFactory valueFactory) { + return new MessageReaderV61(input, valueFactory); + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageReaderV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageReaderV61.java new file mode 100644 index 00000000..6f7ca672 --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageReaderV61.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import org.neo4j.bolt.connection.netty.impl.messaging.v6.MessageReaderV6; +import org.neo4j.bolt.connection.netty.impl.packstream.PackInput; +import org.neo4j.bolt.connection.values.ValueFactory; + +final class MessageReaderV61 extends MessageReaderV6 { + public MessageReaderV61(PackInput input, ValueFactory valueFactory) { + super(new ValueUnpackerV61(input, valueFactory), valueFactory); + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageWriterV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageWriterV61.java new file mode 100644 index 00000000..bd9adfa4 --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/MessageWriterV61.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import java.util.Map; +import org.neo4j.bolt.connection.netty.impl.messaging.AbstractMessageWriter; +import org.neo4j.bolt.connection.netty.impl.messaging.MessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.BeginMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.CommitMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.DiscardMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.GoodbyeMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.HelloMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.LogoffMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.LogonMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.PullMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.ResetMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.RollbackMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.RouteV44MessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.RunWithMetadataMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.encode.TelemetryMessageEncoder; +import org.neo4j.bolt.connection.netty.impl.messaging.request.BeginMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.CommitMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.DiscardMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.GoodbyeMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.HelloMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.LogoffMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.LogonMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.PullMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.ResetMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.RollbackMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.RouteMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.RunWithMetadataMessage; +import org.neo4j.bolt.connection.netty.impl.messaging.request.TelemetryMessage; +import org.neo4j.bolt.connection.netty.impl.packstream.PackOutput; +import org.neo4j.bolt.connection.values.ValueFactory; + +final class MessageWriterV61 extends AbstractMessageWriter { + public MessageWriterV61(PackOutput output, ValueFactory valueFactory) { + super(new ValuePackerV61(output), buildEncoders(), valueFactory); + } + + private static Map buildEncoders() { + return Map.ofEntries( + Map.entry(HelloMessage.SIGNATURE, new HelloMessageEncoder()), + Map.entry(LogonMessage.SIGNATURE, new LogonMessageEncoder()), + Map.entry(LogoffMessage.SIGNATURE, new LogoffMessageEncoder()), + Map.entry(GoodbyeMessage.SIGNATURE, new GoodbyeMessageEncoder()), + Map.entry(RunWithMetadataMessage.SIGNATURE, new RunWithMetadataMessageEncoder()), + Map.entry(RouteMessage.SIGNATURE, new RouteV44MessageEncoder()), + Map.entry(DiscardMessage.SIGNATURE, new DiscardMessageEncoder()), + Map.entry(PullMessage.SIGNATURE, new PullMessageEncoder()), + Map.entry(BeginMessage.SIGNATURE, new BeginMessageEncoder()), + Map.entry(CommitMessage.SIGNATURE, new CommitMessageEncoder()), + Map.entry(RollbackMessage.SIGNATURE, new RollbackMessageEncoder()), + Map.entry(ResetMessage.SIGNATURE, new ResetMessageEncoder()), + Map.entry(TelemetryMessage.SIGNATURE, new TelemetryMessageEncoder())); + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValuePackerV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValuePackerV61.java new file mode 100644 index 00000000..c5bedc01 --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValuePackerV61.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import java.io.IOException; +import java.util.UUID; +import org.neo4j.bolt.connection.netty.impl.messaging.v6.ValuePackerV6; +import org.neo4j.bolt.connection.netty.impl.packstream.PackOutput; + +final class ValuePackerV61 extends ValuePackerV6 { + public ValuePackerV61(PackOutput output) { + super(output); + } + + @Override + protected void packUUID(UUID uuid) throws IOException { + packer.pack(uuid); + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValueUnpackerV61.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValueUnpackerV61.java new file mode 100644 index 00000000..c1e66f4b --- /dev/null +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/messaging/v61/ValueUnpackerV61.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.netty.impl.messaging.v61; + +import java.io.IOException; +import org.neo4j.bolt.connection.netty.impl.messaging.v6.ValueUnpackerV6; +import org.neo4j.bolt.connection.netty.impl.packstream.PackInput; +import org.neo4j.bolt.connection.values.Value; +import org.neo4j.bolt.connection.values.ValueFactory; + +final class ValueUnpackerV61 extends ValueUnpackerV6 { + public ValueUnpackerV61(PackInput input, ValueFactory valueFactory) { + super(input, valueFactory); + } + + @Override + protected Value unpackUUID() throws IOException { + return valueFactory.value(unpacker.unpackUUID()); + } +} diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackStream.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackStream.java index 4b5f0504..533f11fe 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackStream.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackStream.java @@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; +import java.util.UUID; /** * PackStream is a messaging serialisation format heavily inspired by MessagePack. @@ -116,6 +117,8 @@ public class PackStream { public static final byte STRING_16 = (byte) 0xD1; public static final byte STRING_32 = (byte) 0xD2; + public static final byte UUID_16 = (byte) 0xE0; + @SuppressWarnings("unused") public static final byte RESERVED_D3 = (byte) 0xD3; @@ -142,9 +145,6 @@ public class PackStream { @SuppressWarnings("unused") public static final byte RESERVED_DF = (byte) 0xDF; - @SuppressWarnings("unused") - public static final byte RESERVED_E0 = (byte) 0xE0; - @SuppressWarnings("unused") public static final byte RESERVED_E1 = (byte) 0xE1; @@ -261,6 +261,16 @@ public void pack(String value) throws IOException { } } + public void pack(UUID value) throws IOException { + if (value == null) { + packNull(); + } else { + packUUIDHeader(); + packRaw(value.getMostSignificantBits()); + packRaw(value.getLeastSignificantBits()); + } + } + private void pack(List values) throws IOException { if (values == null) { packNull(); @@ -355,6 +365,11 @@ private void packStringHeader(int size) throws IOException { } } + @SuppressWarnings("DuplicatedCode") + private void packUUIDHeader() throws IOException { + out.writeByte(UUID_16); + } + @SuppressWarnings("DuplicatedCode") public void packListHeader(int size) throws IOException { if (size < 0x10) { @@ -529,6 +544,11 @@ public String unpackString() throws IOException { return new String(unpackUtf8(markerByte), UTF_8); } + public UUID unpackUUID() throws IOException { + var markerByte = in.readByte(); + return new UUID(in.readLong(), in.readLong()); + } + /** * This may seem confusing. This method exists to move forward the internal pointer when encountering * a null value. The idiomatic usage would be someone using {@link #peekNextType()} to detect a null type, @@ -620,6 +640,7 @@ public PackType peekNextType() throws IOException { case LIST_8, LIST_16, LIST_32 -> PackType.LIST; case MAP_8, MAP_16, MAP_32 -> PackType.MAP; case STRUCT_8, STRUCT_16 -> PackType.STRUCT; + case UUID_16 -> PackType.UUID; default -> PackType.INTEGER; }; }; diff --git a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackType.java b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackType.java index 61139bde..94164e59 100644 --- a/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackType.java +++ b/neo4j-bolt-connection-netty/src/main/java/org/neo4j/bolt/connection/netty/impl/packstream/PackType.java @@ -23,6 +23,7 @@ public enum PackType { FLOAT, BYTES, STRING, + UUID, LIST, MAP, STRUCT diff --git a/neo4j-bolt-connection-pooled/pom.xml b/neo4j-bolt-connection-pooled/pom.xml index 2c7c11fa..e87bb2df 100644 --- a/neo4j-bolt-connection-pooled/pom.xml +++ b/neo4j-bolt-connection-pooled/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-pooled diff --git a/neo4j-bolt-connection-query-api/pom.xml b/neo4j-bolt-connection-query-api/pom.xml index 48fc2f2e..161f7ce4 100644 --- a/neo4j-bolt-connection-query-api/pom.xml +++ b/neo4j-bolt-connection-query-api/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-query-api diff --git a/neo4j-bolt-connection-routed/pom.xml b/neo4j-bolt-connection-routed/pom.xml index e21e0b4f..91ff67db 100644 --- a/neo4j-bolt-connection-routed/pom.xml +++ b/neo4j-bolt-connection-routed/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-routed diff --git a/neo4j-bolt-connection-test-values/pom.xml b/neo4j-bolt-connection-test-values/pom.xml index 0e3421c4..8b1b21d0 100644 --- a/neo4j-bolt-connection-test-values/pom.xml +++ b/neo4j-bolt-connection-test-values/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection-test-values diff --git a/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/UUIDValue.java b/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/UUIDValue.java new file mode 100644 index 00000000..ec928003 --- /dev/null +++ b/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/UUIDValue.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.bolt.connection.test.values.impl; + +import java.util.Objects; +import java.util.UUID; +import org.neo4j.bolt.connection.values.Type; + +final class UUIDValue extends ValueAdapter { + private final UUID val; + + public UUIDValue(UUID val) { + if (val == null) { + throw new IllegalArgumentException("Cannot construct UUIDValue from null"); + } + this.val = val; + } + + @Override + public UUID asUUID() { + return val; + } + + @Override + public String toString() { + return val.toString(); + } + + @Override + public Type boltValueType() { + return Type.UUID; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + var that = (UUIDValue) o; + return Objects.equals(val, that.val); + } + + @Override + public int hashCode() { + return val.hashCode(); + } +} diff --git a/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/ValueAdapter.java b/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/ValueAdapter.java index bea74986..8aa2730b 100644 --- a/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/ValueAdapter.java +++ b/neo4j-bolt-connection-test-values/src/main/java/org/neo4j/bolt/connection/test/values/impl/ValueAdapter.java @@ -24,6 +24,7 @@ import java.time.OffsetTime; import java.time.ZonedDateTime; import java.util.Map; +import java.util.UUID; import org.neo4j.bolt.connection.test.values.TestNode; import org.neo4j.bolt.connection.test.values.TestPath; import org.neo4j.bolt.connection.test.values.TestRelationship; @@ -159,6 +160,11 @@ public Vector asBoltVector() { throw new Uncoercible(boltValueType().name(), "Vector"); } + @Override + public UUID asUUID() { + throw new Uncoercible(boltValueType().name(), "UUID"); + } + // Force implementation @Override public abstract boolean equals(Object obj); diff --git a/neo4j-bolt-connection/pom.xml b/neo4j-bolt-connection/pom.xml index de49bac9..64016922 100644 --- a/neo4j-bolt-connection/pom.xml +++ b/neo4j-bolt-connection/pom.xml @@ -5,7 +5,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT neo4j-bolt-connection diff --git a/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Type.java b/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Type.java index ff9c9df4..aa32ebf3 100644 --- a/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Type.java +++ b/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Type.java @@ -42,5 +42,10 @@ public enum Type { * @since 9.0.0 */ UNSUPPORTED, - NULL + NULL, + /** + * A UUID Cypher Type. + * @since 11.2.0 + */ + UUID } diff --git a/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Value.java b/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Value.java index e3472e8c..cd5e89da 100644 --- a/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Value.java +++ b/neo4j-bolt-connection/src/main/java/org/neo4j/bolt/connection/values/Value.java @@ -22,6 +22,7 @@ import java.time.OffsetTime; import java.time.ZonedDateTime; import java.util.Map; +import java.util.UUID; public interface Value extends MapAccessor { Type boltValueType(); @@ -54,6 +55,8 @@ public interface Value extends MapAccessor { Vector asBoltVector(); + UUID asUUID(); + boolean isNull(); boolean isEmpty(); diff --git a/pom.xml b/pom.xml index e9d9b555..beac38e5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.neo4j.bolt neo4j-bolt-connection-parent - 11.1-SNAPSHOT + 11.2-SNAPSHOT pom Neo4j Bolt Connection