package edu.cmu.minorthird.util; import java.lang.reflect.Method; import org.apache.log4j.Logger; /** * Utilities for reflection. */ public class RefUtils { private static Logger log = Logger.getLogger(RefUtils.class); private static int LHS=0, RHS=1; static private String toGetter(String s) { return "get"+s.substring(0,1).toUpperCase()+s.substring(1); } static private String toSetter(String s) { return "set"+s.substring(0,1).toUpperCase()+s.substring(1); } /** * Creates an instance of class c, initialized with the string s. * String can be something like "true", "false", "1041", "13.56", or * the name of a class (for instance * "text.learn.SequentialLearner"). */ static private Object toObject(String s,Class<?> c) { if ((c==Boolean.class || c==boolean.class) && s.equalsIgnoreCase("true")) return new Boolean(true); else if ((c==Boolean.class || c==boolean.class) && s.equalsIgnoreCase("false")) return new Boolean(false); else if (c==Integer.class || c==int.class) return new Integer(StringUtil.atoi(s)); else if (c==Double.class || c==double.class) return new Double(StringUtil.atof(s)); else try { return Class.forName(s).newInstance(); } catch (Exception ex1) { try { return Class.forName("edu.cmu.minorthird."+s).newInstance(); } catch (Exception ex2) { try{ int i = s.lastIndexOf('.'); int len = s.length(); String s2 = s.substring(0,i) + "$" + s.substring(i+1,len); return Class.forName("edu.cmu.minorthird."+s2).newInstance(); } catch (Exception ex3){ try { int i = s.lastIndexOf('.'); int len = s.length(); String s2 = s.substring(0,i) + "$" + s.substring(i+1,len); return Class.forName(s2).newInstance(); } catch (Exception ex4){ throw new IllegalArgumentException("can't create instance of '"+s+"' or 'edu.cmu.minorthird."+s+"'"); } } } } } /** * Returns a modified copy of the object. * * @param modifications a comma or semi-colon separated list of * strings of the form LHS=RHS, where RHS is something that can be * passed to toObject(), and LHS is a period-separated chain of * getters/setters, where only the last item is a setter. * <p> * Example:<br> * <code>RefUtils.modify( * new StackedSequenceLearner(new MaxEntLearner(),1),<br> * "params.historySize=1,params.futureSize=0")<br> * </code> * is the same as: * <code> * StackedSequenceLearner a = new StackedSequenceLearner(new MaxEntLearner(),1);<br> * a.getParams().setHistorySize(1);<br> * a.getParams().setFutureSize(0);<br> * </code> */ public static Object modify(Object obj,String modifications) { String[] mods = modifications.split("[,;]\\s*"); for (int i=0; i<mods.length; i++) { String[] sides = mods[i].split("="); if (sides.length!=2) { log.warn("Illegal modification (should be of the form x=y): "+mods[i]); continue; } String[] path = sides[LHS].split("\\."); Object objToChange=obj; try { for (int j=0; j<path.length-1; j++) { Method m = objToChange.getClass().getMethod(toGetter(path[j]),new Class[]{}); objToChange = m.invoke(objToChange, new Object[]{}); } // find a setter method m Method m = null; Method ms[] = objToChange.getClass().getMethods(); String setterName = toSetter(path[path.length-1]); for (int k=0; k<ms.length; k++) { if (setterName.equals(ms[k].getName())) { m = ms[k]; break; } } if (m==null) log.warn("No setter defined for '"+path[path.length-1]+"'"); else { Class<?>[] expectedClasses = m.getParameterTypes(); Object rhs = toObject(sides[RHS], expectedClasses[0]); m.invoke(objToChange, new Object[]{rhs}); } } catch (Exception ex) { log.warn("Can't execute modification '"+mods[i]+"': error was "+ex); } } return obj; } }