1 package jfun.yan.util; 2 3 import java.lang.reflect.Constructor ; 4 import java.lang.reflect.Field ; 5 import java.lang.reflect.Member ; 6 import java.lang.reflect.Method ; 7 import java.lang.reflect.Modifier ; 8 import java.util.ArrayList ; 9 import java.util.Arrays ; 10 import java.util.HashMap ; 11 import java.util.Iterator ; 12 import java.util.List ; 13 import java.util.Map ; 14 15 import jfun.util.Misc; 16 17 37 public class ClassDescriptor<T> { 38 39 private static final class Sig{ 40 private final String name; 41 private final Params params; 42 43 public String getName() { 44 return name; 45 } 46 public Params getParams() { 47 return params; 48 } 49 Sig(String name, Class [] ptypes){ 50 this(name, new Params(ptypes)); 51 } 52 Sig(String name, Params params) { 53 this.name = name; 54 this.params = params; 55 } 56 public boolean equals(Object obj) { 57 if(obj instanceof Sig){ 58 final Sig other = (Sig)obj; 59 return name.equals(other.name)&¶ms.equals(other.params); 60 } 61 return false; 62 } 63 public int hashCode() { 64 return name.hashCode()*31+params.hashCode(); 65 } 66 public String toString() { 67 return name+params; 68 } 69 } 70 private static final Class [] noparams = new Class [0]; 71 private static final class Params{ 72 private final Class [] ptypes; 73 Params(Class [] ptypes) { 74 this.ptypes = ptypes==null?noparams:ptypes; 75 } 76 public Class [] getParameterTypes() { 77 return ptypes; 78 } 79 public boolean equals(Object obj) { 80 if(obj instanceof Params){ 81 final Params other = (Params)obj; 82 return Arrays.equals(ptypes, other.ptypes); 83 } 84 else return false; 85 } 86 public int hashCode() { 87 return Misc.getArrayHashcode(ptypes); 88 } 89 public String toString() { 90 return Utils.toString(ptypes); 91 } 92 } 93 private static boolean isSub(Method a, Method b){ 94 return 95 a.getDeclaringClass().isAssignableFrom(b.getDeclaringClass()) 96 && Arrays.equals(a.getParameterTypes(), b.getParameterTypes()); 97 } 98 private static Object combine(Method a, Method b){ 99 if(isSub(a,b)){ 100 return b; 101 } 102 else if(isSub(b,a)){ 103 return a; 104 } 105 else{ 106 final ArrayList list = new ArrayList (); 107 list.add(a); 108 list.add(b); 109 return list; 110 } 111 } 112 private static ArrayList merge(ArrayList mbrs, Method b){ 113 final int sz = mbrs.size(); 114 final ArrayList result = new ArrayList (sz+1); 115 for(int i=0; i<sz; i++){ 116 final Method mbr = (Method )mbrs.get(i); 117 if(isSub(b, mbr)){ 118 return mbrs; 120 } 121 else if(!isSub(mbr, b)){ 122 result.add(mbr); 124 } 125 } 126 result.add(b); 127 return result; 128 } 129 private final class Methods { 130 private final HashMap mtds = new HashMap (); 131 private final HashMap mtd_names = new HashMap (); 132 boolean isEmpty(){ 133 return mtds.isEmpty(); 134 } 135 void addAll(Methods other){ 136 for(Iterator it = other.mtds.keySet().iterator(); it.hasNext();){ 137 final Sig sig = (Sig)it.next(); 138 final Method mtd = other.getMethod(sig); 139 addMethod(sig, mtd); 140 } 141 } 142 void addMethod(Sig sig, Method mtd){ 143 final String name = sig.getName(); 144 final Method old = (Method )mtds.get(sig); 145 if(old!=null && 146 !old.getDeclaringClass().isAssignableFrom(mtd.getDeclaringClass())){ 147 return; 149 } 150 final Object dup = mtd_names.get(name); 151 if(dup==null){ 152 mtd_names.put(name, mtd); 153 } 154 else{ 155 if(dup instanceof Method ){ 156 mtd_names.put(name, combine((Method )dup, mtd)); 157 } 158 else{ 159 final ArrayList dups = (ArrayList )dup; 160 mtd_names.put(name, merge(dups, mtd)); 162 } 163 } 164 mtds.put(sig, mtd); 165 } 166 167 Method getMethod(Sig sig){ 168 return (Method )mtds.get(sig); 169 } 170 Method filterMethod(String name, MethodPredicate pred) 171 throws AmbiguityException{ 172 final Object r = mtd_names.get(name); 173 if(r==null) return null; 174 if(r instanceof Method ){ 175 final Method ret = (Method )r; 176 if(pred.isMethod(ret)){ 177 return ret; 178 } 179 else return null; 180 } 181 else{ 182 final List list = (List )r; 183 Method ret = null; 184 final int sz = list.size(); 185 for(int i=0;i<sz;i++){ 186 final Method m = (Method )list.get(i); 187 if(pred.isMethod(m)){ 188 if(ret!=null){ 189 throw new AmbiguityException("type " 190 +Misc.getTypeName(type) + 191 " has more than one " + pred + "."); 192 } 193 ret = m; 194 } 195 } 196 return ret; 197 } 198 } 199 Method findMethod(String name) 200 throws AmbiguityException{ 201 final Object r = mtd_names.get(name); 202 if(r==null) return null; 203 if(r instanceof Method ){ 204 return (Method )r; 205 } 206 else{ 207 final List list = (List )r; 208 if(list.size()>1){ 209 throw new AmbiguityException("type " 210 +Misc.getTypeName(type) + 211 " has more than one qualified methods named "+name); 212 } 213 return (Method )list.get(0); 214 } 215 } 216 230 } 231 private static final class Fields{ 232 private final HashMap flds = new HashMap (); 233 boolean isEmpty(){ 234 return flds.isEmpty(); 235 } 236 void addField(String name, Field fld){ 237 final Field old = (Field )flds.get(name); 238 if(old!=null && 239 !old.getDeclaringClass().isAssignableFrom(fld.getDeclaringClass())){ 240 return; 241 } 242 flds.put(name, fld); 243 } 244 Field getField(String name){ 245 return (Field )flds.get(name); 246 } 247 void addAll(Fields other){ 248 for(Iterator it = other.flds.keySet().iterator(); it.hasNext();){ 249 final String name = (String )it.next(); 250 final Field fld = other.getField(name); 251 addField(name, fld); 252 } 253 } 254 } 255 private final Class <T> type; 257 258 private final Methods mtds = new Methods(); 259 260 private final Methods priv_mtds = new Methods(); 263 264 265 private final Fields flds = new Fields(); 267 private final Fields priv_flds = new Fields(); 271 272 273 private final HashMap ctors = new HashMap (); 275 private final HashMap priv_ctors = new HashMap (); 277 280 281 282 283 284 void addAll(ClassDescriptor<T> other){ 285 final Class supertype = other.getType(); 287 if(!supertype.isAssignableFrom(type)){ 288 throw new IllegalArgumentException ( 289 "only parent type can be added to this descriptor."); 290 } 291 flds.addAll(other.flds); 292 priv_flds.addAll(other.priv_flds); 294 295 mtds.addAll(other.mtds); 296 priv_mtds.addAll(other.priv_mtds); 298 } 299 private static boolean isPublic(Member mbr){ 300 return Modifier.isPublic(mbr.getModifiers()); 301 } 302 private static boolean isPublic(Class c){ 303 return Modifier.isPublic(c.getModifiers()); 304 } 305 void addConstructor(Constructor <T> ctor){ 306 final Params params = new Params(ctor.getParameterTypes()); 307 if(isPublic(ctor)){ 308 if(!isPublic(type)){ 309 Utils.forceAccess(ctor); 310 } 311 ctors.put(params, ctor); 312 } 313 else{ 314 Utils.forceAccess(ctor); 315 priv_ctors.put(params, ctor); 316 } 317 } 318 319 void addMethod(Method mtd){ 320 final Sig sig = new Sig(mtd.getName(), mtd.getParameterTypes()); 321 if(isPublic(mtd)){ 322 if(isPublic(mtd.getDeclaringClass())){ 323 mtds.addMethod(sig, mtd); 324 } 325 } 326 Utils.forceAccess(mtd); 327 priv_mtds.addMethod(sig, mtd); 328 } 329 void addField(Field fld){ 330 final String name = fld.getName(); 331 if(isPublic(fld)){ 332 if(isPublic(fld.getDeclaringClass())){ 333 flds.addField(name, fld); 334 } 335 } 336 Utils.forceAccess(fld); 337 priv_flds.addField(name, fld); 338 } 339 private static <T> Constructor <T> findConstructor(Class <T> type, Map from){ 340 if(from.isEmpty()) 341 return null; 342 if(from.size()>1){ 343 throw new AmbiguityException("type " 344 +Misc.getTypeName(type) + 345 " has more than one qualified constructors"); 346 } 347 return (Constructor <T>)from.values().iterator().next(); 348 } 349 private static <T> Constructor <T> findConstructor(Class <T> type, Map from, 350 int param_count){ 351 Constructor result = null; 352 for(Iterator it=from.keySet().iterator();it.hasNext();){ 353 final Params params = (Params)it.next(); 354 if(params.ptypes.length==param_count){ 355 if(result!=null) 356 throw new AmbiguityException("type " 357 +Misc.getTypeName(type) + 358 " has more than one qualified constructors with " 359 + param_count+" formal parameters."); 360 result = (Constructor )from.get(params); 361 } 362 } 363 return result; 364 } 365 371 public Constructor <T> getConstructor(Class [] param_types, 372 boolean suppress_security){ 373 if(suppress_security){ 374 return getAnyConstructor(param_types); 375 } 376 else return getConstructor(param_types); 377 } 378 383 public Constructor <T> getConstructor(Class [] param_types){ 384 final Params params = new Params(param_types); 385 return (Constructor )ctors.get(params); 386 } 387 393 public Constructor <T> getConstructor(boolean suppress_security) 394 throws AmbiguityException{ 395 if(suppress_security) 396 return getAnyConstructor(); 397 else 398 return getConstructor(); 399 } 400 405 public Constructor <T> getConstructor() 406 throws AmbiguityException{ 407 return findConstructor(type, ctors); 408 } 409 410 417 public Constructor <T> getConstructor(int param_count, boolean suppress_security) 418 throws AmbiguityException{ 419 if(suppress_security) 420 return getAnyConstructor(param_count); 421 else 422 return getConstructor(param_count); 423 } 424 430 public Constructor <T> getConstructor(int param_count) 431 throws AmbiguityException{ 432 return findConstructor(type, ctors, param_count); 433 } 434 private Constructor <T> getAnyConstructor(Class [] param_types){ 435 final Params params = new Params(param_types); 436 final Constructor ret = (Constructor )ctors.get(params); 437 if(ret!=null) return ret; 438 return (Constructor )priv_ctors.get(params); 439 } 440 private Constructor <T> getAnyConstructor() 441 throws AmbiguityException{ 442 final Constructor ret = getConstructor(); 443 if(ret==null){ 444 return findConstructor(type, priv_ctors); 445 } 446 else return ret; 447 } 448 private Constructor <T> getAnyConstructor(int param_count) 449 throws AmbiguityException{ 450 final Constructor ret = getConstructor(param_count); 451 if(ret==null){ 452 return findConstructor(type, priv_ctors, param_count); 453 } 454 else return ret; 455 } 456 463 public Method getMethod(String name, boolean suppress_security) 464 throws AmbiguityException{ 465 if(suppress_security) 466 return getAnyMethod(name); 467 else 468 return getMethod(name); 469 } 470 476 public Method getMethod(String name) 477 throws AmbiguityException{ 478 return mtds.findMethod(name); 479 } 480 489 public Method filterMethod(String name, MethodPredicate pred) 490 throws AmbiguityException{ 491 return mtds.filterMethod(name, pred); 492 } 493 505 public Method filterMethod(String name, MethodPredicate pred, 506 boolean suppress_security) 507 throws AmbiguityException{ 508 if(suppress_security) 509 return filterAnyMethod(name, pred); 510 else return filterMethod(name, pred); 511 } 512 private Method filterAnyMethod(String name, MethodPredicate pred){ 513 final Method ret = mtds.filterMethod(name, pred); 514 if(ret!=null) return ret; 515 else return priv_mtds.filterMethod(name, pred); 516 } 517 525 532 537 541 548 public Method getMethod(String name, Class [] param_types, boolean suppress_security){ 549 if(suppress_security) 550 return getAnyMethod(name, param_types); 551 else 552 return getMethod(name, param_types); 553 } 554 560 public Method getMethod(String name, Class [] param_types){ 561 return mtds.getMethod(new Sig(name, param_types)); 562 } 563 private Method getAnyMethod(String name, Class [] param_types){ 564 final Sig sig = new Sig(name, param_types); 565 Method ret = mtds.getMethod(sig); 566 if(ret != null) return ret; 567 return priv_mtds.getMethod(sig); 570 } 571 private Method getAnyMethod(String name) 572 throws AmbiguityException{ 573 Method ret = mtds.findMethod(name); 574 if(ret != null) return ret; 575 return priv_mtds.findMethod(name); 578 } 579 585 591 public Field getField(String name, boolean suppress_security){ 592 if(suppress_security) 593 return getAnyField(name); 594 else 595 return getField(name); 596 } 597 602 public Field getField(String name){ 603 return flds.getField(name); 604 } 605 private Field getAnyField(String name){ 606 Field ret = flds.getField(name); 607 if(ret!=null) return ret; 608 return priv_flds.getField(name); 611 } 612 615 public Class <T> getType(){ 616 return type; 617 } 618 ClassDescriptor(Class <T> type) { 619 this.type = type; 620 } 621 622 } 623 | Popular Tags |