diff options
Diffstat (limited to 'base/vim/bundle/javacomplete/autoload/Reflection.java')
-rw-r--r-- | base/vim/bundle/javacomplete/autoload/Reflection.java | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/base/vim/bundle/javacomplete/autoload/Reflection.java b/base/vim/bundle/javacomplete/autoload/Reflection.java new file mode 100644 index 0000000..5452b0f --- /dev/null +++ b/base/vim/bundle/javacomplete/autoload/Reflection.java @@ -0,0 +1,670 @@ +/** + * Reflection.java + * + * A utility class for javacomplete mainly for reading class or package information. + * Version: 0.77 + * Maintainer: cheng fang <fangread@yahoo.com.cn> + * Last Change: 2007-09-16 + * Copyright: Copyright (C) 2007 cheng fang. All rights reserved. + * License: Vim License (see vim's :help license) + * + */ + +import java.lang.reflect.*; +import java.io.*; +import java.util.*; +import java.util.zip.*; + +class Reflection { + static final String VERSION = "0.77"; + + static final int OPTION_FIELD = 1; + static final int OPTION_METHOD = 2; + static final int OPTION_STATIC_FIELD = 4; + static final int OPTION_STATIC_METHOD = 8; + static final int OPTION_CONSTRUCTOR = 16; + static final int OPTION_STATIC = 12; // compound static + static final int OPTION_INSTANCE = 15; // compound instance + static final int OPTION_ALL = 31; // compound all + static final int OPTION_SUPER = 32; + static final int OPTION_SAME_PACKAGE = 64; + + static final int STRATEGY_ALPHABETIC = 128; + static final int STRATEGY_HIERARCHY = 256; + static final int STRATEGY_DEFAULT = 512; + + static final int RETURN_ALL_PACKAGE_INFO = 0x1000; + + static final String KEY_NAME = "'n':"; // "'name':"; + static final String KEY_TYPE = "'t':"; // "'type':"; + static final String KEY_MODIFIER = "'m':"; // "'modifier':"; + static final String KEY_PARAMETERTYPES = "'p':"; // "'parameterTypes':"; + static final String KEY_RETURNTYPE = "'r':"; // "'returnType':"; + static final String KEY_DESCRIPTION = "'d':"; // "'description':"; + static final String KEY_DECLARING_CLASS = "'c':"; // "'declaringclass':"; + + static final String NEWLINE = ""; // "\r\n" + + static boolean debug_mode = false; + + static Hashtable htClasspath = new Hashtable(); + + public static boolean existed(String fqn) { + boolean result = false; + try { + Class.forName(fqn); + result = true; + } + catch (Exception ex) { + } + return result; + } + + public static String existedAndRead(String fqns) { + Hashtable mapPackages = new Hashtable(); // qualified name --> StringBuffer + Hashtable mapClasses = new Hashtable(); // qualified name --> StringBuffer + + for (StringTokenizer st = new StringTokenizer(fqns, ","); st.hasMoreTokens(); ) { + String fqn = st.nextToken(); + try { + Class clazz = Class.forName(fqn); + putClassInfo(mapClasses, clazz); + } + catch (Exception ex) { + String binaryName = fqn; + boolean found = false; + while (true) { + try { + int lastDotPos = binaryName.lastIndexOf('.'); + if (lastDotPos == -1) + break; + binaryName = binaryName.substring(0, lastDotPos) + '$' + binaryName.substring(lastDotPos+1, binaryName.length()); + Class clazz = Class.forName(binaryName); + putClassInfo(mapClasses, clazz); + found = true; + break; + } + catch (Exception e) { + } + } + if (!found) + putPackageInfo(mapPackages, fqn); + } + } + + if (mapPackages.size() > 0 || mapClasses.size() > 0) { + StringBuffer sb = new StringBuffer(4096); + sb.append("{"); + for (Enumeration e = mapPackages.keys(); e.hasMoreElements(); ) { + String s = (String)e.nextElement(); + sb.append("'").append( s.replace('$', '.') ).append("':").append(mapPackages.get(s)).append(","); + } + for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) { + String s = (String)e.nextElement(); + sb.append("'").append( s.replace('$', '.') ).append("':").append(mapClasses.get(s)).append(","); + } + sb.append("}"); + return sb.toString(); + } + else + return ""; + } + + private static String getPackageList(String fqn) { + Hashtable mapPackages = new Hashtable(); + putPackageInfo(mapPackages, fqn); + return mapPackages.size() > 0 ? mapPackages.get(fqn).toString() : ""; + } + + private static Hashtable collectClassPath() { + if (!htClasspath.isEmpty()) + return htClasspath; + + // runtime classes + if ("Kaffe".equals(System.getProperty("java.vm.name"))) { + addClasspathesFromDir(System.getProperty("java.home") + File.separator + "share" + File.separator + "kaffe" + File.separator); + } + else if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) { + if (new File(System.getProperty("sun.boot.class.path")).exists()) + htClasspath.put(System.getProperty("sun.boot.class.path"), ""); + } + + if (System.getProperty("java.vendor").toLowerCase(Locale.US).indexOf("microsoft") >= 0) { + // `*.ZIP` files in `Packages` directory + addClasspathesFromDir(System.getProperty("java.home") + File.separator + "Packages" + File.separator); + } + else { + // the following code works for several kinds of JDK + // - JDK1.1: classes.zip + // - JDK1.2+: rt.jar + // - JDK1.4+ of Sun and Apple: rt.jar + jce.jar + jsse.jar + // - JDK1.4 of IBM split rt.jar into core.jar, graphics.jar, server.jar + // combined jce.jar and jsse.jar into security.jar + // - JDK for MacOS X split rt.jar into classes.jar, ui.jar in Classes directory + addClasspathesFromDir(System.getProperty("java.home") + File.separator + "lib" + File.separator); + addClasspathesFromDir(System.getProperty("java.home") + File.separator + "jre" + File.separator + "lib" + File.separator); + addClasspathesFromDir(System.getProperty("java.home") + File.separator + ".." + File.separator + "Classes" + File.separator); + } + + // ext + String extdirs = System.getProperty("java.ext.dirs"); + for (StringTokenizer st = new StringTokenizer(extdirs, File.pathSeparator); st.hasMoreTokens(); ) { + addClasspathesFromDir(st.nextToken() + File.separator); + } + + // user classpath + String classPath = System.getProperty("java.class.path"); + StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator); + while (st.hasMoreTokens()) { + String path = st.nextToken(); + File f = new File(path); + if (!f.exists()) + continue; + + if (path.endsWith(".jar") || path.endsWith(".zip")) + htClasspath.put(f.toString(), ""); + else { + if (f.isDirectory()) + htClasspath.put(f.toString(), ""); + } + } + + return htClasspath; + } + + private static void addClasspathesFromDir(String dirpath) { + File dir = new File(dirpath); + if (dir.isDirectory()) { + String[] items = dir.list(); // use list() instead of listFiles() since the latter are introduced in 1.2 + for (int i = 0; i < items.length; i++) { + File f = new File(dirpath + items[i]); + if (!f.exists()) + continue; + + if (items[i].endsWith(".jar") || items[i].endsWith(".zip") || items[i].endsWith(".ZIP")) { + htClasspath.put(f.toString(), ""); + } + else if (items.equals("classes")) { + if (f.isDirectory()) + htClasspath.put(f.toString(), ""); + } + } + } + } + + + /** + * If name is empty, put all loadable package info into map once. + */ + private static void putPackageInfo(Hashtable map, String name) { + String prefix = name.replace('.', '/') + "/"; + Hashtable subpackages = new Hashtable(); + Hashtable classes = new Hashtable(); + for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) { + String path = (String)e.nextElement(); + if (path.endsWith(".jar") || path.endsWith(".zip")) + appendListFromJar(subpackages, classes, path, prefix); + else + appendListFromFolder(subpackages, classes, path, prefix); + } + + if (subpackages.size() > 0 || classes.size() > 0) { + StringBuffer sb = new StringBuffer(1024); + sb.append("{'tag':'PACKAGE','subpackages':["); + for (Enumeration e = subpackages.keys(); e.hasMoreElements(); ) { + sb.append("'").append(e.nextElement()).append("',"); + } + sb.append("],'classes':["); + for (Enumeration e = classes.keys(); e.hasMoreElements(); ) { + sb.append("'").append(e.nextElement()).append("',"); + } + sb.append("]}"); + map.put(name, sb.toString()); + } + } + + public static void appendListFromJar(Hashtable subpackages, Hashtable classes, String path, String prefix) { + try { + for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) { + String entry = entries.nextElement().toString(); + int len = entry.length(); + if (entry.endsWith(".class") && entry.indexOf('$') == -1 + && entry.startsWith(prefix)) { + int splitPos = entry.indexOf('/', prefix.length()); + String shortname = entry.substring(prefix.length(), splitPos == -1 ? entry.length()-6 : splitPos); + if (splitPos == -1) { + if (!classes.containsKey(shortname)) + classes.put(shortname, ""); //classes.put(shortname, "{'tag':'CLASSDEF','name':'"+shortname+"'}"); + } + else { + if (!subpackages.containsKey(shortname)) + subpackages.put(shortname, ""); //subpackages.put(shortname, "{'tag':'PACKAGE','name':'" +shortname+"'}"); + } + } + } + } + catch (Throwable e) { + //e.printStackTrace(); + } + } + + public static void appendListFromFolder(Hashtable subpackages, Hashtable classes, String path, String prefix) { + try { + String fullPath = path + "/" + prefix; + File file = new File(fullPath); + if (file.isDirectory()) { + String[] descents = file.list(); + for (int i = 0; i < descents.length; i++) { + if (descents[i].indexOf('$') == -1) { + if (descents[i].endsWith(".class")) { + String shortname = descents[i].substring(0, descents[i].length()-6); + if (!classes.containsKey(shortname)) + classes.put(shortname, ""); + } + else if ((new File(fullPath + "/" + descents[i])).isDirectory()) { + if (!subpackages.containsKey(descents[i])) + subpackages.put(descents[i], ""); + } + } + } + } + } + catch (Throwable e) { + } + } + + private static int INDEX_PACKAGE = 0; + private static int INDEX_CLASS = 1; + + // generate information of all packages in jar files. + public static String getPackageList() { + Hashtable map = new Hashtable(); + + for (Enumeration e = collectClassPath().keys(); e.hasMoreElements(); ) { + String path = (String)e.nextElement(); + if (path.endsWith(".jar") || path.endsWith(".zip")) + appendListFromJar(path, map); + } + + StringBuffer sb = new StringBuffer(4096); + sb.append("{"); + //sb.append("'*':'").append( map.remove("") ).append("',"); // default package + for (Enumeration e = map.keys(); e.hasMoreElements(); ) { + String s = (String)e.nextElement(); + StringBuffer[] sbs = (StringBuffer[])map.get(s); + sb.append("'").append( s.replace('/', '.') ).append("':") + .append("{'tag':'PACKAGE'"); + if (sbs[INDEX_PACKAGE].length() > 0) + sb.append(",'subpackages':[").append(sbs[INDEX_PACKAGE]).append("]"); + if (sbs[INDEX_CLASS].length() > 0) + sb.append(",'classes':[").append(sbs[INDEX_CLASS]).append("]"); + sb.append("},"); + } + sb.append("}"); + return sb.toString(); + + } + + public static void appendListFromJar(String path, Hashtable map) { + try { + for (Enumeration entries = new ZipFile(path).entries(); entries.hasMoreElements(); ) { + String entry = entries.nextElement().toString(); + int len = entry.length(); + if (entry.endsWith(".class") && entry.indexOf('$') == -1) { + int slashpos = entry.lastIndexOf('/'); + String parent = entry.substring(0, slashpos); + String child = entry.substring(slashpos+1, len-6); + putItem(map, parent, child, INDEX_CLASS); + + slashpos = parent.lastIndexOf('/'); + if (slashpos != -1) { + AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1)); + } + } + } + } + catch (Throwable e) { + //e.printStackTrace(); + } + } + + public static void putItem(Hashtable map, String parent, String child, int index) { + StringBuffer[] sbs = (StringBuffer[])map.get(parent); + if (sbs == null) { + sbs = new StringBuffer[] { new StringBuffer(256), // packages + new StringBuffer(256) // classes + }; + } + if (sbs[index].toString().indexOf("'" + child + "',") == -1) + sbs[index].append("'").append(child).append("',"); + map.put(parent, sbs); + } + + public static void AddToParent(Hashtable map, String parent, String child) { + putItem(map, parent, child, INDEX_PACKAGE); + + int slashpos = parent.lastIndexOf('/'); + if (slashpos != -1) { + AddToParent(map, parent.substring(0, slashpos), parent.substring(slashpos+1)); + } + } + + + public static String getClassInfo(String className) { + Hashtable mapClasses = new Hashtable(); + try { + Class clazz = Class.forName(className); + putClassInfo(mapClasses, clazz); + } + catch (Exception ex) { + } + + if (mapClasses.size() == 1) { + return mapClasses.get(className).toString(); // return {...} + } + else if (mapClasses.size() > 1) { + StringBuffer sb = new StringBuffer(4096); + sb.append("["); + for (Enumeration e = mapClasses.keys(); e.hasMoreElements(); ) { + String s = (String)e.nextElement(); + sb.append(mapClasses.get(s)).append(","); + } + sb.append("]"); + return sb.toString(); // return [...] + } + else + return ""; + } + + private static void putClassInfo(Hashtable map, Class clazz) { + if (map.containsKey(clazz.getName())) + return ; + + try { + StringBuffer sb = new StringBuffer(1024); + sb.append("{") + .append("'tag':'CLASSDEF',").append(NEWLINE) + .append("'flags':'").append(Integer.toString(clazz.getModifiers(), 2)).append("',").append(NEWLINE) + .append("'name':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE) + //.append("'package':'").append(clazz.getPackage().getName()).append("',").append(NEWLINE) // no getPackage() in JDK1.1 + .append("'classpath':'1',").append(NEWLINE) + .append("'fqn':'").append(clazz.getName().replace('$', '.')).append("',").append(NEWLINE); + + Class[] interfaces = clazz.getInterfaces(); + if (clazz.isInterface()) { + sb.append("'extends':["); + } else { + Class superclass = clazz.getSuperclass(); + if (superclass != null && !"java.lang.Object".equals(superclass.getName())) { + sb.append("'extends':['").append(superclass.getName().replace('$', '.')).append("'],").append(NEWLINE); + putClassInfo(map, superclass); // !! + } + sb.append("'implements':["); + } + for (int i = 0, n = interfaces.length; i < n; i++) { + sb.append("'").append(interfaces[i].getName().replace('$', '.')).append("',"); + putClassInfo(map, interfaces[i]); // !! + } + sb.append("],").append(NEWLINE);; + + Constructor[] ctors = clazz.getConstructors(); + sb.append("'ctors':["); + for (int i = 0, n = ctors.length; i < n; i++) { + Constructor ctor = ctors[i]; + sb.append("{"); + appendModifier(sb, ctor.getModifiers()); + appendParameterTypes(sb, ctor.getParameterTypes()); + sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'"); + sb.append("},").append(NEWLINE); + } + sb.append("], ").append(NEWLINE); + + Field[] fields = clazz.getFields(); + //java.util.Arrays.sort(fields, comparator); + sb.append("'fields':["); + for (int i = 0, n = fields.length; i < n; i++) { + Field f = fields[i]; + int modifier = f.getModifiers(); + sb.append("{"); + sb.append(KEY_NAME).append("'").append(f.getName()).append("',"); + if (!f.getDeclaringClass().getName().equals(clazz.getName())) + sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',"); + appendModifier(sb, modifier); + sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'"); + sb.append("},").append(NEWLINE); + } + sb.append("], ").append(NEWLINE); + + Method[] methods = clazz.getMethods(); + //java.util.Arrays.sort(methods, comparator); + sb.append("'methods':["); + for (int i = 0, n = methods.length; i < n; i++) { + Method m = methods[i]; + int modifier = m.getModifiers(); + sb.append("{"); + sb.append(KEY_NAME).append("'").append(m.getName()).append("',"); + if (!m.getDeclaringClass().getName().equals(clazz.getName())) + sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',"); + appendModifier(sb, modifier); + sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',"); + appendParameterTypes(sb, m.getParameterTypes()); + sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'"); + sb.append("},").append(NEWLINE); + } + sb.append("], ").append(NEWLINE); + + Class[] classes = clazz.getClasses(); + sb.append("'classes': ["); + for (int i = 0, n = classes.length; i < n; i++) { + Class c = classes[i]; + sb.append("'").append(c.getName().replace('$', '.')).append("',"); + putClassInfo(map, c); // !! + } + sb.append("], ").append(NEWLINE); + + appendDeclaredMembers(map, clazz, sb); + + sb.append("}"); + map.put(clazz.getName(), sb); + } + catch (Exception ex) { + //ex.printStackTrace(); + } + } + + private static void appendDeclaredMembers(Hashtable map, Class clazz, StringBuffer sb) { + Constructor[] ctors = clazz.getDeclaredConstructors(); + sb.append("'declared_ctors':["); + for (int i = 0, n = ctors.length; i < n; i++) { + Constructor ctor = ctors[i]; + if (!Modifier.isPublic(ctor.getModifiers())) { + sb.append("{"); + appendModifier(sb, ctor.getModifiers()); + appendParameterTypes(sb, ctor.getParameterTypes()); + sb.append(KEY_DESCRIPTION).append("'").append(ctors[i].toString()).append("'"); + sb.append("},").append(NEWLINE); + } + } + sb.append("], ").append(NEWLINE); + + Field[] fields = clazz.getDeclaredFields(); + sb.append("'declared_fields':["); + for (int i = 0, n = fields.length; i < n; i++) { + Field f = fields[i]; + int modifier = f.getModifiers(); + if (!Modifier.isPublic(modifier)) { + sb.append("{"); + sb.append(KEY_NAME).append("'").append(f.getName()).append("',"); + if (!f.getDeclaringClass().getName().equals(clazz.getName())) + sb.append(KEY_DECLARING_CLASS).append("'").append(f.getDeclaringClass().getName()).append("',"); + appendModifier(sb, modifier); + sb.append(KEY_TYPE).append("'").append(f.getType().getName()).append("'"); + sb.append("},").append(NEWLINE); + } + } + sb.append("], ").append(NEWLINE); + + Method[] methods = clazz.getDeclaredMethods(); + sb.append("'declared_methods':["); + for (int i = 0, n = methods.length; i < n; i++) { + Method m = methods[i]; + int modifier = m.getModifiers(); + if (!Modifier.isPublic(modifier)) { + sb.append("{"); + sb.append(KEY_NAME).append("'").append(m.getName()).append("',"); + if (!m.getDeclaringClass().getName().equals(clazz.getName())) + sb.append(KEY_DECLARING_CLASS).append("'").append(m.getDeclaringClass().getName()).append("',"); + appendModifier(sb, modifier); + sb.append(KEY_RETURNTYPE).append("'").append(m.getReturnType().getName()).append("',"); + appendParameterTypes(sb, m.getParameterTypes()); + sb.append(KEY_DESCRIPTION).append("'").append(m.toString()).append("'"); + sb.append("},").append(NEWLINE); + } + } + sb.append("], ").append(NEWLINE); + + Class[] classes = clazz.getDeclaredClasses(); + sb.append("'declared_classes': ["); + for (int i = 0, n = classes.length; i < n; i++) { + Class c = classes[i]; + if (!Modifier.isPublic(c.getModifiers())) { + sb.append("'").append(c.getName().replace('$', '.')).append("',"); + putClassInfo(map, c); // !! + } + } + sb.append("], ").append(NEWLINE); + } + + private static void appendModifier(StringBuffer sb, int modifier) { + sb.append(KEY_MODIFIER).append("'").append(Integer.toString(modifier, 2)).append("', "); + } + + private static void appendParameterTypes(StringBuffer sb, Class[] paramTypes) { + if (paramTypes.length == 0) return ; + + sb.append(KEY_PARAMETERTYPES).append("["); + for (int j = 0; j < paramTypes.length; j++) { + sb.append("'").append(paramTypes[j].getName()).append("',"); + } + sb.append("],"); + } + + private static boolean isBlank(String str) { + int len; + if (str == null || (len = str.length()) == 0) + return true; + for (int i = 0; i < len; i++) + if ((Character.isWhitespace(str.charAt(i)) == false)) + return false; + return true; + } + + // test methods + + static void debug(String s) { + if (debug_mode) + System.out.println(s); + } + static void output(String s) { + if (!debug_mode) + System.out.print(s); + } + + + private static void usage() { + System.out.println("Reflection for javacomplete (" + VERSION + ")"); + System.out.println(" java [-classpath] Reflection [-c] [-d] [-e] [-h] [-v] [-p] [-s] name[,comma_separated_name_list]"); + System.out.println("Options:"); + System.out.println(" -a list all members in alphabetic order"); + System.out.println(" -c list constructors"); + System.out.println(" -C return class info"); + System.out.println(" -d default strategy, i.e. instance fields, instance methods, static fields, static methods"); + System.out.println(" -e check class existed"); + System.out.println(" -E check class existed and read class information"); + System.out.println(" -D debug mode"); + System.out.println(" -p list package content"); + System.out.println(" -P print all package info in the Vim dictionary format"); + System.out.println(" -s list static fields and methods"); + System.out.println(" -h help"); + System.out.println(" -v version"); + } + + public static void main(String[] args) { + String className = null; + int option = 0x0; + boolean wholeClassInfo = false; + boolean onlyStatic = false; + boolean onlyConstructor = false; + boolean listPackageContent = false; + boolean checkExisted = false; + boolean checkExistedAndRead = false; + boolean allPackageInfo = false; + + for (int i = 0, n = args.length; i < n && !isBlank(args[i]); i++) { + //debug(args[i]); + if (args[i].charAt(0) == '-') { + if (args[i].length() > 1) { + switch (args[i].charAt(1)) { + case 'a': + break; + case 'c': // request constructors + option = option | OPTION_CONSTRUCTOR; + onlyConstructor = true; + break; + case 'C': // class info + wholeClassInfo = true; + break; + case 'd': // default strategy + option = option | STRATEGY_DEFAULT; + break; + case 'D': // debug mode + debug_mode = true; + break; + case 'e': // class existed + checkExisted = true; + break; + case 'E': // check existed and read class information + checkExistedAndRead = true; + break; + case 'h': // help + usage(); + return ; + case 'v': // version + System.out.println("Reflection for javacomplete (" + VERSION + ")"); + break; + case 'p': + listPackageContent = true; + break; + case 'P': + option = RETURN_ALL_PACKAGE_INFO; + break; + case 's': // request static members + option = option | OPTION_STATIC_METHOD | OPTION_STATIC_FIELD; + onlyStatic = true; + break; + default: + } + } + } + else { + className = args[i]; + } + } + if (className == null && (option & RETURN_ALL_PACKAGE_INFO) != RETURN_ALL_PACKAGE_INFO) { + return; + } + if (option == 0x0) + option = OPTION_INSTANCE; + + if (wholeClassInfo) + output( getClassInfo(className) ); + else if ((option & RETURN_ALL_PACKAGE_INFO) == RETURN_ALL_PACKAGE_INFO) + output( getPackageList() ); + else if (checkExistedAndRead) + output( existedAndRead(className) ); + else if (checkExisted) + output( String.valueOf(existed(className)) ); + else if (listPackageContent) + output( getPackageList(className) ); + } +} |