1 18 19 package org.objectweb.jac.core.rtti; 20 21 import java.lang.NoSuchMethodException ; 22 import java.lang.reflect.*; 23 import java.lang.reflect.Modifier ; 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Vector ; 30 import org.apache.log4j.Logger; 31 import org.objectweb.jac.util.*; 32 33 55 56 public class FieldItem extends MemberItem { 57 58 static Class wrappeeClass = ClassRepository.wrappeeClass; 59 static Logger logger = Logger.getLogger("rtti.field"); 60 61 69 70 public static Field[] toFields(FieldItem[] fieldItems) { 71 Field[] res = new Field[fieldItems.length]; 72 for (int i=0; i<fieldItems.length; i++) { 73 if (fieldItems[i] == null) { 74 res[i] = null; 75 } else { 76 res[i] = fieldItems[i].getActualField(); 77 } 78 } 79 return res; 80 } 81 82 87 88 public FieldItem(Field delegate, ClassItem parent) 89 throws InvalidDelegateException 90 { 91 super(delegate,parent); 92 name = delegate.getName(); 93 } 94 95 public FieldItem(ClassItem parent) { 96 super(parent); 97 } 98 99 104 public FieldItem(String name, MethodItem getter, ClassItem parent) { 105 super(parent); 106 isCalculated = true; 107 this.name = name; 108 addAccessingMethod(getter); 109 setGetter(getter); 110 getter.addAccessedField(this); 111 getter.setReturnedField(this); 112 } 113 114 120 public FieldItem(String name, MethodItem getter, MethodItem setter, 121 ClassItem parent) 122 { 123 super(parent); 124 this.name = name; 125 setGetter(getter); 126 setSetter(setter); 127 } 128 129 133 public FieldItem(String expression, List path, ClassItem parent) { 134 super(parent); 135 isCalculated = true; 136 isExpression = true; 137 this.name = expression; 138 this.path = path; 139 type = getPathTop().getType(); 140 } 141 142 boolean isCalculated = false; 143 boolean isExpression = false; 144 String name; 145 Class type; 146 147 List path; 149 150 public FieldItem getPathTop() { 151 return (FieldItem)path.get(path.size()-1); 152 } 153 154 158 public final Object getAttribute(String name) { 159 Object value = super.getAttribute(name); 160 if (value==null) { 161 ClassItem parent = ((ClassItem)getParent()).getSuperclass(); 162 if (parent!=null) { 163 if (parent.hasField(getName())) { 164 value = parent.getField(this.name).getAttribute(name); 165 } 166 } 167 } 168 if (isExpression && value==null) { 169 return ((FieldItem)path.get(path.size()-1)).getAttribute(name); 170 } 171 return value; 172 } 173 174 175 MethodItem[] accessingMethods; 176 177 182 public final MethodItem[] getAccessingMethods() { 183 ((ClassItem)parent).buildFieldInfo(); 184 return accessingMethods; 185 } 186 187 public final boolean hasAccessingMethods() { 188 ((ClassItem)parent).buildFieldInfo(); 189 return accessingMethods!=null && accessingMethods.length>0; 190 } 191 192 197 198 public final void setAccessingMethods(MethodItem[] accessingMethods) { 199 this.accessingMethods = accessingMethods; 200 } 201 202 207 208 public final void addAccessingMethod(MethodItem accessingMethod) { 209 if (accessingMethods == null) { 210 accessingMethods = new MethodItem[] { accessingMethod }; 211 } else { 212 MethodItem[] tmp = new MethodItem[accessingMethods.length + 1]; 213 System.arraycopy(accessingMethods, 0, tmp, 0, accessingMethods.length); 214 tmp[accessingMethods.length] = accessingMethod; 215 accessingMethods = tmp; 216 } 217 } 218 219 MethodItem[] writingMethods; 220 221 226 public final MethodItem[] getWritingMethods() { 227 ((ClassItem)parent).buildFieldInfo(); 228 return writingMethods; 229 } 230 public final boolean hasWritingMethods() { 231 ((ClassItem)parent).buildFieldInfo(); 232 return writingMethods!=null && writingMethods.length>0; 233 } 234 235 240 241 public final void setWritingMethods(MethodItem[] writingMethods) { 242 this.writingMethods = writingMethods; 243 } 244 245 250 251 public final void addWritingMethod(MethodItem writingMethod) { 252 if (writingMethods == null) { 253 writingMethods = new MethodItem[] { writingMethod }; 254 } else { 255 MethodItem[] tmp = new MethodItem[writingMethods.length + 1]; 256 System.arraycopy(writingMethods, 0, tmp, 0, writingMethods.length); 257 tmp[writingMethods.length] = writingMethod; 258 writingMethods = tmp; 259 } 260 } 261 262 265 public void clearMethods() { 266 if (writingMethods != null) { 267 for (int i=0; i<writingMethods.length; i++) { 268 writingMethods[i].removeWrittenField(this); 269 } 270 writingMethods = null; 271 } 272 if (accessingMethods != null) { 273 for (int i=0; i<accessingMethods.length; i++) { 274 accessingMethods[i].removeAccessedField(this); 275 } 276 accessingMethods = null; 277 } 278 } 279 280 FieldItem[] dependentFields = FieldItem.emptyArray; 281 284 public final void addDependentField(FieldItem field) { 285 FieldItem[] tmp = new FieldItem[dependentFields.length+1]; 286 System.arraycopy(dependentFields, 0, tmp, 0, dependentFields.length); 287 tmp[dependentFields.length] = field; 288 dependentFields = tmp; 289 ClassItem superClass = getClassItem().getSuperclass(); 290 if (superClass!=null) { 291 FieldItem superField = superClass.getFieldNoError(getName()); 292 if (superField!=null) 293 superField.addDependentField(field); 294 } 295 } 296 300 public final FieldItem[] getDependentFields() { 301 return dependentFields; 302 } 303 304 309 310 public final Field getActualField() { 311 return (Field)delegate; 312 } 313 314 318 public Object getSubstance(Object substance) { 319 if (isExpression) { 320 Iterator it = path.iterator(); 321 while (it.hasNext() && substance!=null) { 322 FieldItem field = (FieldItem)it.next(); 323 if (!it.hasNext()) { 324 return substance; 325 } 326 substance = field.getThroughAccessor(substance); 327 } 328 return null; 329 } else { 330 return substance; 331 } 332 } 333 334 342 public List getSubstances(Object substance) { 343 Vector substances = new Vector (); 344 substances.add(substance); 345 if (isExpression) { 346 Iterator it = path.iterator(); 347 while (it.hasNext() && substance!=null) { 348 FieldItem field = (FieldItem)it.next(); 349 if (!it.hasNext()) { 350 break; 351 } 352 Vector current = substances; 353 substances = new Vector (current.size()); 354 for(Iterator j = current.iterator(); j.hasNext();) { 355 Object o = j.next(); 356 if (o!=null) { 357 if (field instanceof CollectionItem) { 358 substances.addAll( 359 ((CollectionItem)field).getActualCollectionThroughAccessor(o)); 360 } else { 361 substances.add(field.getThroughAccessor(o)); 362 } 363 } 364 } 365 } 366 } 367 return substances; 368 } 369 370 375 public FieldItem getField() { 376 if (isExpression) { 377 return getPathTop(); 378 } else { 379 return this; 380 } 381 } 382 383 390 public final Object get(Object object) { 391 Object ret = null; 392 try { 393 ret = ((Field)delegate).get(object); 394 } catch (Exception e) { 395 logger.error("Failed to get value of field "+this+" for "+object+ 396 (object!=null?(" ("+object.getClass().getName()+")"):""), 397 e); 398 } 399 return ret; 400 } 401 402 407 public Object getThroughAccessor(Object substance) 408 { 409 ((ClassItem)parent).buildFieldInfo(); 410 if (isExpression) { 411 Iterator it = path.iterator(); 412 while (it.hasNext() && substance!=null) { 413 FieldItem field = (FieldItem)it.next(); 414 substance = field.getThroughAccessor(substance); 415 } 416 return substance; 417 } else { 418 Object value = null; 419 String name; 420 MethodItem getter = getGetter(); 421 if (getter!=null) { 422 return (getter.invoke(substance,ExtArrays.emptyObjectArray)); 424 } else { 425 logger.warn("No accessor found for field " + this); 426 return get(substance); 427 } 428 } 429 } 430 431 444 public static Collection getPathLeaves(FieldItem path, Object root) { 445 ((ClassItem)path.parent).buildFieldInfo(); 446 447 if (path.isExpression) { 448 HashSet currentSet = new HashSet (); 449 currentSet.add(root); 450 Iterator it = path.path.iterator(); 451 while (it.hasNext()) { 452 FieldItem field = (FieldItem)it.next(); 453 HashSet newSet = new HashSet (); 454 Iterator j = currentSet.iterator(); 455 while(j.hasNext()) { 456 Object o = j.next(); 457 newSet.addAll(getPathLeaves(field,o)); 458 } 459 currentSet = newSet; 460 } 461 return currentSet; 462 } else { 463 if (path instanceof CollectionItem) 464 return ((CollectionItem)path).getActualCollectionThroughAccessor(root); 465 else { 466 ArrayList singleton = new ArrayList (1); 467 singleton.add(path.getThroughAccessor(root)); 468 return singleton; 469 } 470 } 471 } 472 473 481 public final void set(Object object, Object value) 482 throws IllegalAccessException , IllegalArgumentException 483 { 484 if (value==null && getType().isPrimitive()) { 485 logger.error("Cannot set primitive field "+this+" to null", new Exception ()); 486 } else { 487 ((Field)delegate).set(object, value); 488 } 489 } 490 491 503 public final boolean setConvert(Object object, Object value) 504 throws IllegalAccessException , IllegalArgumentException , 505 InstantiationException , InvocationTargetException, NoSuchMethodException 506 { 507 try { 508 set(object,value); 509 return false; 510 } catch(IllegalArgumentException e) { 511 Object convertedValue = RttiAC.convert(value,getType()); 512 set(object,convertedValue); 513 return true; 514 } 515 } 516 517 525 public final void setThroughWriter(Object substance, Object value) 526 throws IllegalAccessException , IllegalArgumentException 527 { 528 ((ClassItem)parent).buildFieldInfo(); 529 if (isExpression) { 530 Iterator it = path.iterator(); 531 while (it.hasNext()) { 532 FieldItem field = (FieldItem)it.next(); 533 if (it.hasNext()) { 534 substance = field.getThroughAccessor(substance); 535 } else { 536 field.setThroughWriter(substance,value); 537 return; 538 } 539 } 540 } else { 541 logger.debug("setThroughWriter "+substance+"."+getName()+","+value); 542 String name; 543 if (setter!=null) { 544 try { 545 logger.debug(this+": invoking "+setter); 546 setter.invoke(substance,new Object [] { value }); 547 return; 548 } catch (WrappedThrowableException e) { 549 Throwable target = e.getWrappedThrowable(); 550 if (target instanceof IllegalArgumentException ) 551 logger.error("setThroughWriter: IllegalArgumentException for "+substance+"."+getName()+ 552 " = "+Strings.hex(value)+"("+value+")"); 553 throw e; 554 } 555 } 556 } 557 558 if (isCalculated()) { 559 throw new RuntimeException ("Cannot set calculted field "+getLongName()); 560 } 561 logger.warn("No setter found for field "+this); 562 set(substance,value); 563 } 564 565 566 MethodItem setter; 567 568 public MethodItem getSetter() { 569 ((ClassItem)parent).buildFieldInfo(); 570 if (setter!=null) 571 return setter; 572 else if (isExpression) 573 return getPathTop().getSetter(); 574 else 575 return null; 576 } 577 578 public void setSetter(MethodItem setter) { 579 if (this.setter!=null) { 580 logger.warn("overriding setter "+ 581 this.setter.getFullName()+" for field "+ 582 this+" with "+setter.getFullName()); 583 } 584 this.setter = setter; 585 addWritingMethod(setter); 586 } 587 588 589 MethodItem getter; 590 593 public MethodItem getGetter() { 594 if (!isExpression) 595 ((ClassItem)parent).buildFieldInfo(); 596 return getter; 597 } 598 599 public void setGetter(MethodItem getter) { 600 ((ClassItem)parent).buildFieldInfo(); 601 if (this.getter!=null) { 602 if (getType().isAssignableFrom(getter.getType())) { 603 setType(getter.getType()); 604 } else { 605 logger.warn("overriding getter "+ 606 this.getter.getLongName()+ 607 " for field "+this+" with "+getter.getLongName()); 608 } 609 } 610 if (!isCalculated && getType()!=getter.getType() && 611 getType().isAssignableFrom(getter.getType())) { 612 setType(getter.getType()); 613 } 614 this.getter = getter; 615 addAccessingMethod(getter); 616 } 617 618 public String getName() { 619 return name; 620 } 621 622 public Class getType() { 623 if (type!=null) 624 return type; 625 else if (getter!=null) 626 return getter.getType(); 627 else 628 return ((Field)delegate).getType(); 629 } 630 631 public void setType(Class type) { 632 logger.info("overriding field type of "+this+ 633 " with "+type.getName()); 634 this.type = type; 635 } 636 637 647 648 public boolean isPrimitive() { 649 return !isReference(); 650 } 651 652 664 665 public boolean isReference() { 666 return wrappeeClass.isAssignableFrom(getType()); 667 } 668 669 679 680 public boolean isWrappable(Object substance) { 681 Object value = get(substance); 682 if (value==null) { 683 return wrappeeClass.isAssignableFrom(getType()); 684 } 685 return wrappeeClass.isAssignableFrom(value.getClass()); 686 } 687 688 691 public boolean isTransient() { 692 return isCalculated ? true 693 : Modifier.isTransient(((Member)delegate).getModifiers()); 694 } 695 696 public boolean isFinal() { 697 return isCalculated ? false 698 : Modifier.isFinal(((Member)delegate).getModifiers()); 699 } 700 701 public boolean isStatic() { 702 return isCalculated ? ( isExpression ? lastField().isStatic() : getter.isStatic() ) 703 : Modifier.isStatic(((Member)delegate).getModifiers()); 704 } 705 706 public int getModifiers() { 707 if (isCalculated) 708 return Modifier.PUBLIC | Modifier.TRANSIENT; 709 else 710 return super.getModifiers(); 711 } 712 713 protected FieldItem lastField() { 714 return (FieldItem)path.get(path.size()-1); 715 } 716 717 720 public boolean isCalculated() { 721 return isCalculated; 722 } 723 724 728 public FieldItem clone(ClassItem parent) { 729 FieldItem clone = null; 730 try { 731 if (isCalculated) 732 clone = new FieldItem(name,getter,parent); 733 else 734 clone = new FieldItem((Field)delegate,parent); 735 } catch(Exception e) { 736 logger.error("Failed to clone field "+this); 737 } 738 return clone; 739 } 740 741 boolean isAggregation = false; 742 public void setAggregation(boolean isAggregation) { 743 this.isAggregation = isAggregation; 744 } 745 public boolean isAggregation() { 746 return isAggregation; 747 } 748 749 public boolean startsWith(FieldItem field) { 750 return this!=field && name.startsWith(field.getName()); 751 } 752 753 public FieldItem getRelativeField(FieldItem base) { 754 if (base instanceof CollectionItem) 755 return ((CollectionItem)base).getComponentType().getField(name.substring(base.getName().length()+1)); 756 else 757 return base.getTypeItem().getField(name.substring(base.getName().length()+1)); 758 } 759 760 FieldItem oppositeRole; 761 public FieldItem getOppositeRole() { 762 if (oppositeRole!=null) 763 return oppositeRole; 764 else 765 return (FieldItem)getAttribute(RttiAC.OPPOSITE_ROLE); 766 } 767 public void setOppositeRole(FieldItem oppositeRole) { 768 this.oppositeRole = oppositeRole; 769 setAttribute(RttiAC.OPPOSITE_ROLE,oppositeRole); 770 } 771 772 public static final FieldItem[] emptyArray = new FieldItem[0]; 773 } 774 | Popular Tags |