diff --git a/protobuf/src/main/java/tools/jackson/dataformat/protobuf/ProtobufGenerator.java b/protobuf/src/main/java/tools/jackson/dataformat/protobuf/ProtobufGenerator.java index 701a11cfd..5d563f628 100644 --- a/protobuf/src/main/java/tools/jackson/dataformat/protobuf/ProtobufGenerator.java +++ b/protobuf/src/main/java/tools/jackson/dataformat/protobuf/ProtobufGenerator.java @@ -896,6 +896,7 @@ public JsonGenerator writeString(char[] text, int offset, int clen) throws Jacks } if (_currField.wireType != WireType.LENGTH_PREFIXED) { _writeEnum(new String(text, offset, clen)); + return this; } // Could guarantee with 42 chars or less; but let's do bit more speculative diff --git a/protobuf/src/test/java/tools/jackson/dataformat/protobuf/WriteEnumAsCharArrayTest.java b/protobuf/src/test/java/tools/jackson/dataformat/protobuf/WriteEnumAsCharArrayTest.java new file mode 100644 index 000000000..1bd0fe33c --- /dev/null +++ b/protobuf/src/test/java/tools/jackson/dataformat/protobuf/WriteEnumAsCharArrayTest.java @@ -0,0 +1,62 @@ +package tools.jackson.dataformat.protobuf; + +import java.io.ByteArrayOutputStream; + +import org.junit.jupiter.api.Test; + +import tools.jackson.core.JsonGenerator; + +import tools.jackson.dataformat.protobuf.schema.ProtobufSchema; +import tools.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests for writing enum-valued fields through the {@code char[]} variant of + * {@code writeString()}, which used to fall through and additionally emit the + * value as a length-prefixed String. + */ +public class WriteEnumAsCharArrayTest extends ProtobufTestBase +{ + private final ProtobufMapper MAPPER = newObjectMapper(); + + @Test + public void testEnumViaCharArrayMatchesString() throws Exception + { + ProtobufSchema schema = ProtobufSchemaLoader.std.parse(PROTOC_SEARCH_REQUEST); + + byte[] viaString = _write(schema, false); + byte[] viaCharArray = _write(schema, true); + + // 1 byte for tag, 1 byte for enum index -- nothing more + assertEquals(2, viaString.length); + assertArrayEquals(viaString, viaCharArray); + } + + @Test + public void testEnumViaCharArrayRoundTrips() throws Exception + { + ProtobufSchema schema = ProtobufSchemaLoader.std.parse(PROTOC_SEARCH_REQUEST); + SearchRequest result = MAPPER.readerFor(SearchRequest.class).with(schema) + .readValue(_write(schema, true)); + assertEquals(Corpus.WEB, result.corpus); + } + + private byte[] _write(ProtobufSchema schema, boolean useCharArray) throws Exception + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (JsonGenerator g = MAPPER.writer(schema).createGenerator(bytes)) { + g.writeStartObject(); + g.writeName("corpus"); + if (useCharArray) { + char[] ch = "WEB".toCharArray(); + g.writeString(ch, 0, ch.length); + } else { + g.writeString("WEB"); + } + g.writeEndObject(); + } + return bytes.toByteArray(); + } +} diff --git a/release-notes/CREDITS b/release-notes/CREDITS index 6f5d21a88..407b13450 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -76,3 +76,6 @@ PJ Fanning (@pjfanning) * Contributed #763: (protobuf) Use `VarHandle` for multi-byte primitive reads and writes in `ProtobufParser` / `ProtobufGenerator` (3.3.0) +* Contributed #772: (protobuf) `ProtobufGenerator.writeString(char[],int,int)` + writes enum values twice + (3.3.0) diff --git a/release-notes/VERSION b/release-notes/VERSION index 34c5dfd62..64c365edf 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -38,6 +38,9 @@ implementations) #767: (smile) Use more efficient `String` construction wrt "Compact Strings" for "short" ASCII text values of async parser (fix by @cowtowncoder, w/ Claude code) +#772: (protobuf) `ProtobufGenerator.writeString(char[],int,int)` writes enum + values twice + (contributed by @pjfanning) 3.2.3 (not yet released)