diff --git a/all/pom.xml b/all/pom.xml
index 74b93dcae..b9343a7f2 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -183,6 +183,11 @@
sofa-rpc-codec-jackson
${project.version}
+
+ com.alipay.sofa
+ sofa-rpc-codec-sofa-fury
+ ${project.version}
+
com.alipay.sofa
sofa-rpc-fault-tolerance
@@ -519,6 +524,7 @@
com.alipay.sofa:sofa-rpc-codec-jackson
com.alipay.sofa:sofa-rpc-codec-msgpack
com.alipay.sofa:sofa-rpc-codec-sofa-hessian
+ com.alipay.sofa:sofa-rpc-codec-sofa-fury
com.alipay.sofa:sofa-rpc-fault-tolerance
com.alipay.sofa:sofa-rpc-fault-hystrix
com.alipay.sofa:sofa-rpc-log-common-tools
diff --git a/bom/pom.xml b/bom/pom.xml
index 047b7b01a..a17ee2bee 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -39,6 +39,7 @@
2.12.7.1
0.6.12
1.5.9
+ 0.4.1
1.53.0
@@ -298,6 +299,11 @@
msgpack
${msgpack.version}
+
+ org.furyio
+ fury-core
+ ${fury.version}
+
org.apache.curator
diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java
similarity index 59%
rename from codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java
rename to codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java
index 8b48c7a7b..54f4ddf64 100644
--- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoader.java
+++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/BlackAndWhiteListFileLoader.java
@@ -14,10 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.alipay.sofa.rpc.codec.sofahessian;
+package com.alipay.sofa.rpc.codec.common;
-import com.alipay.sofa.rpc.common.SofaConfigs;
-import com.alipay.sofa.rpc.common.SofaOptions;
+import com.alipay.sofa.common.config.SofaConfigs;
import com.alipay.sofa.rpc.common.utils.StringUtils;
import com.alipay.sofa.rpc.log.Logger;
import com.alipay.sofa.rpc.log.LoggerFactory;
@@ -30,6 +29,8 @@
import java.util.LinkedList;
import java.util.List;
+import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_BLACKLIST_OVERRIDE;
+import static com.alipay.sofa.rpc.common.config.RpcConfigKeys.SERIALIZE_WHITELIST_OVERRIDE;
import static com.alipay.sofa.rpc.common.utils.IOUtils.closeQuietly;
/**
@@ -37,21 +38,24 @@
*
* @author GengZhang
*/
-public class BlackListFileLoader {
+public class BlackAndWhiteListFileLoader {
- private static final Logger LOGGER = LoggerFactory.getLogger(BlackListFileLoader.class);
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(BlackAndWhiteListFileLoader.class);
- public static final List SOFA_SERIALIZE_BLACK_LIST = loadFile("/sofa-rpc/serialize_blacklist.txt");
+ public static final List SOFA_SERIALIZE_BLACK_LIST = loadBlackListFile("/sofa-rpc/serialize_blacklist.txt");
- static List loadFile(String path) {
- List blackPrefixList = new ArrayList();
+ public static final List SOFA_SERIALIZER_WHITE_LIST = loadWhiteListFile("/sofa-rpc/serialize_whitelist.txt");
+
+ public static List loadBlackListFile(String path) {
+ List blackPrefixList = new ArrayList<>();
InputStream input = null;
try {
- input = BlackListFileLoader.class.getResourceAsStream(path);
+ input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path);
if (input != null) {
readToList(input, "UTF-8", blackPrefixList);
}
- String overStr = SofaConfigs.getStringValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, "");
+ String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_BLACKLIST_OVERRIDE, "");
if (StringUtils.isNotBlank(overStr)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Serialize blacklist will override with configuration: {}", overStr);
@@ -68,6 +72,31 @@ static List loadFile(String path) {
return blackPrefixList;
}
+ public static List loadWhiteListFile(String path) {
+ List whitePrefixList = new ArrayList<>();
+ InputStream input = null;
+ try {
+ input = BlackAndWhiteListFileLoader.class.getResourceAsStream(path);
+ if (input != null) {
+ readToList(input, "UTF-8", whitePrefixList);
+ }
+ String overStr = SofaConfigs.getOrCustomDefault(SERIALIZE_WHITELIST_OVERRIDE, "");
+ if (StringUtils.isNotBlank(overStr)) {
+ if (LOGGER.isInfoEnabled()) {
+ LOGGER.info("Serialize whitelist will override with configuration: {}", overStr);
+ }
+ overrideWhiteList(whitePrefixList, overStr);
+ }
+ } catch (Exception e) {
+ if (LOGGER.isErrorEnabled()) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ } finally {
+ closeQuietly(input);
+ }
+ return whitePrefixList;
+ }
+
/**
* 读文件,将结果丢入List
*
@@ -100,12 +129,12 @@ private static void readToList(InputStream input, String encoding, List
/**
* Override blacklist with override string.
- *
- * @param originList Origin black list
+ *
+ * @param originList Origin black list
* @param overrideStr The override string
*/
- static void overrideBlackList(List originList, String overrideStr) {
- List adds = new LinkedList();
+ public static void overrideBlackList(List originList, String overrideStr) {
+ List adds = new LinkedList<>();
String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr);
for (String overrideItem : overrideItems) {
if (StringUtils.isNotBlank(overrideItem)) {
@@ -127,4 +156,19 @@ static void overrideBlackList(List originList, String overrideStr) {
originList.addAll(adds);
}
}
+
+ public static void overrideWhiteList(List originList, String overrideStr) {
+ List adds = new LinkedList<>();
+ String[] overrideItems = StringUtils.splitWithCommaOrSemicolon(overrideStr);
+ for (String overrideItem : overrideItems) {
+ if (StringUtils.isNotBlank(overrideItem)) {
+ if (!originList.contains(overrideItem)) {
+ adds.add(overrideItem);
+ }
+ }
+ }
+ if (adds.size() > 0) {
+ originList.addAll(adds);
+ }
+ }
}
diff --git a/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java
new file mode 100644
index 000000000..bcedf2101
--- /dev/null
+++ b/codec/codec-api/src/main/java/com/alipay/sofa/rpc/codec/common/SerializeCheckStatus.java
@@ -0,0 +1,48 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.common;
+
+/**
+ * @author Even
+ * @date 2024/1/5 19:12
+ */
+public enum SerializeCheckStatus {
+ /**
+ * Disable serialize check for all classes
+ */
+ DISABLE(0),
+
+ /**
+ * Only deny danger classes, warn if other classes are not in allow list
+ */
+ WARN(1),
+
+ /**
+ * Only allow classes in allow list, deny if other classes are not in allow list
+ */
+ STRICT(2);
+
+ private final int mode;
+
+ SerializeCheckStatus(int mode) {
+ this.mode = mode;
+ }
+
+ public int getSerializeCheckMode() {
+ return mode;
+ }
+}
diff --git a/codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt
similarity index 100%
rename from codec/codec-sofa-hessian/src/main/resources/sofa-rpc/serialize_blacklist.txt
rename to codec/codec-api/src/main/resources/sofa-rpc/serialize_blacklist.txt
diff --git a/codec/codec-sofa-fury/pom.xml b/codec/codec-sofa-fury/pom.xml
new file mode 100644
index 000000000..70150a8f9
--- /dev/null
+++ b/codec/codec-sofa-fury/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+
+ com.alipay.sofa
+ sofa-rpc-codec
+ ${revision}
+
+
+ sofa-rpc-codec-sofa-fury
+
+
+
+ com.alipay.sofa
+ sofa-rpc-codec-api
+
+
+ com.alipay.sofa
+ sofa-rpc-api
+
+
+ com.alipay.sofa
+ sofa-rpc-log
+
+
+
+
+ org.furyio
+ fury-core
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ test
+
+
+ junit
+ junit
+ test
+
+
+
diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java
new file mode 100644
index 000000000..e1a61a6fd
--- /dev/null
+++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/FurySerializer.java
@@ -0,0 +1,182 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury;
+
+import com.alipay.sofa.common.config.SofaConfigs;
+import com.alipay.sofa.rpc.codec.AbstractSerializer;
+import com.alipay.sofa.rpc.codec.CustomSerializer;
+import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader;
+import com.alipay.sofa.rpc.codec.common.SerializeCheckStatus;
+import com.alipay.sofa.rpc.codec.fury.serialize.SofaRequestFurySerializer;
+import com.alipay.sofa.rpc.codec.fury.serialize.SofaResponseFurySerializer;
+import com.alipay.sofa.rpc.common.config.RpcConfigKeys;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.Extension;
+import com.alipay.sofa.rpc.transport.AbstractByteBuf;
+import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf;
+import io.fury.Fury;
+import io.fury.ThreadLocalFury;
+import io.fury.config.Language;
+import io.fury.memory.MemoryBuffer;
+import io.fury.resolver.AllowListChecker;
+
+import java.util.List;
+import java.util.Map;
+
+import static io.fury.config.CompatibleMode.COMPATIBLE;
+
+/**
+ * @author lipan
+ */
+@Extension(value = "fury2", code = 22)
+public class FurySerializer extends AbstractSerializer {
+
+ private final ThreadLocalFury fury;
+
+ private final String checkerMode = SofaConfigs.getOrDefault(RpcConfigKeys.SERIALIZE_CHECKER_MODE);
+
+ public FurySerializer() {
+ fury = new ThreadLocalFury(classLoader -> {
+ Fury f = Fury.builder().withLanguage(Language.JAVA)
+ .withRefTracking(true)
+ .withCodegen(true)
+ .withNumberCompressed(true)
+ .withCompatibleMode(COMPATIBLE)
+ .requireClassRegistration(false)
+ .withClassLoader(classLoader)
+ .withAsyncCompilation(true)
+ .build();
+
+ // Do not use any configuration
+ if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.DISABLE.name())) {
+ AllowListChecker noChecker = new AllowListChecker(AllowListChecker.CheckLevel.DISABLE);
+ f.getClassResolver().setClassChecker(noChecker);
+ return f;
+ } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.WARN.name())) {
+ AllowListChecker blackListChecker = new AllowListChecker(AllowListChecker.CheckLevel.WARN);
+ List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST;
+ // To setting checker
+ f.getClassResolver().setClassChecker(blackListChecker);
+ blackListChecker.addListener(f.getClassResolver());
+ // BlackList classes use wildcards
+ for (String key : blackList) {
+ blackListChecker.disallowClass(key + "*");
+ }
+ } else if (checkerMode.equalsIgnoreCase(SerializeCheckStatus.STRICT.name())) {
+ AllowListChecker blackAndWhiteListChecker = new AllowListChecker(AllowListChecker.CheckLevel.STRICT);
+ List whiteList = BlackAndWhiteListFileLoader.SOFA_SERIALIZER_WHITE_LIST;
+ // To setting checker
+ f.getClassResolver().setClassChecker(blackAndWhiteListChecker);
+ blackAndWhiteListChecker.addListener(f.getClassResolver());
+ // WhiteList classes use wildcards
+ for (String key : whiteList) {
+ blackAndWhiteListChecker.allowClass(key + "*");
+ }
+ List blackList = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST;
+ // To setting checker
+ f.getClassResolver().setClassChecker(blackAndWhiteListChecker);
+ blackAndWhiteListChecker.addListener(f.getClassResolver());
+ // BlackList classes use wildcards
+ for (String key : blackList) {
+ blackAndWhiteListChecker.disallowClass(key + "*");
+ }
+ }
+ f.register(SofaRequest.class);
+ f.register(SofaResponse.class);
+ f.register(SofaRpcException.class);
+ return f;
+ });
+ addSerializer(SofaRequest.class, new SofaRequestFurySerializer(fury));
+ addSerializer(SofaResponse.class, new SofaResponseFurySerializer(fury));
+ }
+
+ @Override
+ public AbstractByteBuf encode(final Object object, final Map context) throws SofaRpcException {
+ if (object == null) {
+ throw buildSerializeError("Unsupported null message!");
+ }
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ fury.setClassLoader(contextClassLoader);
+ CustomSerializer customSerializer = getObjCustomSerializer(object);
+ if (customSerializer != null) {
+ return customSerializer.encodeObject(object, context);
+ } else {
+ MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32);
+ writeBuffer.writerIndex(0);
+ fury.serialize(writeBuffer, object);
+ return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex()));
+ }
+ } catch (Exception e) {
+ throw buildSerializeError(e.getMessage(), e);
+ } finally {
+ fury.clearClassLoader(contextClassLoader);
+ }
+ }
+
+ @Override
+ public Object decode(final AbstractByteBuf data, final Class clazz, final Map context)
+ throws SofaRpcException {
+ if (data.readableBytes() <= 0 || clazz == null) {
+ throw buildDeserializeError("Deserialized array is empty.");
+ }
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ fury.setClassLoader(contextClassLoader);
+ CustomSerializer customSerializer = getSerializer(clazz);
+ if (customSerializer != null) {
+ return customSerializer.decodeObject(data, context);
+ } else {
+ MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array());
+ return fury.deserialize(readBuffer);
+ }
+ } catch (Exception e) {
+ throw buildDeserializeError(e.getMessage(), e);
+ } finally {
+ fury.clearClassLoader(contextClassLoader);
+ }
+ }
+
+ @Override
+ public void decode(final AbstractByteBuf data, final Object template, final Map context)
+ throws SofaRpcException {
+ if (template == null) {
+ throw buildDeserializeError("template is null!");
+ }
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ fury.setClassLoader(contextClassLoader);
+ CustomSerializer customSerializer = getObjCustomSerializer(template);
+ if (customSerializer != null) {
+ customSerializer.decodeObjectByTemplate(data, context, template);
+ } else {
+ throw buildDeserializeError("Only support decode from SofaRequest and SofaResponse template");
+ }
+ } catch (Exception e) {
+ throw buildDeserializeError(e.getMessage(), e);
+ } finally {
+ fury.clearClassLoader(contextClassLoader);
+ }
+ }
+
+ public ThreadLocalFury getFury() {
+ return fury;
+ }
+
+}
diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java
new file mode 100644
index 000000000..9122c0c18
--- /dev/null
+++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaRequestFurySerializer.java
@@ -0,0 +1,117 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.serialize;
+
+import com.alipay.sofa.rpc.codec.CustomSerializer;
+import com.alipay.sofa.rpc.common.RemotingConstants;
+import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.transport.AbstractByteBuf;
+import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf;
+import io.fury.ThreadLocalFury;
+import io.fury.memory.MemoryBuffer;
+
+import java.util.Map;
+
+/**
+ * @author Even
+ * @date 2024/1/4 19:29
+ */
+public class SofaRequestFurySerializer implements CustomSerializer {
+
+ private final ThreadLocalFury fury;
+
+ public SofaRequestFurySerializer(ThreadLocalFury fury) {
+ this.fury = fury;
+ }
+
+ @Override
+ public AbstractByteBuf encodeObject(SofaRequest object, Map context) throws SofaRpcException {
+ try {
+ MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32);
+ writeBuffer.writerIndex(0);
+
+ // 根据SerializeType信息决定序列化器
+ boolean genericSerialize = context != null &&
+ isGenericRequest(context.get(RemotingConstants.HEAD_GENERIC_TYPE));
+ if (genericSerialize) {
+ // TODO support generic call
+ throw new SofaRpcException("Generic call is not supported for now.");
+ }
+ fury.serialize(writeBuffer, object);
+ final Object[] args = object.getMethodArgs();
+ fury.serialize(writeBuffer, args);
+
+ return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex()));
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public SofaRequest decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException {
+ MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array());
+ try {
+ SofaRequest sofaRequest = (SofaRequest) fury.deserialize(readBuffer);
+ String targetServiceName = sofaRequest.getTargetServiceUniqueName();
+ if (targetServiceName == null) {
+ throw new SofaRpcException("Target service name of request is null!");
+ }
+ String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName);
+ sofaRequest.setInterfaceName(interfaceName);
+ final Object[] args = (Object[]) fury.deserialize(readBuffer);
+ sofaRequest.setMethodArgs(args);
+ return sofaRequest;
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaRequest template)
+ throws SofaRpcException {
+ if (data.readableBytes() <= 0) {
+ throw new SofaRpcException("Deserialized array is empty.");
+ }
+ try {
+ MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array());
+ SofaRequest tmp = (SofaRequest) fury.deserialize(readBuffer);
+ String targetServiceName = tmp.getTargetServiceUniqueName();
+ if (targetServiceName == null) {
+ throw new SofaRpcException("Target service name of request is null!");
+ }
+ // copy values to template
+ template.setMethodName(tmp.getMethodName());
+ template.setMethodArgSigs(tmp.getMethodArgSigs());
+ template.setTargetServiceUniqueName(tmp.getTargetServiceUniqueName());
+ template.setTargetAppName(tmp.getTargetAppName());
+ template.addRequestProps(tmp.getRequestProps());
+ String interfaceName = ConfigUniqueNameGenerator.getInterfaceName(targetServiceName);
+ template.setInterfaceName(interfaceName);
+ final Object[] args = (Object[]) fury.deserialize(readBuffer);
+ template.setMethodArgs(args);
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ protected boolean isGenericRequest(String serializeType) {
+ return serializeType != null && !serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_NORMAL);
+ }
+
+}
diff --git a/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java
new file mode 100644
index 000000000..9a7402ab1
--- /dev/null
+++ b/codec/codec-sofa-fury/src/main/java/com/alipay/sofa/rpc/codec/fury/serialize/SofaResponseFurySerializer.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.serialize;
+
+import com.alipay.sofa.rpc.codec.CustomSerializer;
+import com.alipay.sofa.rpc.common.RemotingConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.transport.AbstractByteBuf;
+import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf;
+import io.fury.ThreadLocalFury;
+import io.fury.memory.MemoryBuffer;
+
+import java.util.Map;
+
+/**
+ * @author Even
+ * @date 2024/1/4 19:30
+ */
+public class SofaResponseFurySerializer implements CustomSerializer {
+
+ private final ThreadLocalFury fury;
+
+ public SofaResponseFurySerializer(ThreadLocalFury fury) {
+ this.fury = fury;
+ }
+
+ @Override
+ public AbstractByteBuf encodeObject(SofaResponse object, Map context) throws SofaRpcException {
+ try {
+ fury.setClassLoader(Thread.currentThread().getContextClassLoader());
+ MemoryBuffer writeBuffer = MemoryBuffer.newHeapBuffer(32);
+ writeBuffer.writerIndex(0);
+ fury.serialize(writeBuffer, object);
+ return new ByteArrayWrapperByteBuf(writeBuffer.getBytes(0, writeBuffer.writerIndex()));
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public SofaResponse decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException {
+ MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array());
+ try {
+ fury.setClassLoader(Thread.currentThread().getContextClassLoader());
+ boolean genericSerialize = context != null && isGenericResponse(
+ context.get(RemotingConstants.HEAD_GENERIC_TYPE));
+ if (genericSerialize) {
+ // TODO support generic call
+ throw new SofaRpcException("Generic call is not supported for now.");
+ }
+ return (SofaResponse) fury.deserialize(readBuffer);
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void decodeObjectByTemplate(AbstractByteBuf data, Map context, SofaResponse template)
+ throws SofaRpcException {
+ if (data.readableBytes() <= 0) {
+ throw new SofaRpcException("Deserialized array is empty.");
+ }
+ try {
+ fury.setClassLoader(Thread.currentThread().getContextClassLoader());
+ MemoryBuffer readBuffer = MemoryBuffer.fromByteArray(data.array());
+ // 根据SerializeType信息决定序列化器
+ boolean genericSerialize = context != null && isGenericResponse(
+ context.get(RemotingConstants.HEAD_GENERIC_TYPE));
+ if (genericSerialize) {
+ // TODO support generic call
+ throw new SofaRpcException("Generic call is not supported for now.");
+ } else {
+ SofaResponse tmp = (SofaResponse) fury.deserialize(readBuffer);
+ // copy values to template
+ template.setErrorMsg(tmp.getErrorMsg());
+ template.setAppResponse(tmp.getAppResponse());
+ template.setResponseProps(tmp.getResponseProps());
+ }
+ } catch (Exception e) {
+ throw new SofaRpcException(e.getMessage(), e);
+ }
+ }
+
+ protected boolean isGenericResponse(String serializeType) {
+ return serializeType != null && serializeType.equals(RemotingConstants.SERIALIZE_FACTORY_GENERIC);
+ }
+}
diff --git a/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer
new file mode 100644
index 000000000..dc727a0dd
--- /dev/null
+++ b/codec/codec-sofa-fury/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.codec.Serializer
@@ -0,0 +1 @@
+fury2=com.alipay.sofa.rpc.codec.fury.FurySerializer
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java
new file mode 100644
index 000000000..fc4fde8cc
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/FurySerializerTest.java
@@ -0,0 +1,289 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury;
+
+import com.alipay.sofa.rpc.codec.Serializer;
+import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass;
+import com.alipay.sofa.rpc.codec.fury.model.none.NoneClassHasBlackClass;
+import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoRequest;
+import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoResponse;
+import com.alipay.sofa.rpc.codec.fury.model.whitelist.WhiteClassHasBlackClass;
+import com.alipay.sofa.rpc.codec.fury.model.whitelist.DemoService;
+import com.alipay.sofa.rpc.common.RemotingConstants;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback;
+import com.alipay.sofa.rpc.core.request.RequestBase;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.ExtensionLoaderFactory;
+import com.alipay.sofa.rpc.transport.AbstractByteBuf;
+import com.alipay.sofa.rpc.transport.ByteArrayWrapperByteBuf;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author lipan
+ */
+public class FurySerializerTest {
+
+ private final FurySerializer serializer = (FurySerializer) ExtensionLoaderFactory.getExtensionLoader(
+ Serializer.class).getExtension("fury2");
+
+ @Test
+ public void encodeAndDecode() {
+ try {
+ serializer.encode(null, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ DemoRequest demoRequest = new DemoRequest();
+ demoRequest.setName("a");
+ AbstractByteBuf byteBuf = serializer.encode(demoRequest, null);
+ DemoRequest req2 = (DemoRequest) serializer.decode(byteBuf, DemoRequest.class, null);
+ Assert.assertEquals(demoRequest.getName(), req2.getName());
+
+ AbstractByteBuf data = serializer.encode("xxx", null);
+ String dst = (String) serializer.decode(data, String.class, null);
+ Assert.assertEquals("xxx", dst);
+
+ try {
+ serializer.decode(data, null, null);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+
+ try {
+ serializer.decode(data, "", null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+ }
+
+ @Test
+ public void testSofaRequest() throws Exception {
+ SofaRequest request = buildRequest();
+ AbstractByteBuf data = serializer.encode(request, null);
+
+ serializer.encode("123456", null);
+ SofaRequest decode = (SofaRequest) serializer.decode(data, SofaRequest.class, null);
+ assertEqualsSofaRequest(request, decode);
+
+ SofaRequest newRequest = new SofaRequest();
+ serializer.decode(data, newRequest, null);
+ assertEqualsSofaRequest(request, newRequest);
+
+ // null request
+ newRequest = new SofaRequest();
+ try {
+ serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newRequest, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+ }
+
+ @Test
+ public void testSofaResponse() throws Exception {
+ SofaResponse response = new SofaResponse();
+ final DemoResponse demoAppResponse = new DemoResponse();
+ demoAppResponse.setWord("result");
+ response.setAppResponse(demoAppResponse);
+ AbstractByteBuf data = serializer.encode(response, null);
+
+ try {
+ serializer.decode(data, null, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ try {
+ serializer.decode(data, new Object(), null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ SofaResponse decode = (SofaResponse) serializer.decode(data, SofaResponse.class, null);
+ Assert.assertFalse(decode.isError());
+ Assert.assertEquals(response.getAppResponse(), decode.getAppResponse());
+ Assert.assertEquals("result", ((DemoResponse) decode.getAppResponse()).getWord());
+
+ // success response
+ SofaResponse newResponse = new SofaResponse();
+ serializer.decode(data, newResponse, null);
+ Assert.assertFalse(newResponse.isError());
+ Assert.assertEquals(response.getAppResponse(), newResponse.getAppResponse());
+ Assert.assertEquals("result", ((DemoResponse) newResponse.getAppResponse()).getWord());
+
+ // null response
+ newResponse = new SofaResponse();
+ try {
+ serializer.decode(new ByteArrayWrapperByteBuf(new byte[0]), newResponse, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+ // error response
+ response = new SofaResponse();
+ response.setErrorMsg("1233");
+ data = serializer.encode(response, null);
+ newResponse = new SofaResponse();
+ serializer.decode(data, newResponse, null);
+ Assert.assertTrue(newResponse.isError());
+ Assert.assertEquals(response.getErrorMsg(), newResponse.getErrorMsg());
+ }
+
+ private SofaRequest buildRequest() throws NoSuchMethodException {
+ SofaRequest request = new SofaRequest();
+ request.setInterfaceName(DemoService.class.getName());
+ request.setMethodName("say");
+ request.setMethod(DemoService.class.getMethod("say", DemoRequest.class));
+ final DemoRequest demoRequest = new DemoRequest();
+ demoRequest.setName("name");
+ request.setMethodArgs(new Object[] { demoRequest });
+ request.setMethodArgSigs(new String[] { DemoRequest.class.getCanonicalName() });
+ request.setTargetServiceUniqueName(DemoService.class.getName() + ":1.0");
+ request.setTargetAppName("targetApp");
+ request.setSerializeType((byte) 22);
+ request.setTimeout(1024);
+ request.setInvokeType(RpcConstants.INVOKER_TYPE_SYNC);
+ Map map = new HashMap();
+ map.put("a", "xxx");
+ map.put("b", "yyy");
+ request.addRequestProp(RemotingConstants.RPC_TRACE_NAME, map);
+ request.setSofaResponseCallback(new SofaResponseCallback() {
+ @Override
+ public void onAppResponse(Object appResponse, String methodName, RequestBase request) {
+
+ }
+
+ @Override
+ public void onAppException(Throwable throwable, String methodName, RequestBase request) {
+
+ }
+
+ @Override
+ public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) {
+
+ }
+ });
+ return request;
+ }
+
+ private void assertEqualsSofaRequest(SofaRequest request, SofaRequest decode) {
+ Assert.assertEquals(decode.getInterfaceName(), request.getInterfaceName());
+ Assert.assertEquals(decode.getMethodName(), request.getMethodName());
+ Assert.assertArrayEquals(decode.getMethodArgSigs(), request.getMethodArgSigs());
+ Assert.assertEquals(decode.getMethodArgs().length, request.getMethodArgs().length);
+ Assert.assertEquals("name", ((DemoRequest) decode.getMethodArgs()[0]).getName());
+ Assert.assertEquals(decode.getTargetServiceUniqueName(), request.getTargetServiceUniqueName());
+ Assert.assertEquals(decode.getTargetAppName(), request.getTargetAppName());
+ Assert.assertEquals(decode.getRequestProp(RemotingConstants.RPC_TRACE_NAME),
+ request.getRequestProp(RemotingConstants.RPC_TRACE_NAME));
+ }
+
+ @Test
+ public void testChecker() throws Exception {
+ // default fury checkMode is STRICT
+ WhiteClassHasBlackClass whiteClassNullBlackClass = new WhiteClassHasBlackClass();
+ NoneClassHasBlackClass noneClassNullBlackClass = new NoneClassHasBlackClass();
+
+ BlackListClass blackListClass = new BlackListClass();
+ WhiteClassHasBlackClass whiteClassHasBlackClass = new WhiteClassHasBlackClass();
+ whiteClassHasBlackClass.setBlackListClass(blackListClass);
+ NoneClassHasBlackClass noneClassHasBlackClass = new NoneClassHasBlackClass();
+ noneClassHasBlackClass.setBlackListClass(blackListClass);
+
+ try {
+ serializer.encode(noneClassNullBlackClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ try {
+ serializer.encode(noneClassHasBlackClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ try {
+ serializer.encode(blackListClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ serializer.encode(whiteClassNullBlackClass, null);
+ try {
+ serializer.encode(whiteClassHasBlackClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ // test change fury checkMode to blacklist
+ System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "WARN");
+ FurySerializer furySerializer = new FurySerializer();
+
+ furySerializer.encode(noneClassNullBlackClass, null);
+
+ try {
+ furySerializer.encode(noneClassHasBlackClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ try {
+ //Not registered this class
+ furySerializer.encode(blackListClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+
+ furySerializer.encode(whiteClassNullBlackClass, null);
+ try {
+ furySerializer.encode(whiteClassHasBlackClass, null);
+ Assert.fail();
+ } catch (Exception e) {
+
+ }
+ System.getProperties().remove("sofa.rpc.codec.serialize.checkMode");
+
+ // test change fury checkMode to none
+ System.getProperties().put("sofa.rpc.codec.serialize.checkMode", "DISABLE");
+ FurySerializer noneFurySerializer = new FurySerializer();
+ noneFurySerializer.encode(noneClassNullBlackClass, null);
+ noneFurySerializer.encode(noneClassHasBlackClass, null);
+ noneFurySerializer.encode(blackListClass, null);
+ noneFurySerializer.encode(whiteClassNullBlackClass, null);
+ noneFurySerializer.encode(whiteClassHasBlackClass, null);
+ System.getProperties().remove("sofa.rpc.codec.serialize.checkMode");
+ }
+
+}
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java
new file mode 100644
index 000000000..78281a910
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/blacklist/BlackListClass.java
@@ -0,0 +1,24 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.model.blacklist;
+
+/**
+ * @author lipan
+ */
+public class BlackListClass {
+ private String test;
+}
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java
new file mode 100644
index 000000000..8ddaaa9a8
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/none/NoneClassHasBlackClass.java
@@ -0,0 +1,36 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.model.none;
+
+import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass;
+
+/**
+ * @author Even
+ * @date 2024/1/2 11:33
+ */
+public class NoneClassHasBlackClass {
+
+ private BlackListClass blackListClass;
+
+ public BlackListClass getBlackListClass() {
+ return blackListClass;
+ }
+
+ public void setBlackListClass(BlackListClass blackListClass) {
+ this.blackListClass = blackListClass;
+ }
+}
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java
new file mode 100644
index 000000000..7b9bb7129
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoRequest.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist;
+
+/**
+ * @author lipan
+ */
+public class DemoRequest {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java
new file mode 100644
index 000000000..ffca06616
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoResponse.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist;
+
+/**
+ * @author lipan
+ */
+public class DemoResponse {
+
+ private String word;
+
+ public String getWord() {
+ return word;
+ }
+
+ public void setWord(String word) {
+ this.word = word;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof DemoResponse))
+ return false;
+
+ DemoResponse that = (DemoResponse) o;
+
+ return word != null ? word.equals(that.word) : that.word == null;
+ }
+
+ @Override
+ public int hashCode() {
+ return word != null ? word.hashCode() : 0;
+ }
+}
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java
new file mode 100644
index 000000000..604473b7b
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/DemoService.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec.fury.model.whitelist;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author lipan
+ */
+public interface DemoService {
+
+ public DemoResponse say(DemoRequest demoRequest);
+
+ public DemoResponse say2(DemoRequest demoRequest, Map ctx, int id);
+
+ public List say3(List list);
+
+}
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.java
new file mode 100644
index 000000000..10e3943fb
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/java/com/alipay/sofa/rpc/codec/fury/model/whitelist/WhiteClassHasBlackClass.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 com.alipay.sofa.rpc.codec.fury.model.whitelist;
+
+import com.alipay.sofa.rpc.codec.fury.model.blacklist.BlackListClass;
+
+/**
+ * @author lipan
+ */
+public class WhiteClassHasBlackClass {
+
+ private BlackListClass blackListClass;
+
+ public BlackListClass getBlackListClass() {
+ return blackListClass;
+ }
+
+ public void setBlackListClass(BlackListClass blackListClass) {
+ this.blackListClass = blackListClass;
+ }
+}
diff --git a/codec/codec-sofa-fury/src/test/resources/log4j.xml b/codec/codec-sofa-fury/src/test/resources/log4j.xml
new file mode 100644
index 000000000..e95634f16
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/resources/log4j.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json
new file mode 100644
index 000000000..5b573549a
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/rpc-config.json
@@ -0,0 +1,4 @@
+{
+ "rpc.config.order": 999,
+ "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl"
+}
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt
new file mode 100644
index 000000000..991e2a54d
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_blacklist.txt
@@ -0,0 +1 @@
+com.alipay.sofa.rpc.codec.fury.model.blacklist.
\ No newline at end of file
diff --git a/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt
new file mode 100644
index 000000000..6f1718654
--- /dev/null
+++ b/codec/codec-sofa-fury/src/test/resources/sofa-rpc/serialize_whitelist.txt
@@ -0,0 +1 @@
+com.alipay.sofa.rpc.codec.fury.model.whitelist.
\ No newline at end of file
diff --git a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java
index ae7eac3f0..06ec4a4a6 100644
--- a/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java
+++ b/codec/codec-sofa-hessian/src/main/java/com/alipay/sofa/rpc/codec/sofahessian/SofaHessianSerializer.java
@@ -19,6 +19,7 @@
import com.alipay.hessian.ClassNameResolver;
import com.alipay.hessian.NameBlackListFilter;
import com.alipay.sofa.rpc.codec.AbstractSerializer;
+import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader;
import com.alipay.sofa.rpc.codec.sofahessian.serialize.CustomHessianSerializer;
import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaRequestHessianSerializer;
import com.alipay.sofa.rpc.codec.sofahessian.serialize.SofaResponseHessianSerializer;
@@ -95,7 +96,7 @@ public SofaHessianSerializer() {
if (RpcConfigs.getBooleanValue(RpcOptions.SERIALIZE_BLACKLIST_ENABLE) &&
SofaConfigs.getBooleanValue(SofaOptions.CONFIG_SERIALIZE_BLACKLIST, true)) {
ClassNameResolver resolver = new ClassNameResolver();
- resolver.addFilter(new NameBlackListFilter(BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192));
+ resolver.addFilter(new NameBlackListFilter(BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST, 8192));
serializerFactory.setClassNameResolver(resolver);
genericSerializerFactory.setClassNameResolver(resolver);
} else {
diff --git a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java
similarity index 71%
rename from codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java
rename to codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java
index df934b6a1..05d279e4f 100644
--- a/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackListFileLoaderTest.java
+++ b/codec/codec-sofa-hessian/src/test/java/com/alipay/sofa/rpc/codec/sofahessian/BlackAndWhiteListFileLoaderTest.java
@@ -17,6 +17,7 @@
package com.alipay.sofa.rpc.codec.sofahessian;
import com.alipay.hessian.NameBlackListFilter;
+import com.alipay.sofa.rpc.codec.common.BlackAndWhiteListFileLoader;
import com.alipay.sofa.rpc.common.SofaOptions;
import org.junit.Assert;
import org.junit.Test;
@@ -29,17 +30,17 @@
*
* @author GengZhang
*/
-public class BlackListFileLoaderTest {
+public class BlackAndWhiteListFileLoaderTest {
@Test
public void testAll() throws Exception {
- List blacks = BlackListFileLoader.SOFA_SERIALIZE_BLACK_LIST;
+ List blacks = BlackAndWhiteListFileLoader.SOFA_SERIALIZE_BLACK_LIST;
Assert.assertNotNull(blacks);
String s = System.getProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE);
try {
System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, "-java.net.Socket");
- blacks = BlackListFileLoader.loadFile("/sofa-rpc/serialize_blacklist.txt");
+ blacks = BlackAndWhiteListFileLoader.loadBlackListFile("/sofa-rpc/serialize_blacklist.txt");
} finally {
if (s != null) {
System.setProperty(SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE, s);
@@ -69,51 +70,51 @@ public void testAll() throws Exception {
@Test
public void overrideBlackList() {
List origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-*");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*");
Assert.assertTrue(origin.size() == 0);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "!*");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "!*");
Assert.assertTrue(origin.size() == 0);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-default");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-default");
Assert.assertTrue(origin.size() == 0);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "!default");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "!default");
Assert.assertTrue(origin.size() == 0);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-*,-com.xxx");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,-com.xxx");
Assert.assertTrue(origin.size() == 0);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "aaa,-*,-com.xxx");
Assert.assertTrue(origin.size() == 1);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-*,aaa");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-*,aaa");
Assert.assertTrue(origin.size() == 1);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-com.xxx");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx");
Assert.assertTrue(origin.size() == 2);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "-com.xxx,-com.yyy");
Assert.assertTrue(origin.size() == 1);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx,-com.yyy");
Assert.assertTrue(origin.size() == 2);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,-com.yyy");
Assert.assertTrue(origin.size() == 3);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "com.aaa");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa");
Assert.assertTrue(origin.size() == 4);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.xxx;com.yyy;com.zzz");
Assert.assertTrue(origin.size() == 3);
origin = buildOriginList();
- BlackListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc");
+ BlackAndWhiteListFileLoader.overrideBlackList(origin, "com.aaa,com.bbb,com.ccc");
Assert.assertTrue(origin.size() == 6);
}
diff --git a/codec/pom.xml b/codec/pom.xml
index 2ca5db8c2..25814b811 100644
--- a/codec/pom.xml
+++ b/codec/pom.xml
@@ -20,6 +20,7 @@
codec-protostuff
codec-sofa-hessian
codec-msgpack
+ codec-sofa-fury
diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java
index 0b9ebc0eb..efe20c953 100644
--- a/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java
+++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/AbstractSerializer.java
@@ -33,6 +33,8 @@ public abstract class AbstractSerializer implements Serializer {
protected static Map genericServiceMap = new ConcurrentHashMap<>();
+ protected Map customSerializers = new ConcurrentHashMap<>();
+
protected SofaRpcException buildSerializeError(String message) {
return new SofaRpcException(getErrorCode(true), LogCodes.getLog(LogCodes.ERROR_SERIALIZER, message));
}
@@ -73,4 +75,19 @@ public static void registerGenericService(String serviceName, String className)
public static void clear() {
genericServiceMap.clear();
}
+
+ protected CustomSerializer getObjCustomSerializer(Object obj) {
+ if (obj == null) {
+ return null;
+ }
+ return getSerializer(obj.getClass());
+ }
+
+ protected CustomSerializer getSerializer(Class clazz) {
+ return customSerializers.get(clazz);
+ }
+
+ protected void addSerializer(Class clazz, CustomSerializer serializerManager) {
+ customSerializers.put(clazz, serializerManager);
+ }
}
diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java
new file mode 100644
index 000000000..42a4f6398
--- /dev/null
+++ b/core/api/src/main/java/com/alipay/sofa/rpc/codec/CustomSerializer.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.alipay.sofa.rpc.codec;
+
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.transport.AbstractByteBuf;
+
+import java.util.Map;
+
+/**
+ * @author leizhiyuan
+ */
+public interface CustomSerializer {
+
+ /**
+ * 序列化
+ *
+ * @param object 对象
+ * @param context 上下文
+ * @return 序列化后的对象
+ * @throws SofaRpcException 序列化异常
+ */
+ public AbstractByteBuf encodeObject(T object, Map context) throws SofaRpcException;
+
+ /**
+ * 反序列化,只有类型,返回对象
+ *
+ * @param data 原始字节数组
+ * @param context 上下文
+ * @return 反序列化后的对象
+ * @throws SofaRpcException 序列化异常
+ */
+ public T decodeObject(AbstractByteBuf data, Map context) throws SofaRpcException;
+
+ /**
+ * 反序列化,已有数据,填充字段
+ *
+ * @param data 原始字节数组
+ * @param template 模板对象
+ * @param context 上下文
+ * @throws SofaRpcException 序列化异常
+ */
+ public void decodeObjectByTemplate(AbstractByteBuf data, Map context, T template)
+ throws SofaRpcException;
+
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java
index 8deb9200f..0e36f2365 100644
--- a/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java
+++ b/core/api/src/main/java/com/alipay/sofa/rpc/ext/ExtensionLoader.java
@@ -34,6 +34,7 @@
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@@ -184,7 +185,7 @@ protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName)
}
BufferedReader reader = null;
try {
- reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
+ reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
readLine(url, line);
diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java
index ae46681d5..4a9e1753c 100644
--- a/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java
+++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/SofaOptions.java
@@ -160,6 +160,10 @@ public class SofaOptions {
* 序列化覆盖
*/
public static final String CONFIG_SERIALIZE_BLACKLIST_OVERRIDE = "rpc_serialize_blacklist_override";
+ /**
+ * 序列化覆盖
+ */
+ public static final String CONFIG_SERIALIZE_WHITELIST_OVERRIDE = "rpc_serialize_whitelist_override";
//========= GRPC 相关配置 ==========
/**
diff --git a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java
index 009c35dbd..99910012b 100644
--- a/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java
+++ b/core/common/src/main/java/com/alipay/sofa/rpc/common/config/RpcConfigKeys.java
@@ -18,6 +18,9 @@
import com.alipay.sofa.common.config.ConfigKey;
+import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_BLACKLIST_OVERRIDE;
+import static com.alipay.sofa.rpc.common.SofaOptions.CONFIG_SERIALIZE_WHITELIST_OVERRIDE;
+
/**
* @author zhaowang
* @version : RpcConfigKeys.java, v 0.1 2020年12月14日 9:56 下午 zhaowang Exp $
@@ -102,6 +105,31 @@ public class RpcConfigKeys {
false,
"judge the generic object exception fields.",
new String[] { "sofa_rpc_generic_exception_fields" });
+
+ public static final ConfigKey SERIALIZE_BLACKLIST_OVERRIDE = ConfigKey
+ .build(
+ "sofa.rpc.serialize.blacklist.override",
+ "",
+ false,
+ "Additional serialization blacklist.",
+ new String[] { CONFIG_SERIALIZE_BLACKLIST_OVERRIDE });
+
+ public static final ConfigKey SERIALIZE_WHITELIST_OVERRIDE = ConfigKey
+ .build(
+ "sofa.rpc.serialize.whitelist.override",
+ "",
+ false,
+ "Additional serialization whitelist.",
+ new String[] { CONFIG_SERIALIZE_WHITELIST_OVERRIDE });
+
+ public static final ConfigKey SERIALIZE_CHECKER_MODE = ConfigKey
+ .build(
+ "sofa.rpc.codec.serialize.checkMode",
+ "STRICT",
+ true,
+ " The default filtering mode is STRICT.You can also set WARN or DISABLE",
+ new String[] { "sofa_rpc_codec_serialize_checkMode" });
+
/**
* biz thread pool type
*/
diff --git a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json
index 9becfcf3f..6ad8f836f 100644
--- a/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json
+++ b/core/common/src/main/resources/com/alipay/sofa/rpc/common/rpc-config-default.json
@@ -17,7 +17,7 @@ PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支
"META-INF/services/"
],
// 需要被加载的模块列表,多个用逗号隔开
- "module.load.list" : "*",
+ "module.load.list": "*",
/*-------------RPC框架内部使用配置项-------------*/