From 0710c645bea5ccf572ecf96879bd8bf9a657c07e Mon Sep 17 00:00:00 2001 From: funkye Date: Mon, 27 Nov 2023 13:36:48 +0800 Subject: [PATCH] bugfix: support jdk9+ compile code (#4410) --- changes/en-us/develop.md | 2 + changes/zh-cn/develop.md | 2 + .../io/seata/common/util/BufferUtils.java | 93 +++++++++++++++++++ .../io/seata/integration/http/HttpTest.java | 17 ++-- .../undo/parser/ProtostuffUndoLogParser.java | 10 +- .../protobuf/ProtobufSerializer.java | 12 ++- .../serializer/seata/SeataSerializer.java | 7 +- .../seata/server/session/BranchSession.java | 5 +- .../seata/server/session/GlobalSession.java | 6 +- .../store/FileTransactionStoreManager.java | 11 ++- .../file/FileTransactionStoreManagerTest.java | 15 +-- 11 files changed, 145 insertions(+), 35 deletions(-) create mode 100644 common/src/main/java/io/seata/common/util/BufferUtils.java diff --git a/changes/en-us/develop.md b/changes/en-us/develop.md index 1b2f57f1de7..4b464d99b98 100644 --- a/changes/en-us/develop.md +++ b/changes/en-us/develop.md @@ -10,6 +10,7 @@ Add changes here for all PR submitted to the develop branch. - [[#5991](https://github.com/seata/seata/pull/5991)] fix the issue that the Lua script is not synchronized when the redis sentinel master node is down - [[#6025](https://github.com/seata/seata/pull/6025)] fix the white screen after click the "View Global Lock" button on the transaction info page in the console - [[#6026](https://github.com/seata/seata/pull/6026)] fix incorrect metric report +- [[#4410](https://github.com/seata/seata/pull/4410)] support jdk9+ compile code ### optimize: - [[#6044](https://github.com/seata/seata/pull/6044)] optimize derivative product check base on mysql @@ -27,6 +28,7 @@ Thanks to these contributors for their code commits. Please report an unintended - [jsbxyyx](https://github.com/jsbxyyx) - [liuqiufeng](https://github.com/liuqiufeng) - [ptyin](https://github.com/ptyin) +- [funky-eyes](https://github.com/funky-eyes) Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/develop.md b/changes/zh-cn/develop.md index 2eb0a37fbac..90b7dab8518 100644 --- a/changes/zh-cn/develop.md +++ b/changes/zh-cn/develop.md @@ -10,6 +10,7 @@ - [[#5991](https://github.com/seata/seata/pull/5991)] 修复redis sentinel master node 宕机时,lua脚本未同步的问题 - [[#6025](https://github.com/seata/seata/pull/6025)] 修复控制台点击事务信息页面中的"查看全局锁"按钮之后白屏的问题 - [[#6026](https://github.com/seata/seata/pull/6026)] 修复异常的打点 +- [[#4410](https://github.com/seata/seata/pull/4410)] 修复jdk9+版本编译后,引入后ByteBuffer#flip NoSuchMethodError的问题 ### optimize: - [[#6044](https://github.com/seata/seata/pull/6044)] 优化MySQL衍生数据库判断逻辑 @@ -27,5 +28,6 @@ - [jsbxyyx](https://github.com/jsbxyyx) - [liuqiufeng](https://github.com/liuqiufeng) - [ptyin](https://github.com/ptyin) +- [funky-eyes](https://github.com/funky-eyes) 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/common/src/main/java/io/seata/common/util/BufferUtils.java b/common/src/main/java/io/seata/common/util/BufferUtils.java new file mode 100644 index 00000000000..5b69ecf7a0d --- /dev/null +++ b/common/src/main/java/io/seata/common/util/BufferUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.seata.common.util; + +import java.nio.Buffer; + +/** + * Explicit cast to {@link Buffer} parent buffer type. It resolves issues with covariant return types in Java 9+ for + * {@link java.nio.ByteBuffer} and {@link java.nio.CharBuffer}. Explicit casting resolves the NoSuchMethodErrors (e.g + * java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip(I)Ljava/nio/ByteBuffer) when the project is compiled with + * newer Java version and run on Java 8. + *

+ * Java 8 doesn't provide override the + * following Buffer methods in subclasses: + * + *

+ * Buffer clear()
+ * Buffer flip()
+ * Buffer limit(int newLimit)
+ * Buffer mark()
+ * Buffer position(int newPosition)
+ * Buffer reset()
+ * Buffer rewind()
+ * 
+ * + * Java 9 introduces the overrides in + * child classes (e.g the ByteBuffer), but the return type is the specialized one and not the abstract {@link Buffer}. + * So the code compiled with newer Java is not working on Java 8 unless a workaround with explicit casting is used. + * + * @author funkye + */ +public class BufferUtils { + + /** + * @param buffer byteBuffer + */ + public static void flip(Buffer buffer) { + buffer.flip(); + } + + /** + * @param buffer byteBuffer + */ + public static void clear(Buffer buffer) { + buffer.clear(); + } + + /** + * @param buffer byteBuffer + */ + public static void limit(Buffer buffer, int newLimit) { + buffer.limit(newLimit); + } + + /** + * @param buffer byteBuffer + */ + public static void mark(Buffer buffer) { + buffer.mark(); + } + + /** + * @param buffer byteBuffer + */ + public static void position(Buffer buffer, int newPosition) { + buffer.position(newPosition); + } + + /** + * @param buffer byteBuffer + */ + public static void rewind(Buffer buffer) { + buffer.rewind(); + } + + /** + * @param buffer byteBuffer + */ + public static void reset(Buffer buffer) { + buffer.reset(); + } + +} diff --git a/integration/http/src/test/java/io/seata/integration/http/HttpTest.java b/integration/http/src/test/java/io/seata/integration/http/HttpTest.java index 8b20b5269aa..5ff8cc23f8c 100644 --- a/integration/http/src/test/java/io/seata/integration/http/HttpTest.java +++ b/integration/http/src/test/java/io/seata/integration/http/HttpTest.java @@ -15,13 +15,6 @@ */ package io.seata.integration.http; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import io.seata.core.context.RootContext; -import org.apache.http.HttpResponse; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -31,6 +24,14 @@ import java.nio.channels.WritableByteChannel; import java.util.HashMap; import java.util.Map; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.seata.common.util.BufferUtils; +import io.seata.core.context.RootContext; +import org.apache.http.HttpResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + import static io.seata.integration.http.AbstractHttpExecutor.convertParamOfBean; import static io.seata.integration.http.AbstractHttpExecutor.convertParamOfJsonString; @@ -205,7 +206,7 @@ public static String readStreamAsStr(InputStream is) throws IOException { ByteBuffer bb = ByteBuffer.allocate(4096); while (src.read(bb) != -1) { - bb.flip(); + BufferUtils.flip(bb); dest.write(bb); bb.clear(); } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/parser/ProtostuffUndoLogParser.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/parser/ProtostuffUndoLogParser.java index 6df392f6711..608722cb1c0 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/parser/ProtostuffUndoLogParser.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/parser/ProtostuffUndoLogParser.java @@ -20,6 +20,9 @@ import java.sql.Timestamp; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.protostuff.Input; import io.protostuff.LinkedBuffer; import io.protostuff.Output; @@ -36,11 +39,10 @@ import io.seata.common.loader.EnhancedServiceNotFoundException; import io.seata.common.loader.LoadLevel; import io.seata.common.util.CollectionUtils; +import io.seata.common.util.BufferUtils; import io.seata.rm.datasource.undo.BranchUndoLog; import io.seata.rm.datasource.undo.UndoLogParser; import io.seata.rm.datasource.undo.parser.spi.ProtostuffDelegate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The type protostuff based undo log parser. @@ -132,7 +134,7 @@ public java.sql.Timestamp readFrom(Input input) throws IOException { ByteBuffer buffer = input.readByteBuffer(); long time = buffer.getLong(); int nanos = buffer.getInt(); - buffer.flip(); + BufferUtils.flip(buffer); java.sql.Timestamp timestamp = new Timestamp(time); timestamp.setNanos(nanos); return timestamp; @@ -143,7 +145,7 @@ public void writeTo(Output output, int number, java.sql.Timestamp value, boolean ByteBuffer buffer = ByteBuffer.allocate(12); buffer.putLong(value.getTime()); buffer.putInt(value.getNanos()); - buffer.flip(); + BufferUtils.flip(buffer); output.writeBytes(number, buffer, repeated); } diff --git a/serializer/seata-serializer-protobuf/src/main/java/io/seata/serializer/protobuf/ProtobufSerializer.java b/serializer/seata-serializer-protobuf/src/main/java/io/seata/serializer/protobuf/ProtobufSerializer.java index 378245cb1e8..a81ce621c92 100644 --- a/serializer/seata-serializer-protobuf/src/main/java/io/seata/serializer/protobuf/ProtobufSerializer.java +++ b/serializer/seata-serializer-protobuf/src/main/java/io/seata/serializer/protobuf/ProtobufSerializer.java @@ -15,16 +15,18 @@ */ package io.seata.serializer.protobuf; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + import com.google.protobuf.GeneratedMessageV3; + import io.seata.common.loader.LoadLevel; +import io.seata.common.util.BufferUtils; import io.seata.core.serializer.Serializer; import io.seata.serializer.protobuf.convertor.PbConvertor; import io.seata.serializer.protobuf.manager.ProtobufConvertManager; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - /** * The type Protobuf codec. * @@ -53,7 +55,7 @@ public byte[] serialize(T t) { byteBuffer.putInt(nameBytes.length); byteBuffer.put(nameBytes); byteBuffer.put(body); - byteBuffer.flip(); + BufferUtils.flip(byteBuffer); byte[] content = new byte[byteBuffer.limit()]; byteBuffer.get(content); return content; diff --git a/serializer/seata-serializer-seata/src/main/java/io/seata/serializer/seata/SeataSerializer.java b/serializer/seata-serializer-seata/src/main/java/io/seata/serializer/seata/SeataSerializer.java index c1a96e611a4..b3d81d6c163 100644 --- a/serializer/seata-serializer-seata/src/main/java/io/seata/serializer/seata/SeataSerializer.java +++ b/serializer/seata-serializer-seata/src/main/java/io/seata/serializer/seata/SeataSerializer.java @@ -15,14 +15,15 @@ */ package io.seata.serializer.seata; +import java.nio.ByteBuffer; + import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.seata.common.loader.LoadLevel; +import io.seata.common.util.BufferUtils; import io.seata.core.protocol.AbstractMessage; import io.seata.core.serializer.Serializer; -import java.nio.ByteBuffer; - /** * The Seata codec. * @@ -53,7 +54,7 @@ public byte[] serialize(T t) { byteBuffer.putShort(typecode); byteBuffer.put(body); - byteBuffer.flip(); + BufferUtils.flip(byteBuffer); byte[] content = new byte[byteBuffer.limit()]; byteBuffer.get(content); return content; diff --git a/server/src/main/java/io/seata/server/session/BranchSession.java b/server/src/main/java/io/seata/server/session/BranchSession.java index af0bcf63295..b6c1e139617 100644 --- a/server/src/main/java/io/seata/server/session/BranchSession.java +++ b/server/src/main/java/io/seata/server/session/BranchSession.java @@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import io.seata.common.util.CompressUtil; +import io.seata.common.util.BufferUtils; import io.seata.core.exception.TransactionException; import io.seata.core.model.BranchStatus; import io.seata.core.model.BranchType; @@ -350,7 +351,7 @@ public byte[] encode() { ByteBuffer byteBuffer = byteBufferThreadLocal.get(); //recycle - byteBuffer.clear(); + BufferUtils.clear(byteBuffer); byteBuffer.putLong(transactionId); byteBuffer.putLong(branchId); @@ -394,7 +395,7 @@ public byte[] encode() { byteBuffer.put((byte)status.getCode()); byteBuffer.put((byte)lockStatus.getCode()); - byteBuffer.flip(); + BufferUtils.flip(byteBuffer); byte[] result = new byte[byteBuffer.limit()]; byteBuffer.get(result); return result; diff --git a/server/src/main/java/io/seata/server/session/GlobalSession.java b/server/src/main/java/io/seata/server/session/GlobalSession.java index 5ea1a9fa1db..29b71e80832 100644 --- a/server/src/main/java/io/seata/server/session/GlobalSession.java +++ b/server/src/main/java/io/seata/server/session/GlobalSession.java @@ -29,6 +29,7 @@ import io.seata.common.Constants; import io.seata.common.DefaultValues; import io.seata.common.XID; +import io.seata.common.util.BufferUtils; import io.seata.common.util.StringUtils; import io.seata.config.ConfigurationFactory; import io.seata.core.constants.ConfigurationKeys; @@ -46,6 +47,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import static io.seata.core.model.GlobalStatus.AsyncCommitting; import static io.seata.core.model.GlobalStatus.CommitRetrying; import static io.seata.core.model.GlobalStatus.Committing; @@ -584,7 +586,7 @@ public byte[] encode() { } ByteBuffer byteBuffer = byteBufferThreadLocal.get(); //recycle - byteBuffer.clear(); + BufferUtils.clear(byteBuffer); byteBuffer.putLong(transactionId); byteBuffer.putInt(timeout); @@ -621,7 +623,7 @@ public byte[] encode() { byteBuffer.putLong(beginTime); byteBuffer.put((byte)status.getCode()); - byteBuffer.flip(); + BufferUtils.flip(byteBuffer); byte[] result = new byte[byteBuffer.limit()]; byteBuffer.get(result); return result; diff --git a/server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java b/server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java index a52fce9b054..3beb2cd7203 100644 --- a/server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java +++ b/server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java @@ -31,10 +31,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; - import io.seata.common.exception.StoreException; import io.seata.common.thread.NamedThreadFactory; import io.seata.common.util.CollectionUtils; +import io.seata.common.util.BufferUtils; import io.seata.server.session.BranchSession; import io.seata.server.session.GlobalSession; import io.seata.server.session.SessionCondition; @@ -50,6 +50,7 @@ import org.slf4j.LoggerFactory; import org.slf4j.MDC; + import static io.seata.core.context.RootContext.MDC_KEY_BRANCH_ID; /** @@ -263,11 +264,11 @@ private boolean writeDataFrame(byte[] data) { } private boolean flushWriteBuffer(ByteBuffer writeBuffer) { - writeBuffer.flip(); + BufferUtils.flip(writeBuffer); if (!writeDataFileByBuffer(writeBuffer)) { return false; } - writeBuffer.clear(); + BufferUtils.clear(writeBuffer); return true; } @@ -397,12 +398,12 @@ private List parseDataFile(File file, int readSize, long ByteBuffer buffSize = ByteBuffer.allocate(MARK_SIZE); while (fileChannel.position() < size) { try { - buffSize.clear(); + BufferUtils.clear(buffSize); int avilReadSize = fileChannel.read(buffSize); if (avilReadSize != MARK_SIZE) { break; } - buffSize.flip(); + BufferUtils.flip(buffSize); int bodySize = buffSize.getInt(); byte[] byBody = new byte[bodySize]; ByteBuffer buffBody = ByteBuffer.wrap(byBody); diff --git a/server/src/test/java/io/seata/server/store/file/FileTransactionStoreManagerTest.java b/server/src/test/java/io/seata/server/store/file/FileTransactionStoreManagerTest.java index 809832ec60a..8f572cd7481 100644 --- a/server/src/test/java/io/seata/server/store/file/FileTransactionStoreManagerTest.java +++ b/server/src/test/java/io/seata/server/store/file/FileTransactionStoreManagerTest.java @@ -21,6 +21,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; + +import org.assertj.core.util.Files; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.context.SpringBootTest; + +import io.seata.common.util.BufferUtils; import io.seata.server.UUIDGenerator; import io.seata.server.session.BranchSession; import io.seata.server.session.GlobalSession; @@ -30,11 +38,6 @@ import io.seata.server.storage.file.store.FileTransactionStoreManager; import io.seata.server.store.StoreConfig; import io.seata.server.store.TransactionStoreManager; -import org.assertj.core.util.Files; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.boot.test.context.SpringBootTest; /** * @author ggndnn @@ -166,7 +169,7 @@ private byte[] createBigBranchSessionData(GlobalSession global, byte c) { byteBuffer.put((byte) 0); byteBuffer.put((byte) 0); byteBuffer.put((byte) 0); - byteBuffer.flip(); + BufferUtils.flip(byteBuffer); byte[] bytes = new byte[byteBuffer.limit()]; byteBuffer.get(bytes); return bytes;