Commits

Keigo Imai committed a59cdef

much incomplete IDL generator

Comments (0)

Files changed (6)

idlgen/.classpath

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="lib" path="/usr/local/android/platforms/android-3/android.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>genstubcj</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

idlgen/.settings/org.eclipse.jdt.core.prefs

+#Sat Dec 25 18:52:24 JST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6

idlgen/src/Main.java

+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Output all classes reachable from a particular class in the current classpath,
+ * in a IDL file (thus the resulting file might be bigger).
+ */
+public class Main {
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) throws Throwable {
+
+		Class<?> root = Class.forName("android.app.Activity"); // change here
+		List<Class<?>> classes = resolve(new HashSet<Class<?>>(), root, 50); // change the number
+		System.err.println(classes.size()+ " classes.");
+		new OutputIDL(classes).outputIDL();
+	}
+
+	// set of classes that should not traversed further
+	private static final Set<Class<?>> ignoreSet = new HashSet<Class<?>>();
+	static {
+		ignoreSet.add(Appendable.class); // covariance を使うメソッドがあるので
+		ignoreSet.add(CharSequence.class); // stringにマップしたい
+		ignoreSet.add(Object.class); // topなりにマップしたい
+		ignoreSet.add(Iterable.class);
+		ignoreSet.add(Cloneable.class);
+		ignoreSet.add(ClassLoader.class);
+		ignoreSet.add(Serializable.class);
+		ignoreSet.add(Comparable.class);
+	}
+
+	// judge whether a class should be ignored or not
+	public static boolean isIgnored(Class<?> clazz) {
+		if (clazz == null)
+			return true;
+		boolean b = clazz.isLocalClass() || clazz.isMemberClass()
+				|| clazz.isAnonymousClass();
+		b |= clazz.isArray() ? isIgnored(clazz.getComponentType()) : false;
+		b |= ignoreSet.contains(clazz);
+		b |= clazz.getPackage() == null
+				|| "java.lang.reflect".equals(clazz.getPackage().getName())
+				|| clazz.getPackage().getName().startsWith("java.nio")
+				|| clazz.getPackage().getName().startsWith("java.net")
+				|| clazz.getPackage().getName().startsWith("java.io")
+				|| "java.lang.annotation".equals(clazz.getPackage().getName());
+		return b;
+	}
+
+	private static Class<?> trimQual(Class<?> clazz) {
+		if (clazz.isArray()) {
+			return trimQual(clazz.getComponentType());
+		} else {
+			return clazz;
+		}
+	}
+
+	private static final List<Class<?>> empty = new ArrayList<Class<?>>();
+
+	public static List<Class<?>> resolve(Set<Class<?>> pending_,
+			Class<?> clazz, int depth) {
+		if(!Modifier.isPublic(clazz.getModifiers())) {
+			return empty;
+		}
+		if (clazz.isPrimitive())
+			return empty;
+		if (isIgnored(clazz))
+			return empty;
+		// if(depth<1) {
+		// System.err.println("depth exceeded :" + clazz.getCanonicalName());
+		// return empty;
+		// }
+		if (pending_.contains(clazz))
+			return empty;
+		ArrayList<Class<?>> ret = new ArrayList<Class<?>>();
+		HashSet<Class<?>> pending = new HashSet<Class<?>>(pending_);
+		pending.add(clazz);
+
+		if (!clazz.isInterface()) {
+			Class<?> parent = trimQual(clazz.getSuperclass());
+			List<Class<?>> resolved = resolve(pending, parent, depth - 1);
+			ret.addAll(resolved);
+			pending.addAll(resolved);
+		}
+
+		Class<?>[] interfaces = clazz.getInterfaces();
+		for (Class<?> i : interfaces) {
+			i = trimQual(i);
+			List<Class<?>> resolved = resolve(pending, i, depth - 1);
+			ret.addAll(resolved);
+			pending.addAll(resolved);
+		}
+		ret.add(clazz);
+
+		for (Constructor<?> cstr : clazz.getConstructors()) {
+			Class<?>[] paramTypes = cstr.getParameterTypes();
+			for (Class<?> p : paramTypes) {
+				p = trimQual(p);
+				List<Class<?>> resolved = resolve(pending, p, depth - 1);
+				ret.addAll(resolved);
+				pending.addAll(resolved);
+			}
+		}
+
+		Method[] methods = clazz.getMethods();
+		for (Method m : methods) {
+			Class<?>[] paramTypes = m.getParameterTypes();
+			for (Class<?> p : paramTypes) {
+				p = trimQual(p);
+				List<Class<?>> resolved = resolve(pending, p, depth - 1);
+				ret.addAll(resolved);
+				pending.addAll(resolved);
+			}
+			Class<?> retType = trimQual(m.getReturnType());
+			List<Class<?>> resolved = resolve(pending, retType, depth - 1);
+			ret.addAll(resolved);
+			pending.addAll(resolved);
+		}
+		return ret;
+	}
+
+}

idlgen/src/OutputIDL.java

+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashMap;
+
+public class OutputIDL {
+
+	private static final char NL = '\n';
+
+	Overloading overloading;
+
+	private Collection<Class<?>> classes;
+
+	public OutputIDL(Collection<Class<?>> classes) {
+		this.classes = classes;
+		overloading = new Overloading(classes);
+	}
+
+	public void outputIDL() {
+		StringBuffer buf = new StringBuffer();
+		int count = 0;
+		for (Class<?> c : classes) {
+			if (classMap.get(c) != null) {
+				continue;
+			}
+			if (isIgnored(c)) {
+				continue;
+			}
+			// System.err.println("processing: "+c.getCanonicalName());
+			buf.append("package " + c.getPackage().getName() + ";" + NL);
+			genClassHeader(buf, c);
+			buf.append(" {" + NL);
+			genClassBody(buf, c);
+			buf.append("}" + NL + NL);
+			count++;
+		}
+		System.err.println(count + " classes : printing");
+		System.out.println(buf);
+
+	}
+
+	private static final HashMap<Class<?>, String> classMap = new HashMap<Class<?>, String>();
+	static {
+		classMap.put(Void.TYPE, "void");
+		classMap.put(Boolean.TYPE, "boolean");
+		classMap.put(Byte.TYPE, "byte");
+		classMap.put(Character.TYPE, "char");
+		classMap.put(Short.TYPE, "short");
+		classMap.put(Integer.TYPE, "int");
+		classMap.put(Long.TYPE, "long");
+		classMap.put(Float.TYPE, "float");
+		classMap.put(Double.TYPE, "double");
+		classMap.put(String.class, "string");
+	}
+
+	public static String mapType(Class<?> clazz) {
+		if (clazz.isArray()) {
+			return mapType(clazz.getComponentType()) + "[]";
+		} else {
+			String ret = classMap.get(clazz);
+			if (ret == null) {
+				return clazz.getCanonicalName();
+			} else {
+				return ret;
+			}
+		}
+	}
+
+	public boolean isIgnored(Class<?> clazz) {
+		if (clazz.isArray()) {
+			return isIgnored(clazz.getComponentType());
+		}
+		if (classMap.get(clazz) != null) {
+			return false;
+		}
+		if (!classes.contains(clazz)) {
+			return true;
+		}
+		if (false 
+				|| clazz.getPackage().getName().startsWith("android.app")
+				//|| clazz.getPackage().getName().startsWith("android.content")
+				|| clazz.getPackage().getName().startsWith("android.view")
+				|| clazz.getPackage().getName().startsWith("android.os")
+				//|| clazz.getPackage().getName().startsWith("android.util")
+				//|| clazz.getPackage().getName().startsWith("android.content")
+				//|| clazz.getPackage().getName().startsWith("java.lang")
+				//|| clazz.getPackage().getName().startsWith("java.util")
+				) {
+			return false;
+		}
+		return true;
+	}
+
+	private static <T> void genArgs(StringBuffer buf, Class<?>[] params) {
+		buf.append("(");
+		boolean first = true;
+		for (Class<?> p : params) {
+			if (!first)
+				buf.append(", ");
+			buf.append(mapType(p));
+			first = false;
+		}
+		buf.append(")");
+	}
+
+	static <T> T default_(T v, T fallback) {
+		if (v != null)
+			return v;
+		else
+			return fallback;
+	}
+
+	private <T> void genClassBody(StringBuffer buf, Class<?> c) {
+		// constructors
+		Constructor<?>[] cstrs = c.getConstructors();
+		for (int i = 0; i < cstrs.length; i++) {
+			for (Class<?> p : cstrs[i].getParameterTypes()) {
+				if (isIgnored(p)) {
+					buf.append("// ");
+					break;
+				}
+			}
+			buf.append("\t");
+			buf.append("[name cre_" + c.getSimpleName() + (i == 0 ? "" : i)
+					+ "] ");
+			buf.append("<init>");
+			genArgs(buf, cstrs[i].getParameterTypes());
+			buf.append(";" + NL);
+		}
+
+		// methods
+		for (Method m : c.getDeclaredMethods()) {
+			if (m.isBridge()) {
+				continue;
+			}
+			if (!Modifier.isPublic(m.getModifiers())) {
+				continue;
+			}
+			if (Modifier.isFinal(m.getModifiers())) {
+				continue; // FIXME
+			}
+			if (m.getName().contains("$") || m.getName().equals("array")
+					|| m.getName().startsWith("_")
+					|| m.getName().equals("match") // FIXME
+					|| isIgnored(m.getReturnType())) {
+				buf.append("// ");
+			} else {
+				for (Class<?> p : m.getParameterTypes()) {
+					if (isIgnored(p)) {
+						buf.append("// ");
+						break;
+					}
+				}
+			}
+			buf.append("\t");
+			int count = overloading.getNumber(m);
+			buf.append("[name " + uncapitalize(m.getName())
+					+ (count == 0 ? "" : count) + "] ");
+			if (Modifier.isStatic(m.getModifiers())) {
+				buf.append("static ");
+			}
+			buf.append(mapType(m.getReturnType()) + " ");
+			buf.append(m.getName());
+			genArgs(buf, m.getParameterTypes());
+			buf.append(";" + NL);
+		}
+	}
+
+	private static String uncapitalize(String str) {
+		if (str == null || str.length() == 0)
+			return str;
+		return Character.toLowerCase(str.charAt(0)) + str.substring(1);
+	}
+
+	private void genClassHeader(StringBuffer buf, Class<?> c) {
+		if (c.isInterface()) {
+			buf.append("interface ");
+		} else {
+			if (Modifier.isAbstract(c.getModifiers())) {
+				buf.append("abstract ");
+			}
+			buf.append("class ");
+		}
+		buf.append(c.getSimpleName() + " ");
+		Class<?> super_ = c.getSuperclass();
+		if (!c.isInterface()) {
+			if (!super_.equals(Object.class) && !isIgnored(super_)) {
+				buf.append("extends " + super_.getCanonicalName() + " ");
+			}
+		}
+
+		boolean first = true;
+		for (Class<?> i : c.getInterfaces()) {
+			if (isIgnored(i))
+				continue;
+			if (first) {
+				first = false;
+				if (c.isInterface()) {
+					buf.append("implements "); // XXX should be "extends " in
+					// Java manner, but due to a
+					// ojacare bug I put
+					// "implements " here
+				} else {
+					buf.append("implements ");
+				}
+			} else {
+				buf.append(", ");
+			}
+			buf.append(i.getCanonicalName());
+		}
+		buf.append(" ");
+	}
+
+}

idlgen/src/Overloading.java

+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * 
+ */
+
+class Overloading {
+	private HashSet<Class<?>> done = new HashSet<Class<?>>();
+	private HashMap<ClassMethod, HashMap<Method, Object[][]>> methods = new HashMap<ClassMethod, HashMap<Method, Object[][]>>();
+	private ArrayList<Object[][]> boxes = new ArrayList<Object[][]>();
+	
+	private static Method getMethodNullable(Class<?> clazz, Method method) {
+		if(clazz==null) return null;
+		try {
+			return clazz.getMethod(method.getName(), method.getParameterTypes());
+		} catch(NoSuchMethodException e) {
+			return null;
+		}
+	}
+	
+	private void unify(List<Object[][]> boxes) {
+		Object[] top = boxes.get(0)[0];
+		for(int i=boxes.size()+1; i<boxes.size(); i++) {
+			Object[][] box = boxes.get(i);
+			this.boxes.remove(box);
+			box[0] = top;
+		}
+	}
+	
+	public int getNumber(Method method) {
+		HashMap<Method, Object[][]> map = methods.get(new ClassMethod(method.getDeclaringClass(), method.getName()));
+		if(map==null) {
+			return 0;
+		} else {
+			return (Integer)map.get(method)[0][0];
+		}
+		
+	}
+	
+	public Overloading(Collection<Class<?>> classes) {
+		for(Class<?> c : classes) {
+			addClass(c);
+		}
+		HashMap<String, List<Object[][]>> methods = new HashMap<String, List<Object[][]>>(); 
+		for(Object[][] box : boxes) {
+			Method method = (Method)box[0][1];
+			List<Object[][]> myboxes = methods.get(method.getName());
+			if(myboxes==null) {
+				myboxes = new ArrayList<Object[][]>();
+				methods.put(method.getName(), myboxes);
+			}
+			myboxes.add(box);
+		}
+		for(String mName : methods.keySet()) {
+			List<Object[][]> myboxes = methods.get(mName);
+			Collections.sort(myboxes, new Comparator<Object[][]>() {
+				@Override
+				public int compare(Object[][] o1, Object[][] o2) {
+					Method m1 = (Method)o1[0][1], m2 = (Method)o2[0][1];
+					return m1.getParameterTypes().length - m2.getParameterTypes().length;
+				}
+			});
+			int count = 0;
+			Method prev = null;
+			for(Object[][] box : myboxes) {
+				Method curr = (Method)box[0][1];
+				if(prev!=null
+					&& prev.getReturnType().equals(curr.getReturnType()) &&
+							Arrays.deepEquals(prev.getParameterTypes(), curr.getParameterTypes())) {
+					box[0][0] = count - 1;
+				} else {
+					box[0][0] = count;
+					count++;
+				}
+				prev = curr;
+			}
+		}
+	}
+	
+	private void addClass(Class<?> clazz) {
+		if(done.contains(clazz)) return;
+		Class<?> super_ = clazz.getSuperclass();
+		if(super_!=null) {
+			addClass(super_);
+		}
+		for(Class<?> i: clazz.getInterfaces()) {
+			addClass(i);
+		}
+		for(Method method : clazz.getMethods()) {
+			HashMap<Method,Object[][]> thisMethods = methods.get(new ClassMethod(clazz, method.getName()));
+			if(thisMethods==null) {
+				thisMethods = new HashMap<Method,Object[][]>();
+				methods.put(new ClassMethod(clazz, method.getName()), thisMethods);
+			}
+			
+			ArrayList<Object[][]> superBoxes = new ArrayList<Object[][]>();
+			Method superMethod = getMethodNullable(super_, method);
+			if(superMethod!=null) {
+				Object[][] box = methods.get(new ClassMethod(super_, superMethod.getName())).get(superMethod);
+				if(box!=null) {
+					superBoxes.add(box);
+				}
+			}
+			for(Class<?> i : clazz.getInterfaces()) {
+				Method im = getMethodNullable(i, method);
+				if(im!=null) {
+					Object[][] box = methods.get(new ClassMethod(i, im.getName())).get(im);
+					if(box!=null) {
+						superBoxes.add(box);
+					}
+				}
+			}
+			if(superBoxes.size()>0) {
+				unify(superBoxes);
+				thisMethods.put(method, superBoxes.get(0));
+			} else {
+				Object[][] box = new Object[][]{new Object[]{0, method}};
+				boxes.add(box);
+				thisMethods.put(method, box);
+			}
+		}
+		done.add(clazz);
+	}
+	
+	private static class ClassMethod {
+		public final Class<?> clazz;
+		public final String methodName;
+
+		public ClassMethod(Class<?> clazz, String methodName) {
+			this.clazz = clazz;
+			this.methodName = methodName;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			boolean result = false;
+			if (obj instanceof ClassMethod) {
+				ClassMethod that = (ClassMethod) obj;
+				result = clazz.equals(that.clazz)
+						&& methodName.equals(that.methodName)
+						&& this.getClass().equals(that.getClass());
+			}
+			return result;
+		}
+
+		@Override
+		public int hashCode() {
+			return clazz.hashCode() + methodName.hashCode();
+		}
+		
+		@Override
+		public String toString() {
+			return clazz.getSimpleName()+","+methodName;
+		}
+	}
+}
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.