From 88f49fa8cc916720bddb28e1be960d328e6a9f54 Mon Sep 17 00:00:00 2001 From: Tristan Tarrant Date: Tue, 5 Mar 2024 13:12:01 +0100 Subject: [PATCH] IPROTO-305 MessageMarshaller map support * undeprecate MessageMarshaller * add compliance tests for map against protoc-generated marshallers --- .github/workflows/pull_requests.yml | 6 + .github/workflows/release.yml | 3 + .github/workflows/test_report.yaml | 7 - .../protostream/MessageMarshaller.java | 17 +- .../descriptors/MapDescriptor.java | 12 ++ .../impl/ProtoStreamReaderImpl.java | 161 +++++++++++------- .../impl/ProtoStreamWriterImpl.java | 95 ++++++++++- .../protostream/impl/TagReaderImpl.java | 6 +- .../protostream/impl/TagWriterImpl.java | 4 - integrationtests/pom.xml | 18 ++ .../compliance/ComplianceTest.java | 67 ++++++++ .../compliance/handwritten/CustomValue.java | 34 ++++ .../handwritten/CustomValueMarshaller.java | 28 +++ .../compliance/handwritten/MapsTest.java | 8 + .../handwritten/MapsTestMarshaller.java | 32 ++++ integrationtests/src/test/proto/maps.proto | 13 ++ parent/pom.xml | 14 ++ 17 files changed, 428 insertions(+), 97 deletions(-) create mode 100644 integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/ComplianceTest.java create mode 100644 integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValue.java create mode 100644 integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValueMarshaller.java create mode 100644 integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTest.java create mode 100644 integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTestMarshaller.java create mode 100644 integrationtests/src/test/proto/maps.proto diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index c38c14d47..7eb263b5b 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -14,6 +14,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Protoc + uses: arduino/setup-protoc@v3 + - name: Setup Java uses: actions/setup-java@v4 with: @@ -36,6 +39,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Protoc + uses: arduino/setup-protoc@v3 + - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b187fcb8..5b8fbc532 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,6 +30,9 @@ jobs: mvn -B versions:set -DnewVersion=${{ github.event.inputs.version }} -DprocessAllModules=true mvn -B versions:set-property -Dproperty=version.infinispan -DnewVersion=${{ github.event.inputs.version }} + - name: Install Protoc + uses: arduino/setup-protoc@v3 + - name: Set up Java for publishing to OSSRH uses: actions/setup-java@v4 with: diff --git a/.github/workflows/test_report.yaml b/.github/workflows/test_report.yaml index 84665ffce..d5c06c865 100644 --- a/.github/workflows/test_report.yaml +++ b/.github/workflows/test_report.yaml @@ -8,13 +8,6 @@ jobs: report: runs-on: ubuntu-latest steps: - - uses: dorny/test-reporter@v1 - with: - artifact: jdk11-test-results - name: JDK 11 Tests - path: '**/*.xml' - reporter: java-junit - - uses: dorny/test-reporter@v1 with: artifact: jdk17-test-results diff --git a/core/src/main/java/org/infinispan/protostream/MessageMarshaller.java b/core/src/main/java/org/infinispan/protostream/MessageMarshaller.java index 8f61a7d88..695824781 100644 --- a/core/src/main/java/org/infinispan/protostream/MessageMarshaller.java +++ b/core/src/main/java/org/infinispan/protostream/MessageMarshaller.java @@ -5,6 +5,7 @@ import java.time.Instant; import java.util.Collection; import java.util.Date; +import java.util.Map; /** * Contract to be implemented by manually written marshallers for Protobuf message (entity) types. The marshaller @@ -12,10 +13,7 @@ * * @author anistor@redhat.com * @since 1.0 - * @deprecated since 4.3.1.Final. Will be removed in version 5. Please use annotation based marshallers instead. See - * {@link org.infinispan.protostream.annotations.AutoProtoSchemaBuilder} */ -@Deprecated public interface MessageMarshaller extends BaseMarshaller { /** @@ -85,6 +83,8 @@ interface ProtoStreamReader { > C readCollection(String fieldName, C collection, Class elementClass) throws IOException; E[] readArray(String fieldName, Class elementClass) throws IOException; + + > M readMap(String fieldName, M map, Class keyClass, Class valueClass) throws IOException; } /** @@ -141,15 +141,6 @@ interface ProtoStreamWriter { void writeObject(String fieldName, E value, Class clazz) throws IOException; - /** - * Writes an enum value. The third argument (the {@code class} was never used internally) so this variant is now - * deprecated. - * - * @deprecated replaced by {@link ProtoStreamWriter#writeEnum(String fieldName, Enum value)} - */ - @Deprecated - > void writeEnum(String fieldName, E value, Class clazz) throws IOException; - /** * Writes an enum value. * @@ -161,5 +152,7 @@ interface ProtoStreamWriter { void writeCollection(String fieldName, Collection collection, Class elementClass) throws IOException; void writeArray(String fieldName, E[] array, Class elementClass) throws IOException; + + void writeMap(String fieldName, Map map, Class keyClass, Class valueClass) throws IOException; } } diff --git a/core/src/main/java/org/infinispan/protostream/descriptors/MapDescriptor.java b/core/src/main/java/org/infinispan/protostream/descriptors/MapDescriptor.java index 463e1b2b0..62c3acb99 100644 --- a/core/src/main/java/org/infinispan/protostream/descriptors/MapDescriptor.java +++ b/core/src/main/java/org/infinispan/protostream/descriptors/MapDescriptor.java @@ -27,6 +27,18 @@ public JavaType getKeyJavaType() { return getKeyType().getJavaType(); } + public int getWireTag() { + return WireType.makeTag(number, WireType.LENGTH_DELIMITED); + } + + public int getKeyWireTag() { + return WireType.makeTag(1, keyType.getWireType()); + } + + public int getValueWireTag() { + return WireType.makeTag(2, type.getWireType()); + } + @Override public Label getLabel() { return Label.OPTIONAL; diff --git a/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamReaderImpl.java b/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamReaderImpl.java index 9706acdda..0e1bd5db6 100644 --- a/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamReaderImpl.java +++ b/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamReaderImpl.java @@ -11,6 +11,7 @@ import java.util.Date; import java.util.EnumSet; import java.util.List; +import java.util.Map; import org.infinispan.protostream.ImmutableSerializationContext; import org.infinispan.protostream.MessageContext; @@ -21,6 +22,7 @@ import org.infinispan.protostream.descriptors.Descriptor; import org.infinispan.protostream.descriptors.FieldDescriptor; import org.infinispan.protostream.descriptors.JavaType; +import org.infinispan.protostream.descriptors.MapDescriptor; import org.infinispan.protostream.descriptors.Type; import org.infinispan.protostream.descriptors.WireType; import org.jboss.logging.Logger; @@ -149,25 +151,13 @@ private Object convertWireTypeToJavaType(Type type, Object o) { case STRING: o = new String((byte[]) o, StandardCharsets.UTF_8); break; - case BYTES: - o = (byte[]) o; + case BYTES, INT64, UINT64, FIXED64, SFIXED64, SINT64, FIXED32, SFIXED32: break; case INT32: case UINT32: case SINT32: o = ((Long) o).intValue(); break; - case FIXED32: - case SFIXED32: - o = (Integer) o; - break; - case INT64: - case UINT64: - case FIXED64: - case SFIXED64: - case SINT64: - o = (Long) o; - break; case BOOL: o = ((Long) o) != 0; break; @@ -336,7 +326,7 @@ private A readNestedObject(FieldDescriptor fd, Class clazz, ProtobufTagMa TagReader in = ctx.getReader(); A a; if (fd.getType() == Type.GROUP) { - a = marshallerDelegate.unmarshall(ctx ,fd); + a = marshallerDelegate.unmarshall(ctx, fd); in.checkLastTagWas(WireType.makeTag(fd.getNumber(), WireType.WIRETYPE_END_GROUP)); } else if (fd.getType() == Type.MESSAGE) { if (length < 0) { @@ -424,56 +414,24 @@ private void readPrimitiveCollection(FieldDescriptor fd, Collection messageContext.in.readDouble(); + case FLOAT -> messageContext.in.readFloat(); + case BOOL -> messageContext.in.readBool(); + case STRING -> messageContext.in.readString(); + case BYTES -> messageContext.in.readByteArray(); + case INT64 -> messageContext.in.readInt64(); + case UINT64 -> messageContext.in.readUInt64(); + case FIXED64 -> messageContext.in.readFixed64(); + case SFIXED64 -> messageContext.in.readSFixed64(); + case SINT64 -> messageContext.in.readSInt64(); + case INT32 -> messageContext.in.readInt32(); + case FIXED32 -> messageContext.in.readFixed32(); + case UINT32 -> messageContext.in.readUInt32(); + case SFIXED32 -> messageContext.in.readSFixed32(); + case SINT32 -> messageContext.in.readSInt32(); + default -> throw new IllegalStateException("Unexpected field type : " + type); + }; collection.add(value); } else { messageContext.unknownFieldSet.readSingleField(tag, messageContext.in); @@ -509,4 +467,79 @@ private void checkFieldRead(FieldDescriptor fd, boolean expectRepeated) { log.fieldReadOutOfSequence(fd.getFullName()); } } + + @Override + public > M readMap(String fieldName, M map, Class keyClass, Class valueClass) throws IOException { + final MapDescriptor md = (MapDescriptor) messageContext.getFieldByName(fieldName); + TagReaderImpl in = (TagReaderImpl) ctx.getReader(); + final int expectedTag = md.getWireTag(); + while (true) { + Object o = messageContext.unknownFieldSet.consumeTag(expectedTag); + if (o == null) { + break; + } + readMapEntry(map, valueClass, TagReaderImpl.newNestedInstance(in, (byte[]) o), md); + } + while (true) { + int tag = in.readTag(); + if (tag == 0) { + break; + } + if (tag != expectedTag) { + messageContext.unknownFieldSet.readSingleField(tag, messageContext.in); + break; + } + int len = in.readUInt32(); + int limit = in.pushLimit(len); + readMapEntry(map, valueClass, in, md); + in.popLimit(limit); + } + return map; + } + + private > void readMapEntry(M map, Class valueClass, TagReaderImpl in, MapDescriptor md) throws IOException { + int ktag = in.readTag(); + if (ktag != md.getKeyWireTag()) { + throw new IllegalStateException(); + } + Object k = switch (md.getKeyType()) { + case BOOL -> in.readBool(); + case INT32 -> in.readInt32(); + case INT64 -> in.readInt64(); + case FIXED32 -> in.readFixed32(); + case FIXED64 -> in.readFixed64(); + case SINT32 -> in.readSInt32(); + case SINT64 -> in.readSInt64(); + case SFIXED32 -> in.readSFixed32(); + case SFIXED64 -> in.readSFixed64(); + case UINT32 -> in.readUInt32(); + case UINT64 -> in.readUInt64(); + case STRING -> in.readString(); + default -> + throw new IllegalArgumentException("The Protobuf declared field type is not compatible with the written type : " + md.getFullName()); + }; + int vtag = in.readTag(); + if (vtag != md.getValueWireTag()) { + throw new IllegalStateException(); + } + Object v = switch (md.getType()) { + case BOOL -> in.readBool(); + case INT32 -> in.readInt32(); + case INT64 -> in.readInt64(); + case FIXED32 -> in.readFixed32(); + case FIXED64 -> in.readFixed64(); + case SINT32 -> in.readSInt32(); + case SINT64 -> in.readSInt64(); + case SFIXED32 -> in.readSFixed32(); + case SFIXED64 -> in.readSFixed64(); + case UINT32 -> in.readUInt32(); + case UINT64 -> in.readUInt64(); + case STRING -> in.readString(); + case MESSAGE -> readNestedObject(md, valueClass, in, -1); + default -> + throw new IllegalArgumentException("The Protobuf declared field type is not compatible with the written type : " + md.getFullName()); + }; + map.put((K) k, (V) v); + in.checkLastTagWas(0); + } } diff --git a/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamWriterImpl.java b/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamWriterImpl.java index 0fc1725a4..bac3ce88b 100644 --- a/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamWriterImpl.java +++ b/core/src/main/java/org/infinispan/protostream/impl/ProtoStreamWriterImpl.java @@ -7,6 +7,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.infinispan.protostream.ImmutableSerializationContext; import org.infinispan.protostream.MessageContext; @@ -15,6 +16,7 @@ import org.infinispan.protostream.descriptors.Descriptor; import org.infinispan.protostream.descriptors.FieldDescriptor; import org.infinispan.protostream.descriptors.Label; +import org.infinispan.protostream.descriptors.MapDescriptor; import org.infinispan.protostream.descriptors.Type; import org.infinispan.protostream.descriptors.WireType; import org.jboss.logging.Logger; @@ -486,11 +488,6 @@ public void writeObject(String fieldName, E value, Class clazz) } } - @Override - public > void writeEnum(String fieldName, E value, Class clazz) throws IOException { - writeEnum(fieldName, value); - } - @Override public > void writeEnum(String fieldName, E value) throws IOException { final FieldDescriptor fd = messageContext.getFieldByName(fieldName); @@ -808,6 +805,94 @@ public void writeArray(String fieldName, E[] array, Class eleme } } + @Override + public void writeMap(String fieldName, Map map, Class keyClass, Class valueClass) throws IOException { + final MapDescriptor md = (MapDescriptor) messageContext.getFieldByName(fieldName); + if (map == null) { + // a map can never be flagged as required + return; + } + + final int fieldNumber = md.getNumber(); + for (Map.Entry entry : map.entrySet()) { + Object key = entry.getKey(); + validateElement(key, keyClass); // Protobuf 3 does not allow null keys + ByteArrayOutputStreamEx nestedBaos = new ByteArrayOutputStreamEx(); + TagWriterImpl out = TagWriterImpl.newNestedInstance(messageContext.out, nestedBaos); + // Write the key as field 1 + switch (md.getKeyType()) { + case BOOL -> out.writeBool(1, (Boolean) key); + case INT32 -> out.writeInt32(1, (Integer) key); + case INT64 -> out.writeInt64(1, (Long) key); + case FIXED32 -> out.writeFixed32(1, (Integer) key); + case FIXED64 -> out.writeFixed64(1, (Long) key); + case SINT32 -> out.writeSInt32(1, (Integer) key); + case SINT64 -> out.writeSInt64(1, (Long) key); + case SFIXED32 -> out.writeSFixed32(1, (Integer) key); + case SFIXED64 -> out.writeSFixed64(1, (Long) key); + case UINT32 -> out.writeUInt32(1, (Integer) key); + case UINT64 -> out.writeUInt64(1, (Long) key); + case STRING -> out.writeString(1, (String) key); + default -> + throw new IllegalArgumentException("The Protobuf declared field type is not compatible with the written type : " + md.getFullName()); + } + Object value = entry.getValue(); + // Write the value as field 2 + if (value == null) { + switch (md.getType()) { + case BOOL -> out.writeBool(2, false); + case INT32 -> out.writeInt32(2, 0); + case INT64 -> out.writeInt64(2, 0); + case FIXED32 -> out.writeFixed32(2, 0); + case FIXED64 -> out.writeFixed64(2, 0); + case SINT32 -> out.writeSInt32(2, 0); + case SINT64 -> out.writeSInt64(2, 0); + case SFIXED32 -> out.writeSFixed32(2, 0); + case SFIXED64 -> out.writeSFixed64(2, 0); + case UINT32 -> out.writeUInt32(2, 0); + case UINT64 -> out.writeUInt64(2, 0); + case DOUBLE -> out.writeDouble(2, 0); + case FLOAT -> out.writeFloat(2, 0); + case STRING -> out.writeString(2, ""); + case BYTES -> out.writeBytes(2, new byte[0]); + case ENUM -> out.writeEnum(2, 0); + default -> + throw new IllegalArgumentException("The Protobuf declared field type is not compatible with the written type : " + md.getFullName()); + } + } else { + switch (md.getType()) { + case BOOL -> out.writeBool(2, (Boolean) value); + case INT32 -> out.writeInt32(2, (Integer) value); + case INT64 -> out.writeInt64(2, (Long) value); + case FIXED32 -> out.writeFixed32(2, (Integer) value); + case FIXED64 -> out.writeFixed64(2, (Long) value); + case SINT32 -> out.writeSInt32(2, (Integer) value); + case SINT64 -> out.writeSInt64(2, (Long) value); + case SFIXED32 -> out.writeSFixed32(2, (Integer) value); + case SFIXED64 -> out.writeSFixed64(2, (Long) value); + case UINT32 -> out.writeUInt32(2, (Integer) value); + case UINT64 -> out.writeUInt64(2, (Long) value); + case STRING -> out.writeString(2, (String) value); + case BYTES -> out.writeBytes(2, (byte[]) value); + case ENUM -> out.writeEnum(2, ((Enum) value).ordinal()); + case MESSAGE -> { + // FIXME: there is too much nesting here. We can definitely improve things + BaseMarshallerDelegate marshallerDelegate = serCtx.getMarshallerDelegate(valueClass); + ByteArrayOutputStreamEx mapValueBaos = new ByteArrayOutputStreamEx(); + TagWriterImpl mapValueOut = TagWriterImpl.newNestedInstance(out, mapValueBaos); + marshallerDelegate.marshall(mapValueOut, md, (V) value); + mapValueOut.flush(); + out.writeBytes(2, mapValueBaos.getByteBuffer()); + } + default -> + throw new IllegalArgumentException("The Protobuf declared field type is not compatible with the written type : " + md.getFullName()); + } + } + out.flush(); + messageContext.out.writeBytes(fieldNumber, nestedBaos.getByteBuffer()); + } + } + private void validateElementClass(Class elementClass, Class expectedElementClass) { if (elementClass != expectedElementClass) { throw new IllegalArgumentException("elementClass argument should be " + expectedElementClass.getCanonicalName()); diff --git a/core/src/main/java/org/infinispan/protostream/impl/TagReaderImpl.java b/core/src/main/java/org/infinispan/protostream/impl/TagReaderImpl.java index 5a3585cea..f56aefdbb 100644 --- a/core/src/main/java/org/infinispan/protostream/impl/TagReaderImpl.java +++ b/core/src/main/java/org/infinispan/protostream/impl/TagReaderImpl.java @@ -272,10 +272,6 @@ public boolean isInputStream() { return (decoder instanceof InputStreamDecoder); } - /** - * @deprecated this will be removed in 5.0 together with {@link org.infinispan.protostream.MessageMarshaller} - */ - @Deprecated public ProtoStreamReaderImpl getProtoStreamReader() { if (parent != null) { return parent.getProtoStreamReader(); @@ -326,7 +322,7 @@ final void checkLastTagWas(int expectedTag) throws IOException { return; } if (expectedTag == 0) { - throw new MalformedProtobufException("Expected ond of message but found tag " + lastTag); + throw new MalformedProtobufException("Expected end of message but found tag " + lastTag); } throw new MalformedProtobufException("Protobuf message end group tag expected but found " + lastTag); } diff --git a/core/src/main/java/org/infinispan/protostream/impl/TagWriterImpl.java b/core/src/main/java/org/infinispan/protostream/impl/TagWriterImpl.java index f4415a2b3..0b4319c6d 100644 --- a/core/src/main/java/org/infinispan/protostream/impl/TagWriterImpl.java +++ b/core/src/main/java/org/infinispan/protostream/impl/TagWriterImpl.java @@ -273,10 +273,6 @@ public int depth() { return depth; } - /** - * @deprecated this will be removed in 5.0 together with {@link org.infinispan.protostream.MessageMarshaller} - */ - @Deprecated public ProtoStreamWriterImpl getProtoStreamWriter() { if (parent != null) { return parent.getProtoStreamWriter(); diff --git a/integrationtests/pom.xml b/integrationtests/pom.xml index b55a23b5d..6a57413ac 100644 --- a/integrationtests/pom.xml +++ b/integrationtests/pom.xml @@ -51,6 +51,12 @@ test + + com.google.protobuf + protobuf-java + test + + com.fasterxml.jackson.core jackson-core @@ -102,6 +108,18 @@ maven-surefire-report-plugin + + + org.xolstice.maven.plugins + protobuf-maven-plugin + + + + test-compile + + + + diff --git a/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/ComplianceTest.java b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/ComplianceTest.java new file mode 100644 index 000000000..d2f2ad89e --- /dev/null +++ b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/ComplianceTest.java @@ -0,0 +1,67 @@ +package org.infinispan.protostream.integrationtests.compliance; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import org.infinispan.protostream.FileDescriptorSource; +import org.infinispan.protostream.ProtobufUtil; +import org.infinispan.protostream.SerializationContext; +import org.infinispan.protostream.integrationtests.compliance.handwritten.CustomValue; +import org.infinispan.protostream.integrationtests.compliance.handwritten.CustomValueMarshaller; +import org.infinispan.protostream.integrationtests.compliance.handwritten.MapsTest; +import org.infinispan.protostream.integrationtests.compliance.handwritten.MapsTestMarshaller; +import org.junit.Test; + + +public class ComplianceTest { + + @Test + public void testMap() throws IOException { + Maps.MapsTest.Builder builder = Maps.MapsTest.newBuilder(); + builder.putAllStringmap( + Map.of( + "k1", "v1", + "k2", "v2" + ) + ); + builder.putAllCustommap( + Map.of( + 1, Maps.CustomValue.newBuilder().setId(1).setS("s1").build(), + 2, Maps.CustomValue.newBuilder().setId(2).setS("s2").build() + ) + ); + Maps.MapsTest pcMap = builder.build(); + ByteArrayOutputStream pcBaos = new ByteArrayOutputStream(); + pcMap.writeTo(pcBaos); + + SerializationContext ctx = ProtobufUtil.newSerializationContext(); + ctx.registerProtoFiles(FileDescriptorSource.fromResources("/maps.proto")); + ctx.registerMarshaller(new CustomValueMarshaller()); + ctx.registerMarshaller(new MapsTestMarshaller()); + + MapsTest psMap = new MapsTest(); + psMap.stringmap = Map.of( + "k1", "v1", + "k2", "v2" + ); + psMap.custommap = Map.of( + 1, new CustomValue(1, "s1"), + 2, new CustomValue(2, "s2") + ); + ByteArrayOutputStream psBaos = new ByteArrayOutputStream(); + ProtobufUtil.writeTo(ctx, psBaos, psMap); + assertThat(psBaos.toByteArray()).isEqualTo(pcBaos.toByteArray()); + + Files.write(Path.of("/tmp/pc.data"), pcBaos.toByteArray()); + Files.write(Path.of("/tmp/ps.data"), psBaos.toByteArray()); + + MapsTest pc2psMap = ProtobufUtil.fromByteArray(ctx, pcBaos.toByteArray(), MapsTest.class); + assertThat(pc2psMap.stringmap).containsAllEntriesOf(psMap.stringmap); + assertThat(pc2psMap.custommap).containsAllEntriesOf(psMap.custommap); + } +} diff --git a/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValue.java b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValue.java new file mode 100644 index 000000000..bf4e007e8 --- /dev/null +++ b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValue.java @@ -0,0 +1,34 @@ +package org.infinispan.protostream.integrationtests.compliance.handwritten; + +import java.util.Objects; + +public class CustomValue { + int id; + String s; + + public CustomValue(int id, String s) { + this.id = id; + this.s = s; + } + + @Override + public String toString() { + return "CustomValue{" + + "id=" + id + + ", s='" + s + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CustomValue that = (CustomValue) o; + return id == that.id && Objects.equals(s, that.s); + } + + @Override + public int hashCode() { + return Objects.hash(id, s); + } +} diff --git a/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValueMarshaller.java b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValueMarshaller.java new file mode 100644 index 000000000..aab61e50f --- /dev/null +++ b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/CustomValueMarshaller.java @@ -0,0 +1,28 @@ +package org.infinispan.protostream.integrationtests.compliance.handwritten; + +import java.io.IOException; + +import org.infinispan.protostream.MessageMarshaller; + +public class CustomValueMarshaller implements MessageMarshaller { + @Override + public Class getJavaClass() { + return CustomValue.class; + } + + @Override + public String getTypeName() { + return "org.infinispan.protostream.integrationtests.compliance.CustomValue"; + } + + @Override + public CustomValue readFrom(ProtoStreamReader reader) throws IOException { + return new CustomValue(reader.readInt("id"), reader.readString("s")); + } + + @Override + public void writeTo(ProtoStreamWriter writer, CustomValue mapsTest) throws IOException { + writer.writeInt("id", mapsTest.id); + writer.writeString("s", mapsTest.s); + } +} diff --git a/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTest.java b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTest.java new file mode 100644 index 000000000..b3cc41e4c --- /dev/null +++ b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTest.java @@ -0,0 +1,8 @@ +package org.infinispan.protostream.integrationtests.compliance.handwritten; + +import java.util.Map; + +public class MapsTest { + public Map stringmap; + public Map custommap; +} diff --git a/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTestMarshaller.java b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTestMarshaller.java new file mode 100644 index 000000000..7e66b6bf3 --- /dev/null +++ b/integrationtests/src/test/java/org/infinispan/protostream/integrationtests/compliance/handwritten/MapsTestMarshaller.java @@ -0,0 +1,32 @@ +package org.infinispan.protostream.integrationtests.compliance.handwritten; + +import java.io.IOException; +import java.util.HashMap; + +import org.infinispan.protostream.MessageMarshaller; + +public class MapsTestMarshaller implements MessageMarshaller { + @Override + public Class getJavaClass() { + return MapsTest.class; + } + + @Override + public String getTypeName() { + return "org.infinispan.protostream.integrationtests.compliance.MapsTest"; + } + + @Override + public MapsTest readFrom(ProtoStreamReader reader) throws IOException { + MapsTest mapsTest = new MapsTest(); + mapsTest.stringmap = reader.readMap("stringmap", new HashMap<>(), String.class, String.class); + mapsTest.custommap = reader.readMap("custommap", new HashMap<>(), Integer.class, CustomValue.class); + return mapsTest; + } + + @Override + public void writeTo(ProtoStreamWriter writer, MapsTest mapsTest) throws IOException { + writer.writeMap("stringmap", mapsTest.stringmap, String.class, String.class); + writer.writeMap("custommap", mapsTest.custommap, Integer.class, CustomValue.class); + } +} diff --git a/integrationtests/src/test/proto/maps.proto b/integrationtests/src/test/proto/maps.proto new file mode 100644 index 000000000..987508aa6 --- /dev/null +++ b/integrationtests/src/test/proto/maps.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package org.infinispan.protostream.integrationtests.compliance; + +message CustomValue { + int32 id = 1; + string s = 2; +} + +message MapsTest { + map stringmap = 1; + map custommap = 2; +} diff --git a/parent/pom.xml b/parent/pom.xml index 1b0fbe437..e61525351 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -117,6 +117,7 @@ 3.0.1 1.6.13 3.1.0 + 0.6.1 4.13.2 0.21 @@ -131,6 +132,7 @@ 2.16.1 1.1.1 3.25.3 + 3.25.3 https://s01.oss.sonatype.org/ @@ -311,6 +313,13 @@ ${version.jboss.marshalling} test + + + com.google.protobuf + protobuf-java + ${version.protobuf} + test + @@ -431,6 +440,11 @@ + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${version.protobuf.plugin} +