最近有个项目需要用到Java中间层和Delphi客户端,中间层和客户端之间的交互用JSON;
大家都知道Java世界里存在着各种各样的实体类,而Delphi端也需要这些实体类的代码,当然通过JNI也是可以访问JAVA代码的,但是这样无疑会带来项目复杂度,因此写了这么个转换工具类。
调用方法:ClassUtil.TransforEntiyToDelphi( ClassUtil.getModelClasses("com.nbport") );
com.nbport是包名,其会扫描包下所有被标记为@Entity的类
1.实现了Java实体类转为Delphi实体类的功能
2.实现了由SuperObject直接映射成为Delphi实体类的功能;
代码很垃圾。。。有空再重构下
package com.nbport.ctos.framework.util; import java.beans.PropertyDescriptor; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import javax.persistence.Entity; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; public class ClassUtil { private static Hashtable< Class<?>,Integer > useEntiy = new Hashtable< Class<?>,Integer >(); private static final String NEWLINE = "\r\n"; public static void TransforEntiyToDelphi(Set<Class<?>> set) throws IOException, InstantiationException, IllegalAccessException { for (Class<?> c : set) { useEntiy.clear(); String className = GetDClassName(c); File file = new File(GetDUintName(c)+".pas"); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file))); BeanWrapper bw = new BeanWrapperImpl(c.newInstance()); PropertyDescriptor[] pds = bw.getPropertyDescriptors(); StringBuffer privateFieldString = new StringBuffer(); StringBuffer publicFieldString = new StringBuffer(); StringBuffer propertyString = new StringBuffer(); StringBuffer methodImpString = new StringBuffer(); StringBuffer createFromJson = new StringBuffer(); StringBuffer destroyString = new StringBuffer(); publicFieldString.append("\t") .append("constructor Create; overload;").append(NEWLINE); publicFieldString .append("\t") .append("constructor Create(obj : ISuperObject); overload;") .append(NEWLINE); publicFieldString .append("\t") .append("destructor Destroy; overload;") .append(NEWLINE); publicFieldString.append("\t") .append("procedure CreateFromJSON(obj : ISuperObject);") .append(NEWLINE); methodImpString.append("constructor ").append(className) .append(".").append("Create").append(";").append(NEWLINE); methodImpString.append("begin").append(NEWLINE).append("\t") .append("inherited Create;").append(NEWLINE).append("end;") .append(NEWLINE); methodImpString.append("constructor ").append(className) .append(".").append("Create(obj : ISuperObject);").append(NEWLINE); methodImpString.append("begin").append(NEWLINE).append("\t") .append("inherited Create;").append(NEWLINE).append("\t") .append("CreateFromJSON(obj);").append(NEWLINE) .append("end;").append(NEWLINE); methodImpString.append(GetDestoryString(destroyString, c)); createFromJson .append("procedure ").append(className).append(".") .append("CreateFromJSON(obj : ISuperObject);").append(NEWLINE); if(IsNeedVarArray(c)){ createFromJson.append("var").append(NEWLINE).append("i : Integer;").append(NEWLINE) .append("jsonArray : TSuperArray;").append(NEWLINE); } createFromJson.append("begin").append(NEWLINE); for (PropertyDescriptor pd : pds) { Method readMethod = pd.getReadMethod(); Method writeMethod = pd.getWriteMethod(); if (readMethod != null && writeMethod != null) { String fieldName = pd.getDisplayName(); String fixedName = "F" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); privateFieldString.append("\t").append(fixedName) .append(" : ") .append(JToD(pd.getPropertyType(),readMethod)) .append(";").append(NEWLINE); publicFieldString .append("\t") .append("procedure " + writeMethod.getName()) .append("(") .append("const Value : " + JToD(writeMethod .getParameterTypes()[0],readMethod)) .append(")").append(";").append(NEWLINE); publicFieldString.append("\t") .append("function " + readMethod.getName()) .append("() : ").append(JToD(readMethod.getReturnType(),readMethod)) .append(";").append(NEWLINE); propertyString.append("\t").append("property ") .append(fieldName.substring(0, 1).toUpperCase()+ fieldName.substring(1)).append(" : ") .append(JToD(pd.getPropertyType(),readMethod)) .append(" read ").append(readMethod.getName()) .append(" write ").append(writeMethod.getName()) .append(";").append(NEWLINE); methodImpString .append("procedure ") .append(className) .append(".") .append(writeMethod.getName()) .append("(") .append("const Value : " + JToD(writeMethod .getParameterTypes()[0],readMethod)) .append(")").append(";").append(NEWLINE); methodImpString.append("begin").append(NEWLINE).append("\t") .append(fixedName).append(" := Value;") .append(NEWLINE).append("end;").append(NEWLINE); methodImpString.append("function ").append(className) .append(".").append(readMethod.getName()) .append("() : ").append(JToD(readMethod.getReturnType(),readMethod)) .append(";").append(NEWLINE); methodImpString.append("begin").append(NEWLINE).append("\t") .append("Result := ").append(fixedName).append(";") .append(NEWLINE).append("end;").append(NEWLINE); GetJsonConvertString(createFromJson,fieldName,fixedName,pd); } } out.write("unit "+GetDUintName(c)+";"); out.newLine(); out.write("interface"); out.newLine(); out.write("uses"); out.newLine(); StringBuffer useUnit = new StringBuffer(); for (Map.Entry<Class<?>,Integer> entry:useEntiy.entrySet()) { String unitName = GetDUintName(entry.getKey()); if (unitName.compareToIgnoreCase(GetDUintName(c))!=0) { useUnit.append(unitName).append(","); } } out.write(useUnit.length()==0?"\tClasses,SysUtils,Contnrs,SuperObject;" :"\tClasses,SysUtils,Contnrs,SuperObject,"+useUnit.substring(0,useUnit.length()-1)+";"); out.newLine(); String typeDefine = GetTypeDefine(c); out.write(typeDefine.length()==0?"":"\ttype"+NEWLINE+typeDefine); out.newLine(); out.write("\ttype"); out.newLine(); out.write("\t\t" + className + " = class(TObject)"); out.newLine(); out.write("private"); out.newLine(); out.write(privateFieldString.toString()); out.newLine(); out.write("public"); out.newLine(); out.write(publicFieldString.toString()); out.newLine(); out.write(propertyString.toString()); out.newLine(); out.write("end;"); out.newLine(); out.write("implementation"); out.newLine(); out.write(methodImpString.toString()); out.write(createFromJson.append("end;").append(NEWLINE).toString()); out.newLine(); out.write("end."); out.newLine(); out.flush(); out.close(); } } private static boolean IsNeedVarArray(Class<?> c) throws InstantiationException, IllegalAccessException { BeanWrapper bw = new BeanWrapperImpl(c.newInstance()); PropertyDescriptor[] pds = bw.getPropertyDescriptors(); for (PropertyDescriptor pd:pds) { if(pd.getPropertyType().getSimpleName().compareToIgnoreCase("list")==0){ Class<?> jClass = GetGenericTypeByGetMethod(pd.getReadMethod()); if (IsEntiyClass(jClass)) { return true; } } } return false; } private static String GetTypeDefine(Class<?> c) throws InstantiationException, IllegalAccessException { BeanWrapper bw = new BeanWrapperImpl(c.newInstance()); PropertyDescriptor[] pds = bw.getPropertyDescriptors(); StringBuffer sb = new StringBuffer(); for (PropertyDescriptor pd:pds) { if(pd.getPropertyType().getSimpleName().compareToIgnoreCase("list")==0){ Class<?> jClass = GetGenericTypeByGetMethod(pd.getReadMethod()); if (IsEntiyClass(jClass)) { sb.append("\t\t").append(GetDClassName(jClass)).append("Array = Array of ").append(GetDClassName(jClass)).append(";"); }else { sb.append("\t\t").append(JToDBasic(jClass)).append("Array = Array of ").append(JToDBasic(jClass)).append(";"); } } } return sb.toString(); } public static Set<Class<?>> getModelClasses(String pack) { Set<Class<?>> set = getClasses(pack); Set<Class<?>> newSet = new LinkedHashSet<Class<?>>(); for (Class<?> c : set) { if (IsEntiyClass(c)) { newSet.add(c); } } return newSet; } public static Set<Class<?>> getClasses(String pack) { // 第一个class类的集合 Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); // 是否循环迭代 boolean recursive = true; // 获取包的名字 并进行替换 String packageName = pack; String packageDirName = packageName.replace('.', '/'); // 定义一个枚举的集合 并进行循环来处理这个目录下的things Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader() .getResources(packageDirName); // 循环迭代下去 while (dirs.hasMoreElements()) { // 获取下一个元素 URL url = dirs.nextElement(); // 得到协议的名称 String protocol = url.getProtocol(); // 如果是以文件的形式保存在服务器上 if ("file".equals(protocol)) { // 获取包的物理路径 String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); // 以文件的方式扫描整个包下的文件 并添加到集合中 findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes); } else if ("jar".equals(protocol)) { // 如果是jar包文件 // 定义一个JarFile JarFile jar; try { // 获取jar jar = ((JarURLConnection) url.openConnection()) .getJarFile(); // 从此jar包 得到一个枚举类 Enumeration<JarEntry> entries = jar.entries(); // 同样的进行循环迭代 while (entries.hasMoreElements()) { // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 JarEntry entry = entries.nextElement(); String name = entry.getName(); // 如果是以/开头的 if (name.charAt(0) == '/') { // 获取后面的字符串 name = name.substring(1); } // 如果前半部分和定义的包名相同 if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); // 如果以"/"结尾 是一个包 if (idx != -1) { // 获取包名 把"/"替换成"." packageName = name.substring(0, idx) .replace('/', '.'); } // 如果可以迭代下去 并且是一个包 if ((idx != -1) || recursive) { // 如果是一个.class文件 而且不是目录 if (name.endsWith(".class") && !entry.isDirectory()) { // 去掉后面的".class" 获取真正的类名 String className = name.substring( packageName.length() + 1, name.length() - 6); try { // 添加到classes classes.add(Class .forName(packageName + '.' + className)); } catch (ClassNotFoundException e) { } } } } } } catch (IOException e) { // log.error("在扫描用户定义视图时从jar包获取文件出错"); e.printStackTrace(); } } } } catch (IOException e) { e.printStackTrace(); } return classes; } public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) { // 获取此包的目录 建立一个File File dir = new File(packagePath); // 如果不存在或者 也不是目录就直接返回 if (!dir.exists() || !dir.isDirectory()) { // log.warn("用户定义包名 " + packageName + " 下没有任何文件"); return; } // 如果存在 就获取包下的所有文件 包括目录 File[] dirfiles = dir.listFiles(new FileFilter() { // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); // 循环所有文件 for (File file : dirfiles) { // 如果是目录 则继续扫描 if (file.isDirectory()) { findAndAddClassesInPackageByFile( packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes); } else { // 如果是java类文件 去掉后面的.class 只留下类名 String className = file.getName().substring(0, file.getName().length() - 6); try { classes.add(Thread.currentThread().getContextClassLoader() .loadClass(packageName + '.' + className)); } catch (ClassNotFoundException e) { } } } } private static String GetDestoryString(StringBuffer sb,Class<?> jClass) throws InstantiationException, IllegalAccessException { BeanWrapper bw = new BeanWrapperImpl(jClass.newInstance()); PropertyDescriptor[] pds = bw.getPropertyDescriptors(); sb.append("destructor ").append(GetDClassName(jClass)).append(".Destroy;").append(NEWLINE); sb.append("var i:Integer;").append(NEWLINE); sb.append("begin").append(NEWLINE); sb.append("\t").append("inherited Destroy;").append(NEWLINE); for (PropertyDescriptor pd:pds) { Class<?> c = pd.getPropertyType(); String fieldName = pd.getDisplayName(); String fixedName = "F" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); if (c.getSimpleName().compareToIgnoreCase("list") == 0) { Class<?> gClass = GetGenericTypeByGetMethod(pd.getReadMethod()); if (IsEntiyClass(gClass)) { sb.append("\t").append("for i:=0 to Length("+fixedName+")-1 do").append(NEWLINE); sb.append("\tbegin").append(NEWLINE); sb.append("\t\t").append(fixedName).append("[i].").append("Destroy;").append(NEWLINE); sb.append("\tend;").append(NEWLINE); } }else{ if(IsEntiyClass(c)){ sb.append("\t").append(fixedName).append(".Destroy;").append(NEWLINE); } } } return sb.append("end;").append(NEWLINE).toString(); } private static String JToDBasic(Class<?> jClass) { if (jClass==null) { return "TObject"; } if (IsEntiyClass(jClass)) { useEntiy.put(jClass, 1); } if (jClass.getSimpleName().compareToIgnoreCase("int") == 0 || jClass.getSimpleName().compareToIgnoreCase("long") == 0 || jClass.getSimpleName().compareToIgnoreCase("integer")==0) { return "Integer"; }else if (jClass.getSimpleName().compareToIgnoreCase("double") == 0 || jClass.getSimpleName().compareToIgnoreCase("float") == 0) { return "Double"; } else if (jClass.getSimpleName().compareToIgnoreCase("boolean") == 0) { return "Boolean"; } else if (jClass.getSimpleName().compareToIgnoreCase("string") == 0 || jClass.getSimpleName().compareToIgnoreCase("date") == 0) { return "String"; } return jClass.getSimpleName(); } private static String JToD(Class<?> jClass,Method method) { if (jClass==null||method==null) { return "TObject"; } if (IsEntiyClass(jClass)) { useEntiy.put(jClass, 1); return GetDClassName(jClass); } if (jClass.getSimpleName().compareToIgnoreCase("int") == 0 || jClass.getSimpleName().compareToIgnoreCase("long") == 0 || jClass.getSimpleName().compareToIgnoreCase("integer")==0) { return "Integer"; }else if (jClass.getSimpleName().compareToIgnoreCase("double") == 0 || jClass.getSimpleName().compareToIgnoreCase("float") == 0) { return "Double"; } else if (jClass.getSimpleName().compareToIgnoreCase("boolean") == 0) { return "Boolean"; } else if (jClass.getSimpleName().compareToIgnoreCase("string") == 0 || jClass.getSimpleName().compareToIgnoreCase("date") == 0) { return "String"; } else if (jClass.getSimpleName().compareToIgnoreCase("list") == 0) { Class<?> genericType = GetGenericTypeByGetMethod(method); if (IsEntiyClass(genericType)) { useEntiy.put(genericType, 1); return GetDClassName(genericType)+"Array"; }else { return JToDBasic(genericType)+"Array"; } } return jClass.getSimpleName(); } public static Class<?> GetGenericTypeByGetMethod(Method method){ ParameterizedType pt= (ParameterizedType)method.getGenericReturnType(); if (pt!=null&&pt.getActualTypeArguments()!=null&&pt.getActualTypeArguments().length>0) { return (Class<?>)pt.getActualTypeArguments()[0]; } return null; } private static boolean IsEntiyClass(Class<?> jClass){ return (jClass!=null&&jClass.getAnnotation(Entity.class)!=null); } private static String GetDUintName(Class<?> jClass) { return "U"+jClass.getSimpleName()+"Obj"; } private static String GetDClassName(Class<?> jClass){ return "T" + jClass.getSimpleName(); } private static void GetJsonConvertString(StringBuffer sb,String fieldName,String fixedName,PropertyDescriptor pd){ Class<?> jClass = pd.getPropertyType(); sb.append("if obj['").append(fieldName).append("']").append("<>nil then").append(NEWLINE); sb.append("begin").append(NEWLINE); if (jClass.getSimpleName().compareToIgnoreCase("int") == 0 || jClass.getSimpleName().compareToIgnoreCase("long") == 0 || jClass.getSimpleName().compareToIgnoreCase("integer")==0) { sb.append("\t").append(fixedName).append(" := ").append("obj['").append(fieldName).append("']").append(".AsInteger();").append(NEWLINE); }else if (jClass.getSimpleName().compareToIgnoreCase("double") == 0 || jClass.getSimpleName().compareToIgnoreCase("float") == 0) { sb.append("\t").append(fixedName).append(" := ").append("obj['").append(fieldName).append("']").append(".AsDouble();").append(NEWLINE); }else if (jClass.getSimpleName().compareToIgnoreCase("boolean") == 0) { sb.append("\t").append(fixedName).append(" := ").append("obj['").append(fieldName).append("']").append(".AsBoolean();").append(NEWLINE); } else if (jClass.getSimpleName().compareToIgnoreCase("string") == 0 || jClass.getSimpleName().compareToIgnoreCase("date") == 0) { sb.append("\t").append(fixedName).append(" := ").append("obj['").append(fieldName).append("']").append(".AsString();").append(NEWLINE); } else if (jClass.getSimpleName().compareToIgnoreCase("list") == 0) { Class<?> genericType = GetGenericTypeByGetMethod(pd.getReadMethod()); sb.append("\t").append("jsonArray := obj['").append(fieldName).append("']").append(".AsArray();").append(NEWLINE); sb.append("\t").append("setLength(").append(fixedName).append(",jsonArray.Length);").append(NEWLINE); sb.append("\t").append("for i:=0 to jsonArray.Length-1 do").append(NEWLINE); sb.append("\t").append("begin").append(NEWLINE); if (IsEntiyClass(genericType)){ sb.append("\t\t").append(fixedName).append("[i] := ").append(GetDClassName(genericType)) .append(".Create(").append("jsonArray.O[i]").append(");").append(NEWLINE); }else { sb.append("\t\t").append(fixedName).append("[i] := ").append("jsonArray.") .append(GetJsonBasicString(genericType)).append("[i]").append(");").append(NEWLINE); } sb.append("\tend;").append(NEWLINE); }else if(IsEntiyClass(jClass)){ sb.append("\t").append(fixedName).append(" := ").append(GetDClassName(jClass)).append(".Create(").append("obj['"+fieldName+"']);").append(NEWLINE); } sb.append("end;").append(NEWLINE); return; } private static Object GetJsonBasicString(Class<?> jClass) { if (jClass.getSimpleName().compareToIgnoreCase("int") == 0 || jClass.getSimpleName().compareToIgnoreCase("long") == 0 || jClass.getSimpleName().compareToIgnoreCase("integer")==0) { return "I"; }else if (jClass.getSimpleName().compareToIgnoreCase("double") == 0 || jClass.getSimpleName().compareToIgnoreCase("float") == 0) { return "D"; }else if (jClass.getSimpleName().compareToIgnoreCase("boolean") == 0) { return "B"; } else if (jClass.getSimpleName().compareToIgnoreCase("string") == 0 || jClass.getSimpleName().compareToIgnoreCase("date") == 0) { return "S"; } return "S"; } }