1 18 19 package org.objectweb.jac.core.rtti; 20 21 import java.lang.reflect.Array ; 22 import java.lang.reflect.Field ; 23 import java.lang.reflect.InvocationTargetException ; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.Vector ; 29 import org.apache.log4j.Logger; 30 import org.objectweb.jac.util.WrappedThrowableException; 31 import java.util.ArrayList ; 32 33 46 47 public class CollectionItem extends FieldItem { 48 49 static Logger logger = Logger.getLogger("rtti.collection"); 50 51 protected ClassItem componentType; 52 53 58 59 64 public CollectionItem(Field delegate, ClassItem parent) 65 throws InvalidDelegateException 66 { 67 super(delegate,parent); 68 type = delegate.getType(); 69 if (!RttiAC.isCollectionType(type)) { 70 throw new InvalidDelegateException(delegate,"not a collection type"); 71 } 72 } 73 74 80 public CollectionItem(String name, List path, ClassItem parent) 81 throws InvalidDelegateException 82 { 83 super(name,path,parent); 84 if (!RttiAC.isCollectionType(type)) { 85 throw new InvalidDelegateException(parent.getName()+"."+name,"Not a collection type"); 86 } 87 } 88 89 95 public CollectionItem(String name, MethodItem getter, ClassItem parent) { 96 super(name,getter,parent); 97 } 98 99 MethodItem[] addingMethods = MethodItem.emptyArray; 100 101 107 108 public MethodItem[] getAddingMethods() { 109 ((ClassItem)parent).buildFieldInfo(); 110 return addingMethods; 111 } 112 113 117 public boolean hasAdder() { 118 ((ClassItem)parent).buildFieldInfo(); 119 return addingMethods.length>0; 120 } 121 122 MethodItem adder; 123 127 public MethodItem getAdder() { 128 ((ClassItem)parent).buildFieldInfo(); 129 if (adder!=null) 130 return adder; 131 else if (addingMethods.length>0) 132 return addingMethods[0]; 133 else if (isExpression) 134 return ((CollectionItem)getPathTop()).getAdder(); 135 else 136 return null; 137 } 138 142 public void setAdder(MethodItem adder) { 143 this.adder = adder; 144 } 145 146 151 152 public void setAddingMethods( MethodItem[] addingMethods ) { 153 this.addingMethods = addingMethods; 154 } 155 156 161 162 public void addAddingMethod(MethodItem addingMethod) { 163 if (addingMethods.length == 0) { 164 addingMethods = new MethodItem[] { addingMethod }; 165 } else { 166 MethodItem[] tmp = new MethodItem[addingMethods.length + 1]; 167 System.arraycopy(addingMethods, 0, tmp, 0, addingMethods.length); 168 tmp[addingMethods.length] = addingMethod; 169 addingMethods = tmp; 170 if (getLongName().startsWith("org.objectweb.jac.")) 171 logger.debug("Adders for "+getLongName()+": "+Arrays.asList(tmp)); 172 else 173 logger.warn("Adders for "+getLongName()+": "+Arrays.asList(tmp)); 174 } 175 } 176 177 182 public CollectionItem getCollection() { 183 if (isExpression) { 184 return (CollectionItem)getPathTop(); 185 } else { 186 return this; 187 } 188 } 189 190 195 public ClassItem getComponentType() { 196 ((ClassItem)parent).buildFieldInfo(); 197 if (componentType!=null) 198 return componentType; 199 if (isArray()) { 200 componentType = ClassRepository.get().getClass(getType().getComponentType()); 201 } else { 202 203 if (isExpression) { 204 componentType = ((CollectionItem)getPathTop()).getComponentType(); 205 } else { 206 MethodItem adder = getAdder(); 207 if (adder!=null && adder.getParameterCount()>0) { 208 if (isMap()) { 209 if (isIndex()) 210 componentType = adder.getParameterTypeItem( 211 adder.getParameterCount()-1); 212 else { 213 componentType = 214 ClassRepository.get().getClass( 215 "java.util.Map$Entry"); 216 } 217 } else { 218 if (adder.getParameterCount()==1) 219 componentType = adder.getParameterTypeItem(0); 220 else if (adder.getParameterCount()==2) { 221 int itemArg = adder.getCollectionItemArgument(); 222 if (itemArg!=-1) 223 componentType = adder.getParameterTypeItem(itemArg); 224 } 225 if (componentType==null) 226 logger.warn( 227 "Cannot determine component type of "+getName()+ 228 " from adder "+adder.getFullName()); 229 } 230 } 231 } 232 } 233 234 if (componentType==null) { 235 if (!isMap() || isIndex()) 236 logger.warn("Component type of "+this+" is null"); 237 if (adder==null && !isCalculated()) 238 logger.warn("no adder fo "+this+" "+getParent()); 239 } 240 return componentType; 241 } 242 243 247 public void setComponentType(ClassItem componentType) { 248 this.componentType = componentType; 249 } 250 251 public boolean isAddingMethod(MethodItem method) { 252 ((ClassItem)parent).buildFieldInfo(); 253 return Arrays.asList(addingMethods).contains(method); 254 } 255 256 261 public final void addThroughAdder(Object substance, Object value) { 262 logger.debug("addThroughAdder "+substance+"."+getName()+","+value); 263 MethodItem adder = getAdder(); 264 if (adder!=null) { 265 try { 266 adder.invoke(substance,new Object [] { value }); 268 return; 269 } catch (WrappedThrowableException e) { 270 Throwable target = e.getWrappedThrowable(); 271 if (target instanceof InvocationTargetException ) 272 throw e; 273 else 274 logger.error("addThroughAdder "+substance+"."+getName()+","+value,e); 275 } 276 } 277 278 logger.warn("No adder for collection " + this); 279 add(substance,value,null); 280 } 281 282 283 public final void putThroughAdder(Object substance, Object value, Object key) { 284 logger.debug("putThroughAdder "+substance+"."+getName()+","+key+"->"+value); 285 MethodItem adder = getAdder(); 286 if (adder!=null) { 287 try { 288 if (adder.getParameterCount()==2) 290 adder.invoke(substance,new Object [] { key, value }); 291 else if (adder.getParameterCount()==1) 292 adder.invoke(substance,new Object [] { value }); 293 else 294 throw new RuntimeException ("putThroughAdder("+substance+","+value+","+key+ 295 ") :Wrong number off parameters for adder "+adder); 296 return; 297 } catch (WrappedThrowableException e) { 298 Throwable target = e.getWrappedThrowable(); 299 if (target instanceof InvocationTargetException ) 300 throw e; 301 else 302 logger.error("putThroughAdder "+substance+"."+getName()+","+value,e); 303 } 304 } 305 306 logger.warn("No adder for collection " + this); 307 add(substance,value,key); 308 } 309 310 MethodItem[] removingMethods = MethodItem.emptyArray; 311 312 317 318 public MethodItem[] getRemovingMethods() { 319 ((ClassItem)parent).buildFieldInfo(); 320 return removingMethods; 321 } 322 323 327 public boolean hasRemover() { 328 ((ClassItem)parent).buildFieldInfo(); 329 return removingMethods.length>0; 330 } 331 332 MethodItem remover; 333 337 public MethodItem getRemover() { 338 ((ClassItem)parent).buildFieldInfo(); 339 if (remover!=null) 340 return remover; 341 else if (removingMethods.length>0) 342 return removingMethods[0]; 343 else if (isExpression) 344 return ((CollectionItem)getPathTop()).getRemover(); 345 else 346 return null; 347 } 348 349 353 public void setRemover(MethodItem remover) { 354 this.remover = remover; 355 } 356 357 362 363 public void setRemovingMethods( MethodItem[] removingMethods ) { 364 this.removingMethods = removingMethods; 365 } 366 367 372 373 public void addRemovingMethod( MethodItem removingMethod ) { 374 if (removingMethods == null) { 375 removingMethods = new MethodItem[] { removingMethod }; 376 } else { 377 MethodItem[] tmp = new MethodItem[removingMethods.length + 1]; 378 System.arraycopy(removingMethods, 0, tmp, 0, removingMethods.length); 379 tmp[removingMethods.length] = removingMethod; 380 removingMethods = tmp; 381 } 382 } 383 384 public boolean isRemovingMethod(MethodItem method) { 385 ((ClassItem)parent).buildFieldInfo(); 386 return Arrays.asList(removingMethods).contains(method); 387 } 388 389 399 400 public void clearMethods() { 401 super.clearMethods(); 402 if (removingMethods != null) { 403 for (int i=0; i<removingMethods.length; i++) { 404 removingMethods[i].removeRemovedCollection(this); 405 } 406 removingMethods = null; 407 } 408 if (addingMethods != null) { 409 for (int i=0; i<addingMethods.length; i++) { 410 addingMethods[i].removeAddedCollection(this); 411 } 412 addingMethods = null; 413 } 414 } 415 416 425 426 public void clear(Object substance) { 427 logger.debug(this+".clear("+substance+")"); 428 Field f = (Field ) delegate; 429 430 try { 431 Object collection = f.get(substance); 432 logger.debug("collection="+System.identityHashCode(collection)); 433 if (collection!=null) { 434 logger.debug("type="+collection.getClass().getName()); 435 if (collection instanceof Collection ) { 436 ((Collection )collection).clear(); 437 } else if (collection instanceof Map ) { 438 ((Map )collection).clear(); 439 } else if (getType().isArray()) { 440 f.set(substance, Array.newInstance(getType().getComponentType(),0)); 441 } 442 } 443 } catch (Exception e) { 444 logger.error("clear failed for "+this+" on "+substance,e); 445 } 446 } 447 448 453 454 public boolean isArray() { 455 return getType()!=null && getType().isArray(); 456 } 457 458 473 474 public Collection getActualCollection(Object substance) { 475 Object value = null; 476 477 try { 478 value = ((Field )delegate).get(substance); 479 } catch (Exception e) { 480 logger.error("getActualCollection("+getName()+") failed",e); 481 return null; 482 } 483 return toCollection(value); 484 } 485 486 502 public Collection getActualCollectionThroughAccessor(Object substance) { 503 Object value = getThroughAccessor(substance); 504 return value!=null ? toCollection(value) : new ArrayList (); 505 } 506 507 517 518 public Collection toCollection(Object value) { 519 if (value == null) return null; 520 521 if (value instanceof Collection ) { 522 return (Collection )value; 523 } else if (value instanceof Map ) { 524 if (isIndex()) 525 return ((Map )value).values(); 526 else 527 return ((Map )value).entrySet(); 528 } else if (value.getClass().isArray()) { 529 if (value.getClass().getComponentType()==Object .class) { 530 return Arrays.asList( (Object []) value ); 531 } else { 532 int length = Array.getLength(value); 533 Vector result = new Vector (length); 534 for (int i=0; i<length; i++) { 535 result.add(Array.get(value,i)); 536 } 537 return result; 538 } 539 } 540 return null; 541 } 542 543 561 public void add(Object substance, Object newItem, Object extraInfos) { 562 563 Field f = (Field ) delegate; 564 565 try { 566 if (isSet() || isList()) { 567 if ( extraInfos == null ) { 569 ((Collection )f.get(substance)).add(newItem); 570 } else { 571 ((List )f.get(substance)).add( 572 ((Integer )extraInfos).intValue(), newItem); 573 } 574 } else if (isMap()) { 575 ((Map )f.get(substance)).put(extraInfos, newItem); 577 } else if (isArray()) { 578 if (extraInfos == null) { 581 Object oldArray = f.get(substance); 582 int index = 0; 583 if (oldArray != null) { 584 index = Array.getLength(oldArray); 585 } 586 Object newArray; 587 f.set( substance, 588 newArray = Array.newInstance( 589 getType().getComponentType(), index+1 ) ); 590 591 if (oldArray != null) { 592 for(int i=0; i<index; i++) { 593 Array.set(newArray, i, Array.get(oldArray, i)); 594 } 595 } 596 597 Array.set(newArray, index, newItem); 598 599 } else { 600 ((Object [])f.get(substance))[((Integer )extraInfos).intValue()] = newItem; 601 } 603 } 604 } catch ( Exception e ) { 605 logger.error("add "+substance+"."+getName()+" "+newItem+","+extraInfos,e); 606 } 607 } 608 609 614 public void removeThroughRemover(Object substance, Object item) { 615 ((ClassItem)parent).buildFieldInfo(); 616 MethodItem remover = getRemover(); 617 if (remover!=null) { 618 remover.invoke(substance,new Object [] {item}); 619 } else { 620 logger.warn("No remover for collection "+this); 621 remove(substance,item,null); 622 } 623 } 624 625 643 644 public void remove(Object substance, Object item, Object extraInfos) { 645 Field f = (Field )delegate; 646 647 try { 648 649 if (Collection .class.isAssignableFrom(getType())) { 650 if (extraInfos == null) { 652 ((Collection )f.get(substance)).remove(item); 653 } else { 654 int index = ((Integer )extraInfos).intValue(); 655 ((List )f.get(substance)).remove(index); 656 } 657 } else if (Map .class.isAssignableFrom(getType())) { 658 ((Map )f.get(substance)).remove(extraInfos); 660 } else if (getType().isArray()) { 661 if (extraInfos == null) { 664 Object oldArray = f.get(substance); 665 int index = 0; 666 if (oldArray != null) { 667 index = Array.getLength(oldArray); 668 } 669 Object newArray; 670 f.set( substance, 671 newArray = Array.newInstance( 672 getType().getComponentType(), index-1 ) ); 673 674 if (oldArray != null) { 675 for( int i=0; i<index; i++) { 676 Array.set(newArray, i, Array.get(oldArray,i)); 677 } 678 } 679 680 682 } else { 683 } 686 } 687 } catch (Exception e) { 688 logger.error("remove "+substance+"."+getName()+" "+item+","+extraInfos,e); 689 } 690 691 } 692 693 699 public boolean contains(Object substance, Object object) { 700 if (!isArray()) { 701 Collection collection = (Collection )getThroughAccessor(substance); 702 return collection.contains(object); 703 } else { 704 throw new RuntimeException ( 705 "CollectionItem.contains(substance,object) is not implemented for arrays"); 706 } 707 } 708 709 public Object getMap(Object substance, Object key) { 710 if (!isMap()) { 711 throw new RuntimeException ("Cannot call getMap() on "+this); 712 } 713 try { 714 return getMap(substance).get(key); 715 } catch(IllegalAccessException e) { 716 logger.error("getMap "+substance+"."+getName()+" "+key,e); 717 } 718 return null; 719 } 720 721 protected Map getMap(Object substance) throws IllegalAccessException { 722 return (Map )((Field )delegate).get(substance); 723 } 724 725 730 731 public boolean isList() { 732 return List .class.isAssignableFrom(getType()); 733 } 734 735 740 741 public boolean isMap() { 742 return Map .class.isAssignableFrom(getType()); 743 } 744 745 public boolean isIndex() { 746 return RttiAC.isIndex(this); 747 } 748 749 754 755 public boolean isSet() { 756 return java.util.Set .class.isAssignableFrom(getType()); 757 } 758 759 764 765 public boolean isPrimitive() { 766 return false; 767 } 768 769 774 775 public boolean isReference() { 776 return false; 777 } 778 779 public FieldItem clone(ClassItem parent) { 780 CollectionItem clone = null; 781 try { 782 if (isCalculated) 783 clone = new CollectionItem(name,getter,parent); 784 else 785 clone = new CollectionItem((Field )delegate,parent); 786 clone.setAdder(adder); 787 clone.setRemover(remover); 788 } catch(Exception e) { 789 logger.error("Failed to clone collection "+this); 790 } 791 return clone; 792 } 793 794 public static final CollectionItem[] emptyArray = new CollectionItem[0]; 795 } 796 | Popular Tags |