/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* AndroidWorld Library, Copyright 2011 Bryan Chadwick *
* *
* FILE: ./android/util/Util.java *
* *
* This file is part of AndroidWorld. *
* *
* AndroidWorld is free software: you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation, either version *
* 3 of the License, or (at your option) any later version. *
* *
* AndroidWorld is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with AndroidWorld. If not, see . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package android.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
/** Wrapper class for various helper methods. */
public class Util{
/** Simple Test for SExp output */
public static void main(String[] args){
//System.out.println(" Test: "+toSExp(android.universe.List.create(1,2,3,4,5,6)));
}
/** Name of Handler Methods */
public static String funcObjMethName = "apply";
/** Return a pretty argument string for displaying signatures */
public static String argsString(Class>[] args, int i){
if(i == args.length)return "";
if(i == args.length-1)return args[i].getSimpleName();
return args[i].getSimpleName()+", "+argsString(args,i+1);
}
/** For predicting Box/Unboxing and the associated Type differences/subtyping */
public static Class> box(Class> c){
if(c.isPrimitive())return unboxed.get(c);
return c;
}
/** Unboxed -> Boxed primitive types */
public static HashMap, Class>> unboxed = new HashMap, Class>>();
static{
unboxed.put(short.class, Short.class);
unboxed.put(int.class, Integer.class);
unboxed.put(long.class, Long.class);
unboxed.put(float.class, Float.class);
unboxed.put(double.class, Double.class);
unboxed.put(char.class, Character.class);
unboxed.put(byte.class, Byte.class);
unboxed.put(boolean.class, Boolean.class);
}
/** Subtype comparison */
public static boolean subtype(Class> a, Class> b)
{ return box(b).isAssignableFrom(box(a)); }
/** Array Subtype comparison */
public static boolean subtypes(Class>[] a, Class>[] b)
{ return a.length == b.length && subtypes(a,b,0); }
/** Recusive helper method */
private static boolean subtypes(Class>[] a, Class>[] b, int i)
{ return (i >= a.length) || (subtype(a[i],b[i]) && subtypes(a,b,i+1)); }
/** Apply the given method using the given Object and arguments */
public static Object applyFunc(Object f, Method m, Object[] args){
if(f == null)
return args[0];
try{
if(!m.isAccessible())m.setAccessible(true);
Object ret = m.invoke(f, args);
return ret;
}catch(java.lang.IllegalAccessException iae){
throw new RuntimeException(iae);
}catch(java.lang.reflect.InvocationTargetException ite){
if((ite.getTargetException() instanceof RuntimeException))
throw (RuntimeException)ite.getCause();
if((ite.getTargetException() instanceof Error))
throw (Error)ite.getCause();
//ite.getTargetException().printStackTrace();
throw new RuntimeException(ite.getCause());
}
}
/** Return an exception, but drop the top N frames (to hide implementation details) */
public static RuntimeException exceptionDrop(int n, String msg){
RuntimeException rte = new RuntimeException(msg);
StackTraceElement[] st = rte.getStackTrace(), nst = new StackTraceElement[st.length-n-2];
for(int i = n+2; i < st.length; i++)
nst[i-n-2] = st[i];
rte.setStackTrace(nst);
return rte;
}
/** Add an element to the top of a StackTrace, also used to hide implementation details */
public static RuntimeException addTop(RuntimeException rte, StackTraceElement top){
StackTraceElement[] st = rte.getStackTrace(), nst = new StackTraceElement[st.length+1];
for(int i = 0; i < st.length; i++)
nst[i+1] = st[i];
nst[0] = top;
rte.setStackTrace(nst);
return rte;
}
/** Return a String representation of the given arbitrary Object */
public static String display(Object o){ return display(o,""); }
/** Return a String representation of the given arbitrary Object */
public static String display(Object o, String idt){
if(o instanceof Character){ return display(o, char.class,idt); }
if(o instanceof Short){ return display(o,short.class,idt); }
if(o instanceof Integer){ return display(o,int.class,idt); }
if(o instanceof Long){ return display(o,long.class,idt); }
if(o instanceof Float){ return display(o,float.class,idt); }
if(o instanceof Double){ return display(o,double.class,idt); }
if(o instanceof Boolean){ return display(o,boolean.class,idt); }
return display(o,o.getClass(),idt);
}
/** Return a String representation of the given Object of the given Class */
public static String display(Object o, Class> c, String idt){
if(c.equals(String.class))return "\""+escape(o.toString())+"\"";
if(c.equals(char.class) || c.equals(Character.class))
return "\'"+escape(o.toString())+"\'";
if(c.isPrimitive())return o.toString();
c = o.getClass();
String ret = c.getSimpleName()+"(";
Field[] fs = fields(c);
if(fs.length > 0)ret += "\n"+idt;
boolean first = true;
for(Field f : fs){
Class> fc = f.getType();
try{
ret += (!first?(", \n"+idt):"")+f.getName()+" = "+
display(f.get(o),fc,idt+repeat(' ',f.getName().length()+4));
if(first)first = false;
}catch(Exception e){ throw new RuntimeException(e); }
}
return ret+")";
}
/** Repeat a character a bunch of times */
public static String repeat(char c, int times){
if(times < 0)return "";
return repeat(c, times-1)+c;
}
/** Return a String with non-printing characters expanded/escaped */
private static String escape(String s){
char str[] = s.toCharArray();
StringBuffer ret = new StringBuffer("");
for(char c:str)ret.append(escape(c));
return ret.toString();
}
/** Return a String for a single expanded/escaped character*/
public static String escape(char c){
switch(c){
case '\n':return "\\n"; case '\t':return "\\t";
case '\b':return "\\b"; case '\r':return "\\r";
case '\f':return "\\f"; case '\\':return "\\\\";
case '\'':return "\\'"; case '\"':return "\\\"";
default: return ""+c;
}
}
/** Retrieve the (transitive) fields of the given class */
public static Field[] fields(Class> c){
java.util.ArrayList fs = new java.util.ArrayList();
while(c != null && !c.equals(Object.class)){
for(Field f:c.getDeclaredFields()){
if(!java.lang.reflect.Modifier.isStatic(f.getModifiers())){
if(!f.isAccessible())
f.setAccessible(true);
fs.add(f);
}
}
c = c.getSuperclass();
}
return fs.toArray(new Field[0]);
}
/** Return a String representing an SExp of the given arbitrary Object */
public static String toSExp(Object o){
if(o instanceof Character){ return toSExp(o, char.class); }
if(o instanceof Short){ return toSExp(o,short.class); }
if(o instanceof Integer){ return toSExp(o,int.class); }
if(o instanceof Long){ return toSExp(o,long.class); }
if(o instanceof Float){ return toSExp(o,float.class); }
if(o instanceof Double){ return toSExp(o,double.class); }
if(o instanceof Boolean){ return toSExp(o,boolean.class); }
return toSExp(o,o.getClass());
}
/** Return a String representing an SExp of the given Object of the given Class */
private static String toSExp(Object o, Class> c){
if(c.equals(String.class))return "\""+escape(o.toString())+"\"";
if(c.equals(char.class) || c.equals(Character.class))
return "\'"+escape(o.toString())+"\'";
if(c.isPrimitive())return o.toString();
c = o.getClass();
String ret = "("+c.getName();
Field[] fs = fields(c);
for(Field f : fs){
try{
ret += " "+toSExp(f.get(o));
}catch(Exception e){ throw new RuntimeException(e); }
}
return ret+")";
}
}