You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/01/20 06:01:42 UTC
[incubator-servicecomb-java-chassis] 03/10: SCB-266 fix bug:
dynamic enum must not determined out of classload
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit 413db6ec43511eff29a9a915141e16f9c7ce5f7a
Author: wujimin <wu...@huawei.com>
AuthorDate: Sat Jan 20 01:56:24 2018 +0800
SCB-266 fix bug: dynamic enum must not determined out of classload
---
.../common/javassist/JavassistUtils.java | 22 ++++++-
.../common/javassist/TestJavassistUtils.java | 73 ++++++++++++++++++++--
.../property/StringPropertyConverter.java | 31 +--------
3 files changed, 92 insertions(+), 34 deletions(-)
diff --git a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
index f75247f..e369174 100644
--- a/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
+++ b/common/common-javassist/src/main/java/org/apache/servicecomb/common/javassist/JavassistUtils.java
@@ -20,6 +20,7 @@ package org.apache.servicecomb.common.javassist;
import static java.util.Locale.ENGLISH;
import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
@@ -30,6 +31,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;
import com.fasterxml.jackson.databind.JavaType;
+import com.google.common.hash.Hashing;
import javassist.CannotCompileException;
import javassist.ClassPool;
@@ -82,6 +84,25 @@ public final class JavassistUtils {
return createEnum(null, clsName, values);
}
+ @SuppressWarnings("rawtypes")
+ public static Class<? extends Enum> getOrCreateEnumWithPackageName(ClassLoader classLoader, String packageName,
+ List<String> enums) {
+ String strEnums = enums.toString();
+ String enumClsName =
+ packageName + ".Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8).toString();
+ return JavassistUtils.getOrCreateEnumWithClassName(classLoader, enumClsName, enums);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static synchronized Class<? extends Enum> getOrCreateEnumWithClassName(ClassLoader classLoader, String clsName,
+ List<String> values) {
+ try {
+ return (Class<? extends Enum>) classLoader.loadClass(clsName);
+ } catch (ClassNotFoundException e) {
+ return createEnum(classLoader, clsName, values);
+ }
+ }
+
@SuppressWarnings({"rawtypes", "unchecked"})
public static Class<? extends Enum> createEnum(ClassLoader classLoader, String clsName, List<String> values) {
if (values == null || values.size() == 0) {
@@ -148,7 +169,6 @@ public final class JavassistUtils {
if (config.isIntf()) {
ctClass = classPool.makeInterface(config.getClassName());
} else {
-
ctClass = classPool.makeClass(config.getClassName());
}
}
diff --git a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java b/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java
index f7f11bb..73c4c7f 100644
--- a/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java
+++ b/common/common-javassist/src/test/java/org/apache/servicecomb/common/javassist/TestJavassistUtils.java
@@ -18,18 +18,24 @@
package org.apache.servicecomb.common.javassist;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.ws.rs.core.Response.Status;
+
import org.apache.servicecomb.foundation.common.utils.ReflectUtils;
import org.junit.Assert;
import org.junit.Test;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.google.common.hash.Hashing;
import javassist.ClassPool;
import mockit.Deencapsulation;
@@ -161,13 +167,70 @@ public class TestJavassistUtils {
}
@Test
+ public void getOrCreateEnumWithClassName_get() {
+ Class<?> cls = Status.class;
+
+ Assert.assertSame(cls,
+ JavassistUtils.getOrCreateEnumWithClassName(Thread.currentThread().getContextClassLoader(),
+ Status.class.getName(),
+ null));
+ }
+
+ @Test
+ public void getOrCreateEnumWithClassName_create()
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ String name = "cse.ut.EnumAbc";
+ Assert.assertNull(ClassPool.getDefault().getOrNull(name));
+
+ @SuppressWarnings("rawtypes")
+ Class<? extends Enum> cls =
+ JavassistUtils
+ .getOrCreateEnumWithClassName(Thread.currentThread().getContextClassLoader(),
+ name,
+ Arrays.asList("a", "b"));
+ checkEnum(name, cls);
+ }
+
+ @Test
+ public void getOrCreateEnumWithPackageName()
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ List<String> enums = Arrays.asList("a", "b");
+ String packageName = "cse.ut";
+ String clsName =
+ packageName + ".Enum_" + Hashing.sha256().hashString(enums.toString(), StandardCharsets.UTF_8).toString();
+ Assert.assertNull(ClassPool.getDefault().getOrNull(clsName));
+
+ @SuppressWarnings("rawtypes")
+ Class<? extends Enum> cls =
+ JavassistUtils
+ .getOrCreateEnumWithPackageName(Thread.currentThread().getContextClassLoader(),
+ packageName,
+ Arrays.asList("a", "b"));
+
+ checkEnum(clsName, cls);
+ Assert.assertSame(cls,
+ JavassistUtils
+ .getOrCreateEnumWithPackageName(Thread.currentThread().getContextClassLoader(),
+ packageName,
+ Arrays.asList("a", "b")));
+
+ }
+
+ @Test
public void testEnum() throws Exception {
+ String name = "cse.ut.EnumAbc2";
@SuppressWarnings("rawtypes")
- Class<? extends Enum> cls = JavassistUtils.createEnum("cse.ut.EnumAbc", "a", "b");
+ Class<? extends Enum> cls = JavassistUtils.createEnum(name, "a", "b");
+ checkEnum(name, cls);
+ }
+
+ @SuppressWarnings("rawtypes")
+ protected void checkEnum(String expectName, Class<? extends Enum> cls)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method method = cls.getMethod("values");
Enum<?>[] values = (Enum<?>[]) method.invoke(null);
- Assert.assertEquals("cse.ut.EnumAbc", cls.getName());
+ Assert.assertEquals(expectName, cls.getName());
Assert.assertEquals(2, values.length);
Assert.assertEquals("a", values[0].name());
Assert.assertEquals(0, values[0].ordinal());
@@ -192,8 +255,10 @@ public class TestJavassistUtils {
@Test
public void managerClassPool() {
- ClassLoader classLoader1 = new ClassLoader() { };
- ClassLoader classLoader2 = new ClassLoader() { };
+ ClassLoader classLoader1 = new ClassLoader() {
+ };
+ ClassLoader classLoader2 = new ClassLoader() {
+ };
ClassPool p1 = Deencapsulation.invoke(JavassistUtils.class, "getOrCreateClassPool", classLoader1);
ClassPool p2 = Deencapsulation.invoke(JavassistUtils.class, "getOrCreateClassPool", classLoader2);
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java
index a4372a1..b34272c 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java
@@ -17,9 +17,7 @@
package org.apache.servicecomb.swagger.converter.property;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.apache.servicecomb.common.javassist.JavassistUtils;
import org.apache.servicecomb.swagger.converter.ConverterMgr;
@@ -31,32 +29,6 @@ import io.swagger.models.Swagger;
import io.swagger.models.properties.StringProperty;
public class StringPropertyConverter extends AbstractPropertyConverter {
- // 用于生成唯一的enum名称
- // key为enum names, value为enum cls javaType
- private static Map<String, JavaType> enumMap = new HashMap<>();
-
- private static final Object LOCK = new Object();
-
- // 转换并创建enum是小概率事件,没必要double check
- private static JavaType getOrCreateEnumByNames(ClassLoader classLoader, String packageName, List<String> enums) {
- String strEnums = enums.toString();
-
- synchronized (LOCK) {
- JavaType javaType = enumMap.get(strEnums);
- if (javaType != null) {
- return javaType;
- }
-
- String enumClsName = packageName + ".Enum" + enumMap.size();
- @SuppressWarnings("rawtypes")
- Class<? extends Enum> enumCls = JavassistUtils.createEnum(classLoader, enumClsName, enums);
- javaType = TypeFactory.defaultInstance().constructType(enumCls);
- enumMap.put(strEnums, javaType);
-
- return javaType;
- }
- }
-
public static JavaType findJavaType(ClassLoader classLoader, String packageName, Swagger swagger, String type,
String format, List<String> enums) {
if (!isEnum(enums)) {
@@ -64,7 +36,8 @@ public class StringPropertyConverter extends AbstractPropertyConverter {
}
// enum,且需要动态生成class
- return getOrCreateEnumByNames(classLoader, packageName, enums);
+ Class<?> enumCls = JavassistUtils.getOrCreateEnumWithPackageName(classLoader, packageName, enums);
+ return TypeFactory.defaultInstance().constructType(enumCls);
}
public static boolean isEnum(StringProperty stringProperty) {
--
To stop receiving notification emails like this one, please contact
"commits@servicecomb.apache.org" <co...@servicecomb.apache.org>.