Java fixes for 19.x (#12038)
* Fix mutability bug in Java proto lite: sub-messages inside of oneofs were not
being set as immutable. This would allow code to get a builder for a
sub-message and modify the original (supposedly immutable) copy.
PiperOrigin-RevId: 511598810
* Add casts to make protobuf compatible with Java 1.8 runtime.
Fix for: https://github.com/protocolbuffers/protobuf/issues/11393
PiperOrigin-RevId: 511807920
* Update packaging for autotools
Freakin' autotools, we were supposed to be done with you!
---------
Co-authored-by: Protobuf Team Bot <protobuf-github-bot@google.com>
diff --git a/Makefile.am b/Makefile.am
index 41d4061..33225b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -330,6 +330,7 @@
java/core/src/main/java/com/google/protobuf/Internal.java \
java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java \
+ java/core/src/main/java/com/google/protobuf/Java8Compatibility.java \
java/core/src/main/java/com/google/protobuf/JavaType.java \
java/core/src/main/java/com/google/protobuf/LazyField.java \
java/core/src/main/java/com/google/protobuf/LazyFieldLite.java \
diff --git a/java/core/BUILD b/java/core/BUILD
index 419eafb..37ef950 100644
--- a/java/core/BUILD
+++ b/java/core/BUILD
@@ -45,6 +45,7 @@
"src/main/java/com/google/protobuf/Internal.java",
"src/main/java/com/google/protobuf/InvalidProtocolBufferException.java",
"src/main/java/com/google/protobuf/IterableByteBufferInputStream.java",
+ "src/main/java/com/google/protobuf/Java8Compatibility.java",
"src/main/java/com/google/protobuf/JavaType.java",
"src/main/java/com/google/protobuf/LazyField.java",
"src/main/java/com/google/protobuf/LazyFieldLite.java",
diff --git a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
index a01a6c1..09c5d53 100644
--- a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
+++ b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
@@ -187,7 +187,7 @@
@Override
public AllocatedBuffer position(int position) {
- buffer.position(position);
+ Java8Compatibility.position(buffer, position);
return this;
}
diff --git a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
index 94259ec..3e0721b 100644
--- a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
+++ b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java
@@ -2014,8 +2014,8 @@
buffers.addFirst(allocatedBuffer);
buffer = nioBuffer;
- buffer.limit(buffer.capacity());
- buffer.position(0);
+ Java8Compatibility.limit(buffer, buffer.capacity());
+ Java8Compatibility.position(buffer, 0);
// Set byte order to little endian for fast writing of fixed 32/64.
buffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -2041,7 +2041,7 @@
if (buffer != null) {
totalDoneBytes += bytesWrittenToCurrentBuffer();
// Update the indices on the netty buffer.
- buffer.position(pos + 1);
+ Java8Compatibility.position(buffer, pos + 1);
buffer = null;
pos = 0;
limitMinusOne = 0;
@@ -2467,7 +2467,7 @@
}
pos -= length;
- buffer.position(pos + 1);
+ Java8Compatibility.position(buffer, pos + 1);
buffer.put(value, offset, length);
}
@@ -2486,7 +2486,7 @@
}
pos -= length;
- buffer.position(pos + 1);
+ Java8Compatibility.position(buffer, pos + 1);
buffer.put(value, offset, length);
}
@@ -2498,7 +2498,7 @@
}
pos -= length;
- buffer.position(pos + 1);
+ Java8Compatibility.position(buffer, pos + 1);
buffer.put(value);
}
@@ -2518,7 +2518,7 @@
}
pos -= length;
- buffer.position(pos + 1);
+ Java8Compatibility.position(buffer, pos + 1);
buffer.put(value);
}
@@ -2568,8 +2568,8 @@
buffers.addFirst(allocatedBuffer);
buffer = nioBuffer;
- buffer.limit(buffer.capacity());
- buffer.position(0);
+ Java8Compatibility.limit(buffer, buffer.capacity());
+ Java8Compatibility.position(buffer, 0);
bufferOffset = UnsafeUtil.addressOffset(buffer);
limitMinusOne = bufferOffset + (buffer.limit() - 1);
@@ -2594,7 +2594,7 @@
if (buffer != null) {
totalDoneBytes += bytesWrittenToCurrentBuffer();
// Update the indices on the netty buffer.
- buffer.position(bufferPos() + 1);
+ Java8Compatibility.position(buffer, bufferPos() + 1);
buffer = null;
pos = 0;
limitMinusOne = 0;
@@ -3006,7 +3006,7 @@
}
pos -= length;
- buffer.position(bufferPos() + 1);
+ Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value, offset, length);
}
@@ -3025,7 +3025,7 @@
}
pos -= length;
- buffer.position(bufferPos() + 1);
+ Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value, offset, length);
}
@@ -3037,7 +3037,7 @@
}
pos -= length;
- buffer.position(bufferPos() + 1);
+ Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value);
}
@@ -3057,7 +3057,7 @@
}
pos -= length;
- buffer.position(bufferPos() + 1);
+ Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value);
}
diff --git a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
index 2cb3ada..3970b0e 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
@@ -107,7 +107,7 @@
}
} finally {
// Restore the initial position.
- buffer.position(initialPos);
+ Java8Compatibility.position(buffer, initialPos);
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 12f2097..9ec3908 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -1262,7 +1262,7 @@
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@@ -1543,7 +1543,7 @@
@Override
public void flush() {
// Update the position on the buffer.
- byteBuffer.position(initialPosition + getTotalBytesWritten());
+ Java8Compatibility.position(byteBuffer, initialPosition + getTotalBytesWritten());
}
}
@@ -1705,7 +1705,7 @@
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@@ -1815,18 +1815,18 @@
// Save the current position and increment past the length field. We'll come back
// and write the length field after the encoding is complete.
final int startOfBytes = buffer.position() + minLengthVarIntSize;
- buffer.position(startOfBytes);
+ Java8Compatibility.position(buffer, startOfBytes);
// Encode the string.
encode(value);
// Now go back to the beginning and write the length.
int endOfBytes = buffer.position();
- buffer.position(startPos);
+ Java8Compatibility.position(buffer, startPos);
writeUInt32NoTag(endOfBytes - startOfBytes);
// Reposition the buffer past the written data.
- buffer.position(endOfBytes);
+ Java8Compatibility.position(buffer, endOfBytes);
} else {
final int length = Utf8.encodedLength(value);
writeUInt32NoTag(length);
@@ -1834,7 +1834,7 @@
}
} catch (UnpairedSurrogateException e) {
// Roll back the change and convert to an IOException.
- buffer.position(startPos);
+ Java8Compatibility.position(buffer, startPos);
// TODO(nathanmittler): We should throw an IOException here instead.
inefficientWriteStringNoTag(value, e);
@@ -1847,7 +1847,7 @@
@Override
public void flush() {
// Update the position of the original buffer.
- originalBuffer.position(buffer.position());
+ Java8Compatibility.position(originalBuffer, buffer.position());
}
@Override
@@ -2035,7 +2035,7 @@
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@@ -2171,7 +2171,7 @@
// Save the current position and increment past the length field. We'll come back
// and write the length field after the encoding is complete.
int stringStart = bufferPos(position) + minLengthVarIntSize;
- buffer.position(stringStart);
+ Java8Compatibility.position(buffer, stringStart);
// Encode the string.
Utf8.encodeUtf8(value, buffer);
@@ -2208,7 +2208,7 @@
@Override
public void flush() {
// Update the position of the original buffer.
- originalBuffer.position(bufferPos(position));
+ Java8Compatibility.position(originalBuffer, bufferPos(position));
}
@Override
@@ -2222,7 +2222,7 @@
}
private void repositionBuffer(long pos) {
- buffer.position(bufferPos(pos));
+ Java8Compatibility.position(buffer, bufferPos(pos));
}
private int bufferPos(long pos) {
@@ -2499,7 +2499,7 @@
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@@ -2813,7 +2813,7 @@
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index 07e8dd1..1676a26 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -308,7 +308,11 @@
}
// ByteBuffer.equals() will only compare the remaining bytes, but we want to
// compare all the content.
- return a.duplicate().clear().equals(b.duplicate().clear());
+ ByteBuffer aDuplicate = a.duplicate();
+ Java8Compatibility.clear(aDuplicate);
+ ByteBuffer bDuplicate = b.duplicate();
+ Java8Compatibility.clear(bDuplicate);
+ return aDuplicate.equals(bDuplicate);
}
/** Helper method for implementing {@link Message#equals(Object)} for bytes field. */
@@ -348,7 +352,7 @@
bytes.capacity() > DEFAULT_BUFFER_SIZE ? DEFAULT_BUFFER_SIZE : bytes.capacity();
final byte[] buffer = new byte[bufferSize];
final ByteBuffer duplicated = bytes.duplicate();
- duplicated.clear();
+ Java8Compatibility.clear(duplicated);
int h = bytes.capacity();
while (duplicated.remaining() > 0) {
final int length =
diff --git a/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
index 713e806..1e571cf 100644
--- a/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
@@ -140,9 +140,9 @@
updateCurrentByteBufferPos(length);
} else {
int prevPos = currentByteBuffer.position();
- currentByteBuffer.position(currentByteBufferPos);
+ Java8Compatibility.position(currentByteBuffer, currentByteBufferPos);
currentByteBuffer.get(output, offset, length);
- currentByteBuffer.position(prevPos);
+ Java8Compatibility.position(currentByteBuffer, prevPos);
updateCurrentByteBufferPos(length);
}
return length;
diff --git a/java/core/src/main/java/com/google/protobuf/Java8Compatibility.java b/java/core/src/main/java/com/google/protobuf/Java8Compatibility.java
new file mode 100644
index 0000000..ef181c2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/Java8Compatibility.java
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.nio.Buffer;
+
+/**
+ * Wrappers around {@link Buffer} methods that are covariantly overridden in Java 9+. See
+ * https://github.com/protocolbuffers/protobuf/issues/11393
+ *
+ * <p>TODO(b/270454719) remove when Java 8 support is no longer needed.
+ */
+final class Java8Compatibility {
+ static void clear(Buffer b) {
+ b.clear();
+ }
+
+ static void flip(Buffer b) {
+ b.flip();
+ }
+
+ static void limit(Buffer b, int limit) {
+ b.limit(limit);
+ }
+
+ static void mark(Buffer b) {
+ b.mark();
+ }
+
+ static void position(Buffer b, int position) {
+ b.position(position);
+ }
+
+ static void reset(Buffer b) {
+ b.reset();
+ }
+
+ private Java8Compatibility() {}
+}
diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
index 76220cc..35ca407 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
@@ -5508,6 +5508,12 @@
getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
}
break;
+ case 60: // ONEOF_MESSAGE
+ case 68: // ONEOF_GROUP
+ if (isOneofPresent(message, numberAt(pos), pos)) {
+ getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
+ }
+ break;
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
index 1e594ff..f625eda 100644
--- a/java/core/src/main/java/com/google/protobuf/NioByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -37,7 +37,6 @@
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.OutputStream;
-import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.InvalidMarkException;
@@ -110,7 +109,7 @@
protected void copyToInternal(
byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
ByteBuffer slice = buffer.slice();
- ((Buffer) slice).position(sourceOffset);
+ Java8Compatibility.position(slice, sourceOffset);
slice.get(target, targetOffset, numberToCopy);
}
@@ -224,7 +223,7 @@
@Override
public void mark(int readlimit) {
- buf.mark();
+ Java8Compatibility.mark(buf);
}
@Override
@@ -235,7 +234,7 @@
@Override
public void reset() throws IOException {
try {
- buf.reset();
+ Java8Compatibility.reset(buf);
} catch (InvalidMarkException e) {
throw new IOException(e);
}
@@ -286,8 +285,8 @@
}
ByteBuffer slice = buffer.slice();
- ((Buffer) slice).position(beginIndex - buffer.position());
- ((Buffer) slice).limit(endIndex - buffer.position());
+ Java8Compatibility.position(slice, beginIndex - buffer.position());
+ Java8Compatibility.limit(slice, endIndex - buffer.position());
return slice;
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index b350524..06db1c5 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -1684,7 +1684,7 @@
if (n == -1) {
break;
}
- buffer.flip();
+ Java8Compatibility.flip(buffer);
text.append(buffer, 0, n);
}
return text;
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 7c9133e..c59a050 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -769,7 +769,7 @@
if (out.hasArray()) {
final int offset = out.arrayOffset();
int endIndex = Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
- out.position(endIndex - offset);
+ Java8Compatibility.position(out, endIndex - offset);
} else if (out.isDirect()) {
encodeUtf8Direct(in, out);
} else {
@@ -800,7 +800,7 @@
}
if (inIx == inLength) {
// Successfully encoded the entire string.
- out.position(outIx + inIx);
+ Java8Compatibility.position(out, outIx + inIx);
return;
}
@@ -843,7 +843,7 @@
}
// Successfully encoded the entire string.
- out.position(outIx);
+ Java8Compatibility.position(out, outIx);
} catch (IndexOutOfBoundsException e) {
// TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
@@ -1606,7 +1606,7 @@
}
if (inIx == inLimit) {
// We're done, it was ASCII encoded.
- out.position((int) (outIx - address));
+ Java8Compatibility.position(out, (int) (outIx - address));
return;
}
@@ -1646,7 +1646,7 @@
}
// All bytes have been encoded.
- out.position((int) (outIx - address));
+ Java8Compatibility.position(out, (int) (outIx - address));
}
/**
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index e4edb4d..a29f5e1 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -123,6 +123,7 @@
<include>Internal.java</include>
<include>InvalidProtocolBufferException.java</include>
<include>IterableByteBufferInputStream.java</include>
+ <include>Java8Compatibility.java</include>
<include>JavaType.java</include>
<include>LazyField.java</include>
<include>LazyFieldLite.java</include>
diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
index 6535a1b..23654f8 100644
--- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
@@ -189,6 +189,18 @@
}
@Test
+ public void testParsedOneofSubMessageIsImmutable() throws InvalidProtocolBufferException {
+ TestAllTypesLite message =
+ TestAllTypesLite.parseFrom(
+ TestAllTypesLite.newBuilder()
+ .setOneofNestedMessage(NestedMessage.newBuilder().addDd(1234).build())
+ .build()
+ .toByteArray());
+ IntArrayList subList = (IntArrayList) message.getOneofNestedMessage().getDdList();
+ assertThat(subList.isModifiable()).isFalse();
+ }
+
+ @Test
public void testMemoization() throws Exception {
GeneratedMessageLite<?, ?> message = TestUtilLite.getAllLiteExtensionsSet();
@@ -2346,8 +2358,7 @@
Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
Foo fooWithValueAndExtension =
- fooWithOnlyValue
- .toBuilder()
+ fooWithOnlyValue.toBuilder()
.setValue(1)
.setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
.build();
@@ -2363,8 +2374,7 @@
Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
Foo fooWithValueAndExtension =
- fooWithOnlyValue
- .toBuilder()
+ fooWithOnlyValue.toBuilder()
.setValue(1)
.setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
.build();
diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto
index 92282a6..9ee290b 100644
--- a/src/google/protobuf/unittest_lite.proto
+++ b/src/google/protobuf/unittest_lite.proto
@@ -47,6 +47,7 @@
message NestedMessage {
optional int32 bb = 1;
optional int64 cc = 2;
+ repeated int32 dd = 3 [packed = true];
}
message NestedMessage2 {