This is an automated email from the ASF dual-hosted git repository.
iluo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
The following commit(s) were added to refs/heads/master by this push:
new caac0b5 refactor javassist compiler: extract class CtClassBuilder
(#3424)
caac0b5 is described below
commit caac0b573c8f87d0147983c149d5f7d96db2b20c
Author: wanghbxxxx <[email protected]>
AuthorDate: Mon Feb 11 16:44:41 2019 +0800
refactor javassist compiler: extract class CtClassBuilder (#3424)
* refactor JavassistCompiler
* rename variable names
* reformat code
* refactor: prepend modifier of constructor, field and method outside the
JavassistClassInfo
* add null for ClassUtils.getSimpleClassName
* rename JavassistClassInfo to CtClassBuilder
---
.../dubbo/common/compiler/support/ClassUtils.java | 12 ++
.../common/compiler/support/CtClassBuilder.java | 174 +++++++++++++++++++++
.../common/compiler/support/JavassistCompiler.java | 97 ++++--------
.../common/compiler/support/ClassUtilsTest.java | 7 +
4 files changed, 222 insertions(+), 68 deletions(-)
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
index 5d3cdad..365cb7f 100644
---
a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
+++
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
@@ -431,5 +431,17 @@ public class ClassUtils {
}
return map;
}
+
+ /**
+ * get simple class name from qualified class name
+ */
+ public static String getSimpleClassName(String qualifiedName) {
+ if (null == qualifiedName) {
+ return null;
+ }
+
+ int i = qualifiedName.lastIndexOf('.');
+ return i < 0 ? qualifiedName : qualifiedName.substring(i + 1);
+ }
}
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
new file mode 100644
index 0000000..0dc8f88
--- /dev/null
+++
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/CtClassBuilder.java
@@ -0,0 +1,174 @@
+/*
+ * 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.dubbo.common.compiler.support;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+import javassist.LoaderClassPath;
+import javassist.NotFoundException;
+
+/**
+ * CtClassBuilder is builder for CtClass
+ * <p>
+ * contains all the information, including:
+ * <p>
+ * class name, imported packages, super class name, implemented interfaces,
constructors, fields, methods.
+ */
+public class CtClassBuilder {
+
+ private String className;
+
+ private String superClassName = "java.lang.Object";
+
+ private List<String> imports = new ArrayList<>();
+
+ private Map<String, String> fullNames = new HashMap<>();
+
+ private List<String> ifaces = new ArrayList<>();
+
+ private List<String> constructors = new ArrayList<>();
+
+ private List<String> fields = new ArrayList<>();
+
+ private List<String> methods = new ArrayList<>();
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getSuperClassName() {
+ return superClassName;
+ }
+
+ public void setSuperClassName(String superClassName) {
+ this.superClassName = getQualifiedClassName(superClassName);
+ }
+
+ public List<String> getImports() {
+ return imports;
+ }
+
+ public void addImports(String pkg) {
+ int pi = pkg.lastIndexOf('.');
+ if (pi > 0) {
+ String pkgName = pkg.substring(0, pi);
+ this.imports.add(pkgName);
+ if (!pkg.endsWith(".*")) {
+ fullNames.put(pkg.substring(pi + 1), pkg);
+ }
+ }
+ }
+
+ public List<String> getInterfaces() {
+ return ifaces;
+ }
+
+ public void addInterface(String iface) {
+ this.ifaces.add(getQualifiedClassName(iface));
+ }
+
+ public List<String> getConstructors() {
+ return constructors;
+ }
+
+ public void addConstructor(String constructor) {
+ this.constructors.add(constructor);
+ }
+
+ public List<String> getFields() {
+ return fields;
+ }
+
+ public void addField(String field) {
+ this.fields.add(field);
+ }
+
+ public List<String> getMethods() {
+ return methods;
+ }
+
+ public void addMethod(String method) {
+ this.methods.add(method);
+ }
+
+ /**
+ * get full qualified class name
+ *
+ * @param className super class name, maybe qualified or not
+ */
+ protected String getQualifiedClassName(String className) {
+ if (className.contains(".")) {
+ return className;
+ }
+
+ if (fullNames.containsKey(className)) {
+ return fullNames.get(className);
+ }
+
+ return ClassUtils.forName(imports.toArray(new String[0]),
className).getName();
+ }
+
+ /**
+ * build CtClass object
+ */
+ public CtClass build(ClassLoader classLoader) throws NotFoundException,
CannotCompileException {
+ ClassPool pool = new ClassPool(true);
+ pool.appendClassPath(new LoaderClassPath(classLoader));
+
+ // create class
+ CtClass ctClass = pool.makeClass(className, pool.get(superClassName));
+
+ // add imported packages
+ imports.stream().forEach(pool::importPackage);
+
+ // add implemented interfaces
+ for (String iface : ifaces) {
+ ctClass.addInterface(pool.get(iface));
+ }
+
+ // add constructors
+ for (String constructor : constructors) {
+ ctClass.addConstructor(CtNewConstructor.make(constructor,
ctClass));
+ }
+
+ // add fields
+ for (String field : fields) {
+ ctClass.addField(CtField.make(field, ctClass));
+ }
+
+ // add methods
+ for (String method : methods) {
+ ctClass.addMethod(CtNewMethod.make(method, ctClass));
+ }
+
+ return ctClass;
+ }
+
+}
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
index 5beb8e4..11f76b1 100644
---
a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
+++
b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
@@ -18,17 +18,9 @@ package org.apache.dubbo.common.compiler.support;
import org.apache.dubbo.common.utils.ClassHelper;
-import javassist.ClassPool;
import javassist.CtClass;
-import javassist.CtField;
-import javassist.CtNewConstructor;
-import javassist.CtNewMethod;
-import javassist.LoaderClassPath;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,77 +41,46 @@ public class JavassistCompiler extends AbstractCompiler {
@Override
public Class<?> doCompile(String name, String source) throws Throwable {
- int i = name.lastIndexOf('.');
- String className = i < 0 ? name : name.substring(i + 1);
- ClassPool pool = new ClassPool(true);
- pool.appendClassPath(new
LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));
+ CtClassBuilder builder = new CtClassBuilder();
+ builder.setClassName(name);
+
+ // process imported classes
Matcher matcher = IMPORT_PATTERN.matcher(source);
- List<String> importPackages = new ArrayList<String>();
- Map<String, String> fullNames = new HashMap<String, String>();
while (matcher.find()) {
- String pkg = matcher.group(1);
- if (pkg.endsWith(".*")) {
- String pkgName = pkg.substring(0, pkg.length() - 2);
- pool.importPackage(pkgName);
- importPackages.add(pkgName);
- } else {
- int pi = pkg.lastIndexOf('.');
- if (pi > 0) {
- String pkgName = pkg.substring(0, pi);
- pool.importPackage(pkgName);
- importPackages.add(pkgName);
- fullNames.put(pkg.substring(pi + 1), pkg);
- }
- }
+ builder.addImports(matcher.group(1).trim());
}
- String[] packages = importPackages.toArray(new String[0]);
+
+ // process extended super class
matcher = EXTENDS_PATTERN.matcher(source);
- CtClass cls;
if (matcher.find()) {
- String extend = matcher.group(1).trim();
- String extendClass;
- if (extend.contains(".")) {
- extendClass = extend;
- } else if (fullNames.containsKey(extend)) {
- extendClass = fullNames.get(extend);
- } else {
- extendClass = ClassUtils.forName(packages, extend).getName();
- }
- cls = pool.makeClass(name, pool.get(extendClass));
- } else {
- cls = pool.makeClass(name);
+ builder.setSuperClassName(matcher.group(1).trim());
}
+
+ // process implemented interfaces
matcher = IMPLEMENTS_PATTERN.matcher(source);
if (matcher.find()) {
String[] ifaces = matcher.group(1).trim().split("\\,");
- for (String iface : ifaces) {
- iface = iface.trim();
- String ifaceClass;
- if (iface.contains(".")) {
- ifaceClass = iface;
- } else if (fullNames.containsKey(iface)) {
- ifaceClass = fullNames.get(iface);
- } else {
- ifaceClass = ClassUtils.forName(packages, iface).getName();
- }
- cls.addInterface(pool.get(ifaceClass));
- }
+ Arrays.stream(ifaces).forEach(i -> builder.addInterface(i.trim()));
}
- String body = source.substring(source.indexOf("{") + 1,
source.length() - 1);
+
+ // process constructors, fields, methods
+ String body = source.substring(source.indexOf('{') + 1,
source.length() - 1);
String[] methods = METHODS_PATTERN.split(body);
- for (String method : methods) {
- method = method.trim();
- if (method.length() > 0) {
- if (method.startsWith(className)) {
- cls.addConstructor(CtNewConstructor.make("public " +
method, cls));
- } else if (FIELD_PATTERN.matcher(method).matches()) {
- cls.addField(CtField.make("private " + method, cls));
- } else {
- cls.addMethod(CtNewMethod.make("public " + method, cls));
- }
+ String className = ClassUtils.getSimpleClassName(name);
+ Arrays.stream(methods).map(String::trim).filter(m ->
!m.isEmpty()).forEach(method-> {
+ if (method.startsWith(className)) {
+ builder.addConstructor("public " + method);
+ } else if (FIELD_PATTERN.matcher(method).matches()) {
+ builder.addField("private " + method);
+ } else {
+ builder.addMethod("public " + method);
}
- }
- return cls.toClass(ClassHelper.getCallerClassLoader(getClass()),
JavassistCompiler.class.getProtectionDomain());
+ });
+
+ // compile
+ ClassLoader classLoader = ClassHelper.getCallerClassLoader(getClass());
+ CtClass cls = builder.build(classLoader);
+ return cls.toClass(classLoader,
JavassistCompiler.class.getProtectionDomain());
}
}
diff --git
a/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/ClassUtilsTest.java
b/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/ClassUtilsTest.java
index 2ebf668..8acf00b 100644
---
a/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/ClassUtilsTest.java
+++
b/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/ClassUtilsTest.java
@@ -146,6 +146,13 @@ public class ClassUtilsTest {
public void testGetSizeMethod() {
Assertions.assertEquals("getLength()",
ClassUtils.getSizeMethod(GenericClass3.class));
}
+
+ @Test
+ public void testGetSimpleClassName() {
+ Assertions.assertNull(ClassUtils.getSimpleClassName(null));
+ Assertions.assertEquals("Map",
ClassUtils.getSimpleClassName(Map.class.getName()));
+ Assertions.assertEquals("Map",
ClassUtils.getSimpleClassName(Map.class.getSimpleName()));
+ }
private interface GenericInterface<T> {
}