From d40aadf823cf7e1e62b65561656f689da8969463 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Thu, 23 Feb 2023 09:29:42 -0800 Subject: [PATCH] Add casts to make protobuf compatible with Java 1.8 runtime. Fix for: https://github.com/protocolbuffers/protobuf/issues/11393 PiperOrigin-RevId: 511807920 --- java/core/BUILD.bazel | 1 + .../com/google/protobuf/AllocatedBuffer.java | 2 +- .../com/google/protobuf/BinaryWriter.java | 28 ++++---- .../com/google/protobuf/ByteBufferWriter.java | 2 +- .../google/protobuf/CodedOutputStream.java | 28 ++++---- .../java/com/google/protobuf/Internal.java | 8 ++- .../IterableByteBufferInputStream.java | 4 +- .../google/protobuf/Java8Compatibility.java | 67 +++++++++++++++++++ .../com/google/protobuf/NioByteString.java | 11 ++- .../java/com/google/protobuf/TextFormat.java | 2 +- .../main/java/com/google/protobuf/Utf8.java | 10 +-- java/lite/pom.xml | 1 + 12 files changed, 118 insertions(+), 46 deletions(-) create mode 100644 java/core/src/main/java/com/google/protobuf/Java8Compatibility.java diff --git a/java/core/BUILD.bazel b/java/core/BUILD.bazel index 6113169c6c7a..c0e52a4ff4bc 100644 --- a/java/core/BUILD.bazel +++ b/java/core/BUILD.bazel @@ -49,6 +49,7 @@ LITE_SRCS = [ "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 94b09944d1a8..75de57a32ed0 100644 --- a/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java +++ b/java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java @@ -189,7 +189,7 @@ public int position() { @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 66cf51d24c4a..7eb7886312ce 100644 --- a/java/core/src/main/java/com/google/protobuf/BinaryWriter.java +++ b/java/core/src/main/java/com/google/protobuf/BinaryWriter.java @@ -2019,8 +2019,8 @@ private void nextBuffer(AllocatedBuffer allocatedBuffer) { 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); @@ -2046,7 +2046,7 @@ void finishCurrentBuffer() { 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; @@ -2475,7 +2475,7 @@ public void write(byte[] value, int offset, int length) { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value, offset, length); } @@ -2494,7 +2494,7 @@ public void writeLazy(byte[] value, int offset, int length) { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value, offset, length); } @@ -2506,7 +2506,7 @@ public void write(ByteBuffer value) { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value); } @@ -2526,7 +2526,7 @@ public void writeLazy(ByteBuffer value) { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value); } @@ -2576,8 +2576,8 @@ private void nextBuffer(AllocatedBuffer allocatedBuffer) { 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); @@ -2602,7 +2602,7 @@ void finishCurrentBuffer() { 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; @@ -3016,7 +3016,7 @@ public void write(byte[] value, int offset, int length) { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value, offset, length); } @@ -3035,7 +3035,7 @@ public void writeLazy(byte[] value, int offset, int length) { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value, offset, length); } @@ -3047,7 +3047,7 @@ public void write(ByteBuffer value) { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value); } @@ -3067,7 +3067,7 @@ public void writeLazy(ByteBuffer value) { } 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 2cb3ada67fb6..3970b0ea5b85 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 @@ static void write(ByteBuffer buffer, OutputStream output) throws IOException { } } 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 4ad83099d769..44dd4dc20ebd 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -1271,7 +1271,7 @@ public final void writeRawBytes(final ByteBuffer value) throws IOException { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -1522,7 +1522,7 @@ private static final class HeapNioEncoder extends ArrayEncoder { @Override public void flush() { // Update the position on the buffer. - byteBuffer.position(initialPosition + getTotalBytesWritten()); + Java8Compatibility.position(byteBuffer, initialPosition + getTotalBytesWritten()); } } @@ -1684,7 +1684,7 @@ public void writeRawBytes(final ByteBuffer value) throws IOException { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -1794,18 +1794,18 @@ public void writeStringNoTag(String value) throws IOException { // 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); @@ -1813,7 +1813,7 @@ public void writeStringNoTag(String value) throws IOException { } } 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); @@ -1826,7 +1826,7 @@ public void writeStringNoTag(String value) throws IOException { @Override public void flush() { // Update the position of the original buffer. - originalBuffer.position(buffer.position()); + Java8Compatibility.position(originalBuffer, buffer.position()); } @Override @@ -2014,7 +2014,7 @@ public void writeRawBytes(ByteBuffer value) throws IOException { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -2150,7 +2150,7 @@ public void writeStringNoTag(String value) throws IOException { // 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); @@ -2187,7 +2187,7 @@ public void writeStringNoTag(String value) throws IOException { @Override public void flush() { // Update the position of the original buffer. - originalBuffer.position(bufferPos(position)); + Java8Compatibility.position(originalBuffer, bufferPos(position)); } @Override @@ -2201,7 +2201,7 @@ public int getTotalBytesWritten() { } private void repositionBuffer(long pos) { - buffer.position(bufferPos(pos)); + Java8Compatibility.position(buffer, bufferPos(pos)); } private int bufferPos(long pos) { @@ -2478,7 +2478,7 @@ public void writeRawBytes(final ByteBuffer value) throws IOException { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -2792,7 +2792,7 @@ public void writeRawBytes(final ByteBuffer value) throws IOException { 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 7a7270b8c3f1..127a16566edf 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -313,7 +313,11 @@ public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) { } // 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. */ @@ -353,7 +357,7 @@ public static int hashCodeByteBuffer(ByteBuffer bytes) { 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 713e80646931..1e571cfbbb54 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 @@ public int read(byte[] output, int offset, int length) throws IOException { 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 000000000000..ef181c2ae55b --- /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 + * + *

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/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java index 1e594ff878c5..f625edafb9ef 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 @@ public ByteString substring(int beginIndex, int endIndex) { 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 @@ public InputStream newInput() { @Override public void mark(int readlimit) { - buf.mark(); + Java8Compatibility.mark(buf); } @Override @@ -235,7 +234,7 @@ public boolean markSupported() { @Override public void reset() throws IOException { try { - buf.reset(); + Java8Compatibility.reset(buf); } catch (InvalidMarkException e) { throw new IOException(e); } @@ -286,8 +285,8 @@ private ByteBuffer slice(int beginIndex, int endIndex) { } 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 8c3ac5caf10b..9d28d06c9527 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -1710,7 +1710,7 @@ private static StringBuilder toStringBuilder(final Readable input) throws IOExce 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 c74497cd816a..7c6823d91ffa 100644 --- a/java/core/src/main/java/com/google/protobuf/Utf8.java +++ b/java/core/src/main/java/com/google/protobuf/Utf8.java @@ -770,7 +770,7 @@ final void encodeUtf8(CharSequence in, ByteBuffer out) { 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 { @@ -801,7 +801,7 @@ final void encodeUtf8Default(CharSequence in, ByteBuffer out) { } if (inIx == inLength) { // Successfully encoded the entire string. - out.position(outIx + inIx); + Java8Compatibility.position(out, outIx + inIx); return; } @@ -844,7 +844,7 @@ final void encodeUtf8Default(CharSequence in, ByteBuffer out) { } // Successfully encoded the entire string. - out.position(outIx); + Java8Compatibility.position(out, outIx); } catch (IndexOutOfBoundsException e) { // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead. @@ -1545,7 +1545,7 @@ void encodeUtf8Direct(CharSequence in, ByteBuffer out) { } if (inIx == inLimit) { // We're done, it was ASCII encoded. - out.position((int) (outIx - address)); + Java8Compatibility.position(out, (int) (outIx - address)); return; } @@ -1585,7 +1585,7 @@ void encodeUtf8Direct(CharSequence in, ByteBuffer out) { } // 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 af34943dabf7..b59c48a9eade 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -125,6 +125,7 @@ Internal.java InvalidProtocolBufferException.java IterableByteBufferInputStream.java + Java8Compatibility.java JavaType.java LazyField.java LazyFieldLite.java