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 <wuji...@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" <commits@servicecomb.apache.org>.