1 package jfun.yan.xml.nut; 2 3 4 import java.beans.BeanInfo ; 5 import java.beans.IndexedPropertyDescriptor ; 6 import java.beans.IntrospectionException ; 7 import java.beans.Introspector ; 8 import java.beans.PropertyDescriptor ; 9 import java.lang.reflect.InvocationTargetException ; 10 import java.lang.reflect.Method ; 11 import java.util.ArrayList ; 12 import java.util.HashMap ; 13 import java.util.Locale ; 14 import java.util.Map ; 15 16 import jfun.yan.Binder; 17 import jfun.yan.Component; 18 import jfun.yan.xml.ConfigurationException; 19 20 21 22 23 30 public class NutIntrospector implements java.io.Serializable { 31 private final HashMap cache = new HashMap (); 32 38 public NutDescriptor getNutDescriptor(final Class type) 39 throws IntrospectionException { 40 NutDescriptor desc = (NutDescriptor)cache.get(type); 41 if(desc == null){ 42 if(!Nut.class.isAssignableFrom(type)){ 43 throw new IllegalArgumentException ("only Nut class is introspectable."); 44 } 45 52 desc = new NutDescriptor(type); 53 cache.put(type, desc); 54 final Evaluator evaluator = getEvaluator(type); 55 desc.setEvaluator(evaluator); 56 desc.setPropertyDescriptors(getProperties(type)); 57 populateSub(type, desc); 58 } 59 return desc; 60 } 61 private Evaluator getEvaluator(final Class type){ 62 if(ComponentNut.class.isAssignableFrom(type)){ 63 return new Evaluator(){ 64 public Object eval(Object obj) 65 throws Exception { 66 final ComponentNut nut = (ComponentNut)obj; 67 return nut.eval(); 68 } 69 public Class getType(){ 70 return Component.class; 71 } 72 }; 73 } 74 else if(BinderNut.class.isAssignableFrom(type)){ 75 return new Evaluator(){ 76 public Object eval(Object obj) { 77 final BinderNut nut = (BinderNut)obj; 78 try{ 79 return nut.eval(); 80 } 81 catch(Exception e){ 82 throw new ConfigurationException(e, nut.getTagLocation()); 83 } 84 } 85 public Class getType(){ 86 return Binder.class; 87 } 88 }; 89 } 90 else{ 91 try{ 92 final Method mtd = type.getMethod("eval", null); 93 final Class rtype = mtd.getReturnType(); 94 return new Evaluator(){ 95 public Object eval(Object obj){ 96 final Nut nut = (Nut)obj; 97 try{ 98 final Object r = mtd.invoke(nut, null); 99 if(void.class.equals(rtype)){ 100 return nut; 101 } 102 else return r; 103 } 104 catch(InvocationTargetException e){ 105 throw new ConfigurationException(e.getTargetException(), nut.getTagLocation()); 106 } 107 catch(Exception e){ 108 throw new ConfigurationException(e, nut.getTagLocation()); 109 } 110 } 111 public Class getType(){ 112 return (void.class.equals(rtype)?type:rtype); 113 } 114 }; 115 } 116 catch(NoSuchMethodException e){ 117 return new Evaluator(){ 118 public Object eval(Object nut){ 119 return nut; 120 } 121 public Class getType(){ 122 return type; 123 } 124 }; 125 } 126 } 127 } 128 129 private Map getProperties(Class type) 130 throws IntrospectionException { 131 final BeanInfo info = Introspector.getBeanInfo(type); 132 final PropertyDescriptor [] pdescs = info.getPropertyDescriptors(); 133 final HashMap ret = new HashMap (); 134 for(int i=0; i<pdescs.length; i++){ 135 final PropertyDescriptor desc = pdescs[i]; 136 if(desc.getWriteMethod()!=null && !(desc instanceof IndexedPropertyDescriptor )){ 137 ret.put(desc.getName(), desc); 138 } 139 } 140 return ret; 141 } 142 private final void populateSub(Class type, NutDescriptor desc) 145 throws IntrospectionException { 146 final HashMap subs= new HashMap (); 147 final Method [] mtds = type.getMethods(); 148 final ArrayList anonymous_adders = new ArrayList (); 149 Class etype = null; 150 Method r = null; 151 for(int i=0; i<mtds.length; i++){ 152 final Method mtd = mtds[i]; 153 final String mname = mtd.getName(); 154 if(mname.equals("set")){ 155 final Class [] ptypes = mtd.getParameterTypes(); 156 if(ptypes.length != 1){ 157 continue; 158 } 159 final Class ptype = ptypes[0]; 160 if(!ptype.isArray()){ 161 continue; 162 } 163 final Class etype2 = ptype.getComponentType(); 164 if(etype != null){ 165 if(etype.isAssignableFrom(etype2)){ 166 etype = etype2; 168 r = mtd; 169 } 170 } 171 else{ 172 r = mtd; 173 etype = etype2; 174 } 175 } 176 else if(mname.startsWith(ADDER)){ 177 final Class [] ptypes = mtd.getParameterTypes(); 178 if(ptypes.length!=1){ 179 continue; 180 } 181 Class ptype = ptypes[0]; 182 final String elem_name = mname.substring(3).toLowerCase(Locale.US); 183 if(subs.containsKey(elem_name)){ 184 throw new IllegalArgumentException ("duplicate adder: "+mname); 185 } 186 if(elem_name.length()==0){ 187 192 anonymous_adders.add(new Method1(mtd, ptype)); 193 } 194 else{ 195 if(!Nut.class.isAssignableFrom(ptype)) 196 continue; 197 desc.putAdder(elem_name, mtd); 198 if(elem_name.length()>0){ 199 subs.put(elem_name, getNutDescriptor(ptype)); 200 } 201 } 202 } 203 } 204 if(r!=null){ 205 desc.setCollectionDescriptor( 206 new NutDescriptor.CollectionDescriptor(etype, r) 207 ); 208 } 209 else{ 210 desc.setRegularDescriptor( 211 new NutDescriptor.RegularDescriptor(subs) 212 ); 213 } 214 final Method1[] anonymous = new Method1[anonymous_adders.size()]; 215 anonymous_adders.toArray(anonymous); 216 desc.setAdderSuite(new MethodSuite(ADDER, anonymous)); 217 } 218 private static final String ADDER = "add"; 219 } 220 | Popular Tags |