diff --git a/Makefile.am b/Makefile.am index 681cd8c21c..264842f1c3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -343,6 +343,7 @@ java_EXTRA_DIST= 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.bazel b/java/core/BUILD.bazel index cfd53f42e2..9a0a803621 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 94b09944d1..75de57a32e 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 @@ abstract class AllocatedBuffer { @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 cf394e3371..e3854bb1e5 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 @@ abstract class BinaryWriter extends ByteOutput implements Writer { 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 @@ abstract class BinaryWriter extends ByteOutput implements Writer { 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 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value, offset, length); } @@ -2494,7 +2494,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value, offset, length); } @@ -2506,7 +2506,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value); } @@ -2526,7 +2526,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(pos + 1); + Java8Compatibility.position(buffer, pos + 1); buffer.put(value); } @@ -2576,8 +2576,8 @@ abstract class BinaryWriter extends ByteOutput implements Writer { 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 @@ abstract class BinaryWriter extends ByteOutput implements Writer { 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 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value, offset, length); } @@ -3035,7 +3035,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value, offset, length); } @@ -3047,7 +3047,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } pos -= length; - buffer.position(bufferPos() + 1); + Java8Compatibility.position(buffer, bufferPos() + 1); buffer.put(value); } @@ -3067,7 +3067,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer { } 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 2cb3ada67f..3970b0ea5b 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 @@ final class ByteBufferWriter { } } 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 4ad83099d7..44dd4dc20e 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 abstract class CodedOutputStream extends ByteOutput { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -1522,7 +1522,7 @@ public abstract class CodedOutputStream extends ByteOutput { @Override public void flush() { // Update the position on the buffer. - byteBuffer.position(initialPosition + getTotalBytesWritten()); + Java8Compatibility.position(byteBuffer, initialPosition + getTotalBytesWritten()); } } @@ -1684,7 +1684,7 @@ public abstract class CodedOutputStream extends ByteOutput { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -1794,18 +1794,18 @@ public abstract class CodedOutputStream extends ByteOutput { // 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 abstract class CodedOutputStream extends ByteOutput { } } 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 abstract class CodedOutputStream extends ByteOutput { @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 abstract class CodedOutputStream extends ByteOutput { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -2150,7 +2150,7 @@ public abstract class CodedOutputStream extends ByteOutput { // 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 abstract class CodedOutputStream extends ByteOutput { @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 abstract class CodedOutputStream extends ByteOutput { } private void repositionBuffer(long pos) { - buffer.position(bufferPos(pos)); + Java8Compatibility.position(buffer, bufferPos(pos)); } private int bufferPos(long pos) { @@ -2478,7 +2478,7 @@ public abstract class CodedOutputStream extends ByteOutput { write(value.array(), value.arrayOffset(), value.capacity()); } else { ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); + Java8Compatibility.clear(duplicated); write(duplicated); } } @@ -2792,7 +2792,7 @@ public abstract class CodedOutputStream extends ByteOutput { 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 b6bbcb160d..6e4490e254 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 final class Internal { } // 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 final class Internal { 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 713e806469..1e571cfbbb 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 @@ class IterableByteBufferInputStream extends InputStream { 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 0000000000..ef181c2ae5 --- /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/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
index 084d687d1a..ae5dddc53b 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
@@ -5510,6 +5510,12 @@ final class MessageSchema