diff --git a/all/pom.xml b/all/pom.xml index fefcbc8b4a5..014c12f294d 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -267,6 +267,11 @@ seata-serializer-fury ${project.version} + + org.apache.seata + seata-serializer-fory + ${project.version} + org.apache.seata seata-serializer-kryo diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 5613384abf9..509a3c253e1 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -135,6 +135,7 @@ Thanks to these contributors for their code commits. Please report an unintended - [LegendPei](https://github.com/LegendPei) - [lokidundun](https://github.com/lokidundun) - [jsbxyyx](https://github.com/jsbxyyx) +- [diguage](https://github.com/diguage) Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 5b716048807..7cb9409dcb8 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -132,6 +132,7 @@ - [LegendPei](https://github.com/LegendPei) - [lokidundun](https://github.com/lokidundun) - [jsbxyyx](https://github.com/jsbxyyx) +- [diguage](https://github.com/diguage) 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java b/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java index 3461b5cd168..8ce367cabde 100644 --- a/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java +++ b/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java @@ -33,6 +33,7 @@ import java.util.stream.Collectors; import static org.apache.seata.core.serializer.SerializerType.FASTJSON2; +import static org.apache.seata.core.serializer.SerializerType.FORY; import static org.apache.seata.core.serializer.SerializerType.FURY; import static org.apache.seata.core.serializer.SerializerType.HESSIAN; import static org.apache.seata.core.serializer.SerializerType.KRYO; @@ -48,7 +49,7 @@ public final class SerializerServiceLoader { private static final Configuration CONFIG = ConfigurationFactory.getInstance(); private static final SerializerType[] DEFAULT_SERIALIZER_TYPE = - new SerializerType[] {SEATA, PROTOBUF, KRYO, HESSIAN, FASTJSON2, FURY}; + new SerializerType[] {SEATA, PROTOBUF, KRYO, HESSIAN, FASTJSON2, FURY, FORY}; private static final Map SERIALIZER_MAP = new HashMap<>(); diff --git a/core/src/main/java/org/apache/seata/core/serializer/SerializerType.java b/core/src/main/java/org/apache/seata/core/serializer/SerializerType.java index 243cc119114..00697de4074 100644 --- a/core/src/main/java/org/apache/seata/core/serializer/SerializerType.java +++ b/core/src/main/java/org/apache/seata/core/serializer/SerializerType.java @@ -67,7 +67,14 @@ public enum SerializerType { /** * The fury. */ - FURY((byte) 86); + FURY((byte) 86), + + /** + * The fory. + *

+ * To maintain compatibility with FURY, the FURY code was reused. + */ + FORY((byte) 86); private final byte code; diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 78d720fe430..072e0cf3cf8 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -144,7 +144,8 @@ 2.4.0 - 0.8.0 + 0.10.3 + 0.12.3 @@ -900,6 +901,11 @@ fury-core ${fury.version} + + org.apache.fory + fory-core + ${fory.version} + commons-io commons-io diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml index 28da98f41e4..9672700b812 100644 --- a/rm-datasource/pom.xml +++ b/rm-datasource/pom.xml @@ -149,6 +149,12 @@ provided true + + org.apache.fory + fory-core + provided + true + cn.com.kingbase kingbase8 diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParser.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParser.java new file mode 100644 index 00000000000..a06bddd0c6e --- /dev/null +++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParser.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.rm.datasource.undo.parser; + +import org.apache.fory.Fory; +import org.apache.fory.ThreadLocalFory; +import org.apache.fory.ThreadSafeFory; +import org.apache.fory.config.CompatibleMode; +import org.apache.fory.config.Language; +import org.apache.seata.common.executor.Initialize; +import org.apache.seata.common.loader.LoadLevel; +import org.apache.seata.rm.datasource.undo.BranchUndoLog; +import org.apache.seata.rm.datasource.undo.UndoLogParser; + +@LoadLevel(name = ForyUndoLogParser.NAME) +public class ForyUndoLogParser implements UndoLogParser, Initialize { + public static final String NAME = "fory"; + + private static final ThreadSafeFory FORY = new ThreadLocalFory(classLoader -> Fory.builder() + .withLanguage(Language.JAVA) + // In JAVA mode, classes cannot be registered by tag, and the different registration order between the + // server and the client will cause deserialization failure + // In XLANG cross-language mode has problems with Java class serialization, such as enum classes + // [https://github.com/apache/fory/issues/1644]. + .requireClassRegistration(false) + // enable reference tracking for shared/circular reference. + .withRefTracking(true) + .withClassLoader(classLoader) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .build()); + + @Override + public void init() {} + + @Override + public String getName() { + return NAME; + } + + @Override + public byte[] getDefaultContent() { + return encode(new BranchUndoLog()); + } + + @Override + public byte[] encode(BranchUndoLog branchUndoLog) { + return FORY.serializeJavaObject(branchUndoLog); + } + + @Override + public BranchUndoLog decode(byte[] bytes) { + return FORY.deserializeJavaObject(bytes, BranchUndoLog.class); + } +} diff --git a/rm-datasource/src/main/resources/META-INF/services/org.apache.seata.rm.datasource.undo.UndoLogParser b/rm-datasource/src/main/resources/META-INF/services/org.apache.seata.rm.datasource.undo.UndoLogParser index 41596cc4c6a..d9a37d043eb 100644 --- a/rm-datasource/src/main/resources/META-INF/services/org.apache.seata.rm.datasource.undo.UndoLogParser +++ b/rm-datasource/src/main/resources/META-INF/services/org.apache.seata.rm.datasource.undo.UndoLogParser @@ -19,4 +19,5 @@ org.apache.seata.rm.datasource.undo.parser.JacksonUndoLogParser org.apache.seata.rm.datasource.undo.parser.ProtostuffUndoLogParser org.apache.seata.rm.datasource.undo.parser.KryoUndoLogParser org.apache.seata.rm.datasource.undo.parser.Fastjson2UndoLogParser -org.apache.seata.rm.datasource.undo.parser.FuryUndoLogParser \ No newline at end of file +org.apache.seata.rm.datasource.undo.parser.FuryUndoLogParser +org.apache.seata.rm.datasource.undo.parser.ForyUndoLogParser \ No newline at end of file diff --git a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParserTest.java b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParserTest.java new file mode 100644 index 00000000000..f80f343e916 --- /dev/null +++ b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/undo/parser/ForyUndoLogParserTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.rm.datasource.undo.parser; + +import org.apache.seata.common.loader.EnhancedServiceLoader; +import org.apache.seata.rm.datasource.undo.BaseUndoLogParserTest; +import org.apache.seata.rm.datasource.undo.UndoLogParser; + +public class ForyUndoLogParserTest extends BaseUndoLogParserTest { + + ForyUndoLogParser parser = + (ForyUndoLogParser) EnhancedServiceLoader.load(UndoLogParser.class, ForyUndoLogParser.NAME); + + @Override + public UndoLogParser getParser() { + return parser; + } + + @Override + public void testTimestampEncodeAndDecode() {} +} diff --git a/serializer/pom.xml b/serializer/pom.xml index e4435a724d1..e0aa5e5b9df 100644 --- a/serializer/pom.xml +++ b/serializer/pom.xml @@ -39,6 +39,7 @@ seata-serializer-hessian seata-serializer-fastjson2 seata-serializer-fury + seata-serializer-fory diff --git a/serializer/seata-serializer-all/pom.xml b/serializer/seata-serializer-all/pom.xml index d34e9f6b14e..7d9cd6e8aa1 100644 --- a/serializer/seata-serializer-all/pom.xml +++ b/serializer/seata-serializer-all/pom.xml @@ -60,5 +60,10 @@ seata-serializer-fury ${project.version} + + ${project.groupId} + seata-serializer-fory + ${project.version} + diff --git a/serializer/seata-serializer-fory/pom.xml b/serializer/seata-serializer-fory/pom.xml new file mode 100644 index 00000000000..e1c6238d587 --- /dev/null +++ b/serializer/seata-serializer-fory/pom.xml @@ -0,0 +1,46 @@ + + + + + org.apache.seata + seata-serializer + ${revision} + + 4.0.0 + seata-serializer-fory + jar + seata-serializer-fory ${project.version} + serializer-fory for Seata built with Maven + + + + ${project.groupId} + seata-core + ${project.version} + + + + org.apache.fory + fory-core + + + \ No newline at end of file diff --git a/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializer.java b/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializer.java new file mode 100644 index 00000000000..9ed64e81fbe --- /dev/null +++ b/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializer.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fory; + +import org.apache.fory.ThreadSafeFory; +import org.apache.seata.common.loader.LoadLevel; +import org.apache.seata.core.protocol.AbstractMessage; +import org.apache.seata.core.serializer.Serializer; + +@LoadLevel(name = "FORY") +public class ForySerializer implements Serializer { + @Override + public byte[] serialize(T t) { + if (!(t instanceof AbstractMessage)) { + throw new IllegalArgumentException("AbstractMessage isn't available."); + } + + ThreadSafeFory threadSafeFory = ForySerializerFactory.getInstance().get(); + return threadSafeFory.serialize(t); + } + + @Override + public T deserialize(byte[] bytes) { + if (bytes == null || bytes.length == 0) { + throw new IllegalArgumentException("bytes is null"); + } + ThreadSafeFory threadSafeFory = ForySerializerFactory.getInstance().get(); + return (T) threadSafeFory.deserialize(bytes); + } +} diff --git a/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializerFactory.java b/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializerFactory.java new file mode 100644 index 00000000000..fe8b576f36a --- /dev/null +++ b/serializer/seata-serializer-fory/src/main/java/org/apache/seata/serializer/fory/ForySerializerFactory.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fory; + +import org.apache.fory.Fory; +import org.apache.fory.ThreadLocalFory; +import org.apache.fory.ThreadSafeFory; +import org.apache.fory.config.CompatibleMode; +import org.apache.fory.config.Language; +import org.apache.seata.core.serializer.SerializerSecurityRegistry; + +public class ForySerializerFactory { + private static final ForySerializerFactory FACTORY = new ForySerializerFactory(); + + private static final ThreadSafeFory FORY = new ThreadLocalFory(classLoader -> { + Fory f = Fory.builder() + .withLanguage(Language.JAVA) + // In JAVA mode, classes cannot be registered by tag, and the different registration order between the + // server and the client will cause deserialization failure + // In XLANG cross-language mode has problems with Java class serialization, such as enum classes + // [https://github.com/apache/fory/issues/1644]. + .requireClassRegistration(false) + // enable reference tracking for shared/circular reference. + .withRefTracking(true) + .withClassLoader(classLoader) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .build(); + + // register allow class + f.getClassResolver() + .setClassChecker((classResolver, className) -> + SerializerSecurityRegistry.getAllowClassPattern().contains(className)); + return f; + }); + + public static ForySerializerFactory getInstance() { + return FACTORY; + } + + public ThreadSafeFory get() { + return FORY; + } +} diff --git a/serializer/seata-serializer-fory/src/main/resources/META-INF/services/org.apache.seata.core.serializer.Serializer b/serializer/seata-serializer-fory/src/main/resources/META-INF/services/org.apache.seata.core.serializer.Serializer new file mode 100644 index 00000000000..58c6d0ce84d --- /dev/null +++ b/serializer/seata-serializer-fory/src/main/resources/META-INF/services/org.apache.seata.core.serializer.Serializer @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +org.apache.seata.serializer.fory.ForySerializer \ No newline at end of file diff --git a/serializer/seata-serializer-fory/src/test/java/org/apache/seata/serializer/fory/ForySerializerTest.java b/serializer/seata-serializer-fory/src/test/java/org/apache/seata/serializer/fory/ForySerializerTest.java new file mode 100644 index 00000000000..8fe4ec555a2 --- /dev/null +++ b/serializer/seata-serializer-fory/src/test/java/org/apache/seata/serializer/fory/ForySerializerTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fory; + +import org.apache.seata.core.exception.TransactionExceptionCode; +import org.apache.seata.core.model.BranchStatus; +import org.apache.seata.core.model.BranchType; +import org.apache.seata.core.protocol.ResultCode; +import org.apache.seata.core.protocol.transaction.BranchCommitRequest; +import org.apache.seata.core.protocol.transaction.BranchCommitResponse; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ForySerializerTest { + private static ForySerializer forySerializer; + + @BeforeAll + public static void before() { + forySerializer = new ForySerializer(); + } + + @Test + public void testBranchCommitRequest() { + + BranchCommitRequest branchCommitRequest = new BranchCommitRequest(); + branchCommitRequest.setBranchType(BranchType.AT); + branchCommitRequest.setXid("xid"); + branchCommitRequest.setResourceId("resourceId"); + branchCommitRequest.setBranchId(20190809); + branchCommitRequest.setApplicationData("app"); + + byte[] bytes = forySerializer.serialize(branchCommitRequest); + BranchCommitRequest t = forySerializer.deserialize(bytes); + + assertThat(t.getTypeCode()).isEqualTo(branchCommitRequest.getTypeCode()); + assertThat(t.getBranchType()).isEqualTo(branchCommitRequest.getBranchType()); + assertThat(t.getXid()).isEqualTo(branchCommitRequest.getXid()); + assertThat(t.getResourceId()).isEqualTo(branchCommitRequest.getResourceId()); + assertThat(t.getBranchId()).isEqualTo(branchCommitRequest.getBranchId()); + assertThat(t.getApplicationData()).isEqualTo(branchCommitRequest.getApplicationData()); + } + + @Test + public void testBranchCommitResponse() { + + BranchCommitResponse branchCommitResponse = new BranchCommitResponse(); + branchCommitResponse.setTransactionExceptionCode(TransactionExceptionCode.BranchTransactionNotExist); + branchCommitResponse.setBranchId(20190809); + branchCommitResponse.setBranchStatus(BranchStatus.PhaseOne_Done); + branchCommitResponse.setMsg("20190809"); + branchCommitResponse.setXid("20190809"); + branchCommitResponse.setResultCode(ResultCode.Failed); + + byte[] bytes = forySerializer.serialize(branchCommitResponse); + BranchCommitResponse t = forySerializer.deserialize(bytes); + + assertThat(t.getTransactionExceptionCode()).isEqualTo(branchCommitResponse.getTransactionExceptionCode()); + assertThat(t.getBranchId()).isEqualTo(branchCommitResponse.getBranchId()); + assertThat(t.getBranchStatus()).isEqualTo(branchCommitResponse.getBranchStatus()); + assertThat(t.getMsg()).isEqualTo(branchCommitResponse.getMsg()); + assertThat(t.getResultCode()).isEqualTo(branchCommitResponse.getResultCode()); + } +} diff --git a/serializer/seata-serializer-fury/pom.xml b/serializer/seata-serializer-fury/pom.xml index 18a40ac2026..e5310f3f8e4 100644 --- a/serializer/seata-serializer-fury/pom.xml +++ b/serializer/seata-serializer-fury/pom.xml @@ -37,10 +37,18 @@ seata-core ${project.version} + + ${project.groupId} + seata-serializer-fory + ${project.version} + provided + true + org.apache.fury fury-core + true \ No newline at end of file diff --git a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/DynamicSerializerFactory.java b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/DynamicSerializerFactory.java new file mode 100644 index 00000000000..8de2a20cf18 --- /dev/null +++ b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/DynamicSerializerFactory.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fury; + +import org.apache.seata.core.serializer.Serializer; + +public class DynamicSerializerFactory { + private static final DynamicSerializerFactory FACTORY = new DynamicSerializerFactory(); + + private final Serializer furyDelegate; + + private DynamicSerializerFactory() { + this.furyDelegate = createFuryDelegate(); + } + + public static DynamicSerializerFactory getInstance() { + return FACTORY; + } + + public Serializer get() { + return furyDelegate; + } + + private Serializer createFuryDelegate() { + // First, try to load seata-serializer-fory. + try { + Class.forName("org.apache.seata.serializer.fory.ForySerializer"); + return new ForySerializerDelegate(); + } catch (ClassNotFoundException e) { + } + // Second, try to load Apache Fory. + try { + Class.forName("org.apache.fory.Fury"); + return new ThreadSafeForyDelegate(); + } catch (ClassNotFoundException e) { + } + // If Fory is unavailable, fallback to Fury. + try { + Class.forName("org.apache.fury.Fury"); + return new ThreadSafeFuryDelegate(); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Neither Apache Fory nor Apache Fury found in classpath", e); + } + } +} diff --git a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ForySerializerDelegate.java b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ForySerializerDelegate.java new file mode 100644 index 00000000000..130092af68f --- /dev/null +++ b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ForySerializerDelegate.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fury; + +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.serializer.fory.ForySerializer; + +public class ForySerializerDelegate implements Serializer { + + private static final ForySerializer SERIALIZER = new ForySerializer(); + + @Override + public byte[] serialize(Object obj) { + return SERIALIZER.serialize(obj); + } + + @Override + public Object deserialize(byte[] bytes) { + return SERIALIZER.deserialize(bytes); + } +} diff --git a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializer.java b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializer.java index 8724475e458..5ace1545dd7 100644 --- a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializer.java +++ b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializer.java @@ -16,7 +16,6 @@ */ package org.apache.seata.serializer.fury; -import org.apache.fury.ThreadSafeFury; import org.apache.seata.common.loader.LoadLevel; import org.apache.seata.core.protocol.AbstractMessage; import org.apache.seata.core.serializer.Serializer; @@ -28,8 +27,8 @@ public byte[] serialize(T t) { if (!(t instanceof AbstractMessage)) { throw new IllegalArgumentException("AbstractMessage isn't available."); } - ThreadSafeFury threadSafeFury = FurySerializerFactory.getInstance().get(); - return threadSafeFury.serialize(t); + Serializer serializer = DynamicSerializerFactory.getInstance().get(); + return serializer.serialize(t); } @Override @@ -37,7 +36,7 @@ public T deserialize(byte[] bytes) { if (bytes == null || bytes.length == 0) { throw new IllegalArgumentException("bytes is null"); } - ThreadSafeFury threadSafeFury = FurySerializerFactory.getInstance().get(); - return (T) threadSafeFury.deserialize(bytes); + Serializer serializer = DynamicSerializerFactory.getInstance().get(); + return (T) serializer.deserialize(bytes); } } diff --git a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeForyDelegate.java b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeForyDelegate.java new file mode 100644 index 00000000000..8a8843d2d43 --- /dev/null +++ b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeForyDelegate.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.serializer.fury; + +import org.apache.fory.Fory; +import org.apache.fory.ThreadLocalFory; +import org.apache.fory.ThreadSafeFory; +import org.apache.fory.config.CompatibleMode; +import org.apache.fory.config.Language; +import org.apache.seata.core.serializer.Serializer; +import org.apache.seata.core.serializer.SerializerSecurityRegistry; + +public class ThreadSafeForyDelegate implements Serializer { + + private static final ThreadSafeFory FORY = new ThreadLocalFory(classLoader -> { + Fory f = Fory.builder() + .withLanguage(Language.JAVA) + // In JAVA mode, classes cannot be registered by tag, and the different registration order between the + // server and the client will cause deserialization failure + // In XLANG cross-language mode has problems with Java class serialization, such as enum classes + // [https://github.com/apache/fory/issues/1644]. + .requireClassRegistration(false) + // enable reference tracking for shared/circular reference. + .withRefTracking(true) + .withClassLoader(classLoader) + .withCompatibleMode(CompatibleMode.COMPATIBLE) + .build(); + + // register allow class + f.getClassResolver() + .setClassChecker((classResolver, className) -> + SerializerSecurityRegistry.getAllowClassPattern().contains(className)); + return f; + }); + + @Override + public byte[] serialize(Object obj) { + return FORY.serialize(obj); + } + + @Override + public Object deserialize(byte[] bytes) { + return FORY.deserialize(bytes); + } +} diff --git a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializerFactory.java b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeFuryDelegate.java similarity index 88% rename from serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializerFactory.java rename to serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeFuryDelegate.java index f99358622ac..872558b5be5 100644 --- a/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/FurySerializerFactory.java +++ b/serializer/seata-serializer-fury/src/main/java/org/apache/seata/serializer/fury/ThreadSafeFuryDelegate.java @@ -22,10 +22,10 @@ import org.apache.fury.config.CompatibleMode; import org.apache.fury.config.Language; import org.apache.fury.resolver.AllowListChecker; +import org.apache.seata.core.serializer.Serializer; import org.apache.seata.core.serializer.SerializerSecurityRegistry; -public class FurySerializerFactory { - private static final FurySerializerFactory FACTORY = new FurySerializerFactory(); +public class ThreadSafeFuryDelegate implements Serializer { private static final ThreadSafeFury FURY = new ThreadLocalFury(classLoader -> { Fury f = Fury.builder() @@ -48,11 +48,13 @@ public class FurySerializerFactory { return f; }); - public static FurySerializerFactory getInstance() { - return FACTORY; + @Override + public byte[] serialize(Object obj) { + return FURY.serialize(obj); } - public ThreadSafeFury get() { - return FURY; + @Override + public Object deserialize(byte[] bytes) { + return FURY.deserialize(bytes); } }