}\r
return map;\r
}\r
+ \r
+ /**\r
+ * get simple class name from qualified class name\r
+ */\r
+ public static String getSimpleClassName(String qualifiedName) {\r
+ if (null == qualifiedName) {\r
+ return null;\r
+ }\r
+ \r
+ int i = qualifiedName.lastIndexOf('.');\r
+ return i < 0 ? qualifiedName : qualifiedName.substring(i + 1);\r
+ }\r
\r
}\r
--- /dev/null
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.dubbo.common.compiler.support;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import javassist.CannotCompileException;\r
+import javassist.ClassPool;\r
+import javassist.CtClass;\r
+import javassist.CtField;\r
+import javassist.CtNewConstructor;\r
+import javassist.CtNewMethod;\r
+import javassist.LoaderClassPath;\r
+import javassist.NotFoundException;\r
+\r
+/**\r
+ * CtClassBuilder is builder for CtClass\r
+ * <p>\r
+ * contains all the information, including:\r
+ * <p>\r
+ * class name, imported packages, super class name, implemented interfaces, constructors, fields, methods.\r
+ */\r
+public class CtClassBuilder {\r
+\r
+ private String className;\r
+\r
+ private String superClassName = "java.lang.Object";\r
+\r
+ private List<String> imports = new ArrayList<>();\r
+\r
+ private Map<String, String> fullNames = new HashMap<>();\r
+\r
+ private List<String> ifaces = new ArrayList<>();\r
+\r
+ private List<String> constructors = new ArrayList<>();\r
+\r
+ private List<String> fields = new ArrayList<>();\r
+\r
+ private List<String> methods = new ArrayList<>();\r
+\r
+ public String getClassName() {\r
+ return className;\r
+ }\r
+\r
+ public void setClassName(String className) {\r
+ this.className = className;\r
+ }\r
+\r
+ public String getSuperClassName() {\r
+ return superClassName;\r
+ }\r
+\r
+ public void setSuperClassName(String superClassName) {\r
+ this.superClassName = getQualifiedClassName(superClassName);\r
+ }\r
+\r
+ public List<String> getImports() {\r
+ return imports;\r
+ }\r
+\r
+ public void addImports(String pkg) {\r
+ int pi = pkg.lastIndexOf('.');\r
+ if (pi > 0) {\r
+ String pkgName = pkg.substring(0, pi);\r
+ this.imports.add(pkgName);\r
+ if (!pkg.endsWith(".*")) {\r
+ fullNames.put(pkg.substring(pi + 1), pkg);\r
+ }\r
+ }\r
+ }\r
+\r
+ public List<String> getInterfaces() {\r
+ return ifaces;\r
+ }\r
+\r
+ public void addInterface(String iface) {\r
+ this.ifaces.add(getQualifiedClassName(iface));\r
+ }\r
+\r
+ public List<String> getConstructors() {\r
+ return constructors;\r
+ }\r
+\r
+ public void addConstructor(String constructor) {\r
+ this.constructors.add(constructor);\r
+ }\r
+\r
+ public List<String> getFields() {\r
+ return fields;\r
+ }\r
+\r
+ public void addField(String field) {\r
+ this.fields.add(field);\r
+ }\r
+\r
+ public List<String> getMethods() {\r
+ return methods;\r
+ }\r
+\r
+ public void addMethod(String method) {\r
+ this.methods.add(method);\r
+ }\r
+\r
+ /**\r
+ * get full qualified class name\r
+ * \r
+ * @param className super class name, maybe qualified or not\r
+ */\r
+ protected String getQualifiedClassName(String className) {\r
+ if (className.contains(".")) {\r
+ return className;\r
+ }\r
+\r
+ if (fullNames.containsKey(className)) {\r
+ return fullNames.get(className);\r
+ }\r
+\r
+ return ClassUtils.forName(imports.toArray(new String[0]), className).getName();\r
+ }\r
+\r
+ /**\r
+ * build CtClass object\r
+ */\r
+ public CtClass build(ClassLoader classLoader) throws NotFoundException, CannotCompileException {\r
+ ClassPool pool = new ClassPool(true);\r
+ pool.appendClassPath(new LoaderClassPath(classLoader));\r
+ \r
+ // create class\r
+ CtClass ctClass = pool.makeClass(className, pool.get(superClassName));\r
+\r
+ // add imported packages\r
+ imports.stream().forEach(pool::importPackage);\r
+\r
+ // add implemented interfaces\r
+ for (String iface : ifaces) {\r
+ ctClass.addInterface(pool.get(iface));\r
+ }\r
+\r
+ // add constructors\r
+ for (String constructor : constructors) {\r
+ ctClass.addConstructor(CtNewConstructor.make(constructor, ctClass));\r
+ }\r
+\r
+ // add fields\r
+ for (String field : fields) {\r
+ ctClass.addField(CtField.make(field, ctClass));\r
+ }\r
+\r
+ // add methods\r
+ for (String method : methods) {\r
+ ctClass.addMethod(CtNewMethod.make(method, ctClass));\r
+ }\r
+\r
+ return ctClass;\r
+ }\r
+\r
+}\r
\r
import org.apache.dubbo.common.utils.ClassHelper;\r
\r
-import javassist.ClassPool;\r
import javassist.CtClass;\r
-import javassist.CtField;\r
-import javassist.CtNewConstructor;\r
-import javassist.CtNewMethod;\r
-import javassist.LoaderClassPath;\r
\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
+import java.util.Arrays;\r
import java.util.regex.Matcher;\r
import java.util.regex.Pattern;\r
\r
\r
@Override\r
public Class<?> doCompile(String name, String source) throws Throwable {\r
- int i = name.lastIndexOf('.');\r
- String className = i < 0 ? name : name.substring(i + 1);\r
- ClassPool pool = new ClassPool(true);\r
- pool.appendClassPath(new LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));\r
+ CtClassBuilder builder = new CtClassBuilder();\r
+ builder.setClassName(name);\r
+\r
+ // process imported classes\r
Matcher matcher = IMPORT_PATTERN.matcher(source);\r
- List<String> importPackages = new ArrayList<String>();\r
- Map<String, String> fullNames = new HashMap<String, String>();\r
while (matcher.find()) {\r
- String pkg = matcher.group(1);\r
- if (pkg.endsWith(".*")) {\r
- String pkgName = pkg.substring(0, pkg.length() - 2);\r
- pool.importPackage(pkgName);\r
- importPackages.add(pkgName);\r
- } else {\r
- int pi = pkg.lastIndexOf('.');\r
- if (pi > 0) {\r
- String pkgName = pkg.substring(0, pi);\r
- pool.importPackage(pkgName);\r
- importPackages.add(pkgName);\r
- fullNames.put(pkg.substring(pi + 1), pkg);\r
- }\r
- }\r
+ builder.addImports(matcher.group(1).trim());\r
}\r
- String[] packages = importPackages.toArray(new String[0]);\r
+ \r
+ // process extended super class\r
matcher = EXTENDS_PATTERN.matcher(source);\r
- CtClass cls;\r
if (matcher.find()) {\r
- String extend = matcher.group(1).trim();\r
- String extendClass;\r
- if (extend.contains(".")) {\r
- extendClass = extend;\r
- } else if (fullNames.containsKey(extend)) {\r
- extendClass = fullNames.get(extend);\r
- } else {\r
- extendClass = ClassUtils.forName(packages, extend).getName();\r
- }\r
- cls = pool.makeClass(name, pool.get(extendClass));\r
- } else {\r
- cls = pool.makeClass(name);\r
+ builder.setSuperClassName(matcher.group(1).trim());\r
}\r
+ \r
+ // process implemented interfaces\r
matcher = IMPLEMENTS_PATTERN.matcher(source);\r
if (matcher.find()) {\r
String[] ifaces = matcher.group(1).trim().split("\\,");\r
- for (String iface : ifaces) {\r
- iface = iface.trim();\r
- String ifaceClass;\r
- if (iface.contains(".")) {\r
- ifaceClass = iface;\r
- } else if (fullNames.containsKey(iface)) {\r
- ifaceClass = fullNames.get(iface);\r
- } else {\r
- ifaceClass = ClassUtils.forName(packages, iface).getName();\r
- }\r
- cls.addInterface(pool.get(ifaceClass));\r
- }\r
+ Arrays.stream(ifaces).forEach(i -> builder.addInterface(i.trim()));\r
}\r
- String body = source.substring(source.indexOf("{") + 1, source.length() - 1);\r
+ \r
+ // process constructors, fields, methods\r
+ String body = source.substring(source.indexOf('{') + 1, source.length() - 1);\r
String[] methods = METHODS_PATTERN.split(body);\r
- for (String method : methods) {\r
- method = method.trim();\r
- if (method.length() > 0) {\r
- if (method.startsWith(className)) {\r
- cls.addConstructor(CtNewConstructor.make("public " + method, cls));\r
- } else if (FIELD_PATTERN.matcher(method).matches()) {\r
- cls.addField(CtField.make("private " + method, cls));\r
- } else {\r
- cls.addMethod(CtNewMethod.make("public " + method, cls));\r
- }\r
+ String className = ClassUtils.getSimpleClassName(name);\r
+ Arrays.stream(methods).map(String::trim).filter(m -> !m.isEmpty()).forEach(method-> {\r
+ if (method.startsWith(className)) {\r
+ builder.addConstructor("public " + method);\r
+ } else if (FIELD_PATTERN.matcher(method).matches()) {\r
+ builder.addField("private " + method);\r
+ } else {\r
+ builder.addMethod("public " + method);\r
}\r
- }\r
- return cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());\r
+ });\r
+ \r
+ // compile\r
+ ClassLoader classLoader = ClassHelper.getCallerClassLoader(getClass());\r
+ CtClass cls = builder.build(classLoader);\r
+ return cls.toClass(classLoader, JavassistCompiler.class.getProtectionDomain());\r
}\r
\r
}\r
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> {
}