1 22 package org.jboss.xb.binding.sunday.unmarshalling.impl.runtime; 23 24 import java.lang.reflect.Array ; 25 import java.lang.reflect.Constructor ; 26 import java.lang.reflect.Method ; 27 import java.lang.reflect.Modifier ; 28 import java.util.Collection ; 29 import java.util.Map ; 30 import javax.xml.namespace.NamespaceContext ; 31 import javax.xml.namespace.QName ; 32 import org.jboss.logging.Logger; 33 import org.jboss.util.Classes; 34 import org.jboss.xb.binding.Constants; 35 import org.jboss.xb.binding.GenericValueContainer; 36 import org.jboss.xb.binding.JBossXBRuntimeException; 37 import org.jboss.xb.binding.SimpleTypeBindings; 38 import org.jboss.xb.binding.Util; 39 import org.jboss.xb.binding.introspection.FieldInfo; 40 import org.jboss.xb.binding.group.ValueList; 41 import org.jboss.xb.binding.group.ValueListHandler; 42 import org.jboss.xb.binding.group.ValueListInitializer; 43 import org.jboss.xb.binding.metadata.AddMethodMetaData; 44 import org.jboss.xb.binding.metadata.ClassMetaData; 45 import org.jboss.xb.binding.metadata.MapEntryMetaData; 46 import org.jboss.xb.binding.metadata.PackageMetaData; 47 import org.jboss.xb.binding.metadata.PropertyMetaData; 48 import org.jboss.xb.binding.metadata.PutMethodMetaData; 49 import org.jboss.xb.binding.metadata.ValueMetaData; 50 import org.jboss.xb.binding.sunday.unmarshalling.AttributeBinding; 51 import org.jboss.xb.binding.sunday.unmarshalling.AttributeHandler; 52 import org.jboss.xb.binding.sunday.unmarshalling.CharactersHandler; 53 import org.jboss.xb.binding.sunday.unmarshalling.ElementBinding; 54 import org.jboss.xb.binding.sunday.unmarshalling.ModelGroupBinding; 55 import org.jboss.xb.binding.sunday.unmarshalling.ParticleBinding; 56 import org.jboss.xb.binding.sunday.unmarshalling.ParticleHandler; 57 import org.jboss.xb.binding.sunday.unmarshalling.SchemaBinding; 58 import org.jboss.xb.binding.sunday.unmarshalling.TermBinding; 59 import org.jboss.xb.binding.sunday.unmarshalling.TypeBinding; 60 import org.jboss.xb.binding.sunday.unmarshalling.WildcardBinding; 61 import org.xml.sax.Attributes ; 62 63 67 public class RtElementHandler 68 implements ParticleHandler 69 { 70 private static final Logger log = Logger.getLogger(RtElementHandler.class); 71 72 public static final RtElementHandler INSTANCE = new RtElementHandler(); 73 74 76 82 public Object startParticle(Object parent, 83 QName elementName, 84 ParticleBinding particle, 85 Attributes attrs, 86 NamespaceContext nsCtx) 87 { 88 TermBinding term = particle.getTerm(); 89 Object o = startElement(parent, elementName, particle); 90 if(!term.isModelGroup()) 91 { 92 ElementBinding element = (ElementBinding)term; 93 if(o != null) 94 { 95 attrs = element.getType().expandWithDefaultAttributes(attrs); 96 attributes(o, elementName, element, attrs, nsCtx); 97 } 98 } 99 return o; 100 } 101 102 public void setParent(Object parent, 103 Object o, 104 QName qName, 105 ParticleBinding particle, 106 ParticleBinding parentParticle) 107 { 108 TermBinding term = particle.getTerm(); 109 if(term.isSkip()) 110 { 111 return; 112 } 113 114 boolean trace = log.isTraceEnabled(); 115 if(trace) 116 { 117 log.trace("setParent " + qName + " parent=" + parent + " object=" + o + " term=" + term); 118 } 119 120 TermBinding parentTerm = parentParticle.getTerm(); 121 122 if(term.isMapEntryKey()) 123 { 124 if(trace) 125 { 126 log.trace("setParent " + qName + " mapKey"); 127 } 128 129 if(parent instanceof MapEntry) 130 { 131 MapEntry mapEntry = (MapEntry)parent; 132 mapEntry.setKey(o); 133 } 134 else if(parentTerm != null) 135 { 136 MapEntryMetaData mapEntryMetaData = getMapEntryMetaData(parentTerm, qName); 137 138 String getKeyMethodName = mapEntryMetaData.getGetKeyMethod(); 139 if(getKeyMethodName == null) 140 { 141 getKeyMethodName = "getKey"; 142 } 143 144 String setKeyMethodName = mapEntryMetaData.getSetKeyMethod(); 145 if(setKeyMethodName == null) 146 { 147 setKeyMethodName = "setKey"; 148 } 149 150 Class parentCls = parent.getClass(); 151 Method setKeyMethod = getSetMethod(parentCls, getKeyMethodName, setKeyMethodName); 152 invokeSetter(setKeyMethod, parent, o, setKeyMethodName); 153 } 154 else 155 { 156 throw new JBossXBRuntimeException( 157 "Element " + 158 qName + 159 " bound as map entry key but parent element is not recognized as map entry and its metadata is not available." 160 ); 161 } 162 } 163 else if(term.isMapEntryValue()) 164 { 165 if(trace) 166 { 167 log.trace("setParent " + qName + " mapValue"); 168 } 169 170 if(parent instanceof MapEntry) 171 { 172 MapEntry mapEntry = (MapEntry)parent; 173 mapEntry.setValue(o); 174 } 175 else if(parentTerm != null) 176 { 177 MapEntryMetaData mapEntryMetaData = getMapEntryMetaData(parentTerm, qName); 178 setMapEntryValue(mapEntryMetaData, parent, o); 179 } 180 else 181 { 182 throw new JBossXBRuntimeException( 183 "Element " + 184 qName + 185 " bound as map entry key but parent element is not recognized as map entry and its metadata is not available." 186 ); 187 } 188 } 189 else 190 { 191 Object owner = parent; 192 if(parent instanceof MapEntry) 193 { 194 if(trace) 195 { 196 log.trace("setParent " + qName + " mapEntry"); 197 } 198 199 MapEntry mapEntry = (MapEntry)parent; 200 owner = mapEntry.getValue(); 201 if(owner == null) 202 { 203 if(parentTerm == null) 204 { 205 throw new JBossXBRuntimeException("Binding metadata needed for lazy map entry value instantiation is not available " + 206 "for parent element of element " + 207 qName 208 ); 209 } 210 211 MapEntryMetaData mapEntryMetaData = getMapEntryMetaData(parentTerm, qName); 212 String valueType = mapEntryMetaData.getValueType(); 213 if(valueType == null) 214 { 215 throw new JBossXBRuntimeException("Element " + 216 qName + 217 " is supposed to be bound as map entry value with lazy value instantiation " + 218 "but value type is not specified in its map entry metadata." 219 ); 220 } 221 222 Class valueCls; 223 try 224 { 225 valueCls = Thread.currentThread().getContextClassLoader().loadClass(valueType); 226 } 227 catch(ClassNotFoundException e) 228 { 229 throw new JBossXBRuntimeException( 230 "Failed to load value type specified in the map entry metadata: " + valueType 231 ); 232 } 233 234 try 235 { 236 owner = valueCls.newInstance(); 237 } 238 catch(Exception e) 239 { 240 throw new JBossXBRuntimeException( 241 "Failed to create an instance of value type " + valueType + ": " + e.getMessage() 242 ); 243 } 244 245 setMapEntryValue(mapEntryMetaData, parent, owner); 246 } 247 } 248 249 WildcardBinding wildcard = null; 251 if(parentTerm != null && !parentTerm.isModelGroup()) 252 { 253 ElementBinding parentElement = (ElementBinding)parentTerm; 254 TypeBinding parentType = parentElement.getType(); 255 wildcard = parentType.getWildcard(); 256 if(wildcard != null && parentType.getElement(qName) != null) 258 { 259 wildcard = null; 260 } 261 } 262 263 if(tryPut(owner, o, qName, term, trace)) 264 { 265 } 266 else if(tryAdd(owner, o, qName, term, wildcard, trace)) 267 { 268 } 269 else if (owner instanceof GenericValueContainer) 270 { 271 if (trace) 272 { 273 log.trace("setParent " + qName + " addChild"); 274 } 275 ((GenericValueContainer) owner).addChild(qName, o); 276 } 277 else if (owner instanceof Collection ) 278 { 279 if (trace) 280 { 281 log.trace("setParent " + qName + " collection.add()"); 282 } 283 ((Collection ) owner).add(o); 284 } 285 else 286 { 287 PropertyMetaData propertyMetaData = wildcard == null ? null : wildcard.getPropertyMetaData(); 288 if (propertyMetaData == null) 289 { 290 propertyMetaData = term.getPropertyMetaData(); 291 } 292 293 String propName = null; 294 String colType = null; 295 if (propertyMetaData != null) 296 { 297 propName = propertyMetaData.getName(); 298 colType = propertyMetaData.getCollectionType(); 299 } 300 301 if (propName == null) 302 { 303 propName = Util.xmlNameToFieldName(qName.getLocalPart(), term.getSchema().isIgnoreLowLine()); 304 } 305 306 if (trace) 307 { 308 log.trace("setParent " + qName + " metadata set " + propName); 309 } 310 311 320 RtUtil.set(owner, o, propName, colType, 321 term.getSchema().isIgnoreUnresolvedFieldOrClass(), 322 term.getValueAdapter()); 323 } 325 } 326 } 327 328 public Object endParticle(Object o, QName elementName, ParticleBinding particle) 329 { 330 TermBinding term = particle.getTerm(); 331 if(term.isSkip()) 332 { 333 return o; 334 } 335 336 boolean trace = log.isTraceEnabled(); 337 if(trace) 338 { 339 log.trace("endParticle " + elementName + " object=" + o + " term=" + term); 340 } 341 342 if(o instanceof GenericValueContainer) 343 { 344 try 345 { 346 if(trace) 347 { 348 log.trace("endParticle " + elementName + " instantiate()"); 349 } 350 o = ((GenericValueContainer)o).instantiate(); 351 } 352 catch(JBossXBRuntimeException e) 353 { 354 throw e; 355 } 356 catch(RuntimeException e) 357 { 358 throw new JBossXBRuntimeException("Container failed to create an instance for " + 359 elementName + 360 ": " + e.getMessage(), e 361 ); 362 } 363 } 364 365 return o; 366 } 367 368 370 private Object startElement(Object parent, QName elementName, ParticleBinding particle) 371 { 372 TermBinding term = particle.getTerm(); 373 if(term.isSkip()) 374 { 375 return parent; 376 } 377 378 boolean trace = log.isTraceEnabled(); 379 if(trace) 380 { 381 log.trace("startElement " + elementName + " parent=" + parent + " term=" + term); 382 } 383 384 ClassMetaData classMetaData = term.getClassMetaData(); 385 MapEntryMetaData mapEntryMetaData = term.getMapEntryMetaData(); 386 387 if(!term.isModelGroup()) 388 { 389 TypeBinding type = ((ElementBinding)term).getType(); 390 if(!type.isStartElementCreatesObject() || 391 classMetaData == null && mapEntryMetaData == null && Constants.QNAME_ANYTYPE.equals(type.getQName())) 392 { 393 if(trace) 394 { 395 log.trace("startElement " + elementName + " does not create an object"); 396 } 397 return null; 398 } 399 } 400 401 Object o = null; 402 403 ElementBinding arrayItem = null; 406 if(!term.isModelGroup()) 407 { 408 TypeBinding type = ((ElementBinding)term).getType(); 409 if(type.getAttributes().isEmpty()) 410 { 411 ParticleBinding typeParticle = type.getParticle(); 412 ModelGroupBinding modelGroup = (ModelGroupBinding)(typeParticle == null ? null : typeParticle.getTerm()); 413 arrayItem = modelGroup == null ? null : modelGroup.getArrayItem(); 414 415 if(arrayItem != null && 417 (arrayItem.isSkip() || 418 arrayItem.getMapEntryMetaData() != null || 419 arrayItem.getPutMethodMetaData() != null || 420 arrayItem.getAddMethodMetaData() != null 421 )) 422 { 423 arrayItem = null; 424 } 425 } 426 } 427 428 if(arrayItem != null) 429 { 430 Class wrapperType = null; 431 if(classMetaData != null) 432 { 433 wrapperType = loadClassForTerm(classMetaData.getImpl(), 434 term.getSchema().isIgnoreUnresolvedFieldOrClass(), 435 elementName 436 ); 437 438 if(GenericValueContainer.class.isAssignableFrom(wrapperType) || 439 Collection .class.isAssignableFrom(wrapperType) || 440 Map .class.isAssignableFrom(wrapperType)) 441 { 442 return newInstance(wrapperType, elementName, term.getSchema().isUseNoArgCtorIfFound()); 443 } 444 } 445 446 if(wrapperType == null && parent == null) 447 { 448 Class itemType = classForElement(arrayItem, null); 449 if(itemType != null) 450 { 451 if(trace) 452 { 453 log.trace("startElement " + elementName + " new array " + itemType.getName()); 454 } 455 o = GenericValueContainer.FACTORY.array(itemType); 456 } 457 } 458 else 459 { 460 PropertyMetaData propertyMetaData = wrapperType == null ? 461 term.getPropertyMetaData() : arrayItem.getPropertyMetaData(); 462 463 String propName; 464 if(propertyMetaData == null) 465 { 466 propName = Util.xmlNameToFieldName( 467 wrapperType == null ? elementName.getLocalPart() : arrayItem.getQName().getLocalPart(), 468 term.getSchema().isIgnoreLowLine() 469 ); 470 } 471 else 472 { 473 propName = propertyMetaData.getName(); 474 } 475 476 if(trace) 477 { 478 log.trace("startElement " + elementName + " property=" + propName); 479 } 480 481 Class parentClass = wrapperType; 482 if(wrapperType == null) 483 { 484 if(parent instanceof GenericValueContainer) 485 { 486 parentClass = ((GenericValueContainer)parent).getTargetClass(); 487 } 488 else if(parent instanceof ValueList) 489 { 490 parentClass = ((ValueList)parent).getTargetClass(); 491 } 492 else 493 { 494 parentClass = parent.getClass(); 495 } 496 } 497 498 Class fieldType; 499 if(parentClass.isArray()) 500 { 501 fieldType = parentClass.getComponentType(); 502 } 503 else 504 { 505 fieldType = FieldInfo.getFieldInfo(parentClass, propName, true).getType(); 506 if(particle.isRepeatable() && fieldType.isArray()) 507 { 508 fieldType = fieldType.getComponentType(); 509 } 510 } 511 512 if(fieldType.isArray()) 513 { 514 o = GenericValueContainer.FACTORY.array(wrapperType, propName, fieldType.getComponentType()); 515 } 516 else if(Collection .class.isAssignableFrom(fieldType)) 517 { 518 o = new ValueListInitializer().newValueList(ValueListHandler.FACTORY.child(), Collection .class); 520 } 522 else 523 { 524 o = GenericValueContainer.FACTORY.array(wrapperType, propName, fieldType); 525 } 526 } 527 } 528 else 529 { 530 if(mapEntryMetaData != null) 531 { 532 if(mapEntryMetaData.getImpl() != null) 533 { 534 Class cls = loadClassForTerm(mapEntryMetaData.getImpl(), 535 term.getSchema().isIgnoreUnresolvedFieldOrClass(), 536 elementName 537 ); 538 539 if(trace) 540 { 541 log.trace("startElement " + elementName + " new map entry " + cls.getName()); 542 } 543 544 o = newInstance(cls, elementName, term.getSchema().isUseNoArgCtorIfFound()); 545 } 546 else 547 { 548 o = new MapEntry(); 549 if(trace) 550 { 551 log.trace("startElement " + elementName + " new map entry"); 552 } 553 } 554 555 if(mapEntryMetaData.isNonNullValue() && mapEntryMetaData.getValueType() != null) 556 { 557 Class mapValueType; 558 try 559 { 560 mapValueType = 561 Thread.currentThread().getContextClassLoader().loadClass(mapEntryMetaData.getValueType()); 562 } 563 catch(ClassNotFoundException e) 564 { 565 throw new JBossXBRuntimeException("startElement failed for " + 566 elementName + 567 ": failed to load class " + 568 mapEntryMetaData.getValueType() + 569 " for map entry value." 570 ); 571 } 572 573 Object value; 574 try 575 { 576 if(trace) 577 { 578 log.trace("startElement " + elementName + " map value type " + mapEntryMetaData.getValueType()); 579 } 580 value = mapValueType.newInstance(); 581 } 582 catch(Exception e) 583 { 584 throw new JBossXBRuntimeException("startElement failed for " + 585 elementName + 586 ": failed to create an instance of " + 587 mapValueType + 588 " for map entry value." 589 ); 590 } 591 592 if(o instanceof MapEntry) 593 { 594 ((MapEntry)o).setValue(value); 595 } 596 else 597 { 598 String getValueMethodName = mapEntryMetaData.getGetValueMethod(); 599 if(getValueMethodName == null) 600 { 601 getValueMethodName = "getValue"; 602 } 603 604 String setValueMethodName = mapEntryMetaData.getSetValueMethod(); 605 if(setValueMethodName == null) 606 { 607 setValueMethodName = "setValue"; 608 } 609 610 Method getValueMethod; 611 try 612 { 613 getValueMethod = o.getClass().getMethod(getValueMethodName, null); 614 } 615 catch(NoSuchMethodException e) 616 { 617 throw new JBossXBRuntimeException("getValueMethod=" + 618 getValueMethodName + 619 " is not found in map entry " + o.getClass() 620 ); 621 } 622 623 Method setValueMethod; 624 try 625 { 626 setValueMethod = 627 o.getClass().getMethod(setValueMethodName, new Class []{getValueMethod.getReturnType()}); 628 } 629 catch(NoSuchMethodException e) 630 { 631 throw new JBossXBRuntimeException("setValueMethod=" + 632 setValueMethodName + 633 "(" + 634 getValueMethod.getReturnType().getName() + 635 " value) is not found in map entry " + o.getClass() 636 ); 637 } 638 639 try 640 { 641 setValueMethod.invoke(o, new Object []{value}); 642 } 643 catch(Exception e) 644 { 645 throw new JBossXBRuntimeException("setValueMethod=" + 646 setValueMethodName + 647 " failed: owner=" + 648 o + 649 ", value=" + value + ", msg=" + e.getMessage(), e 650 ); 651 } 652 } 653 } 654 } 655 else 656 { 657 Class parentClass = null; 660 if(parent != null) 661 { 662 if(parent instanceof GenericValueContainer) 663 { 664 parentClass = ((GenericValueContainer)parent).getTargetClass(); 665 } 666 else if(parent instanceof ValueList) 667 { 668 parentClass = ((ValueList)parent).getTargetClass(); 669 } 670 else 671 { 672 parentClass = parent.getClass(); 673 } 674 } 675 676 Class cls; 677 if(term.isModelGroup()) 678 { 679 if(classMetaData == null) 680 { 681 throw new JBossXBRuntimeException( 682 "Model groups should be annotated with 'class' annotation to be bound." 683 ); 684 } 685 cls = loadClassForTerm(classMetaData.getImpl(), 686 term.getSchema().isIgnoreUnresolvedFieldOrClass(), 687 elementName 688 ); 689 } 690 else 691 { 692 ElementBinding element = (ElementBinding)term; 693 cls = classForNonArrayItem(element, parentClass); 694 if(cls != null) 695 { 696 TypeBinding simpleType = element.getType().getSimpleType(); 698 if(simpleType != null) 699 { 700 Class simpleCls = classForSimpleType(simpleType, element.isNillable()); 701 if(cls.equals(simpleCls) || 702 cls.isPrimitive() && Classes.getPrimitiveWrapper(cls) == simpleCls || 703 simpleCls.isPrimitive() && Classes.getPrimitiveWrapper(simpleCls) == cls) 704 { 705 cls = null; 706 } 707 } 708 } 709 } 710 711 if(cls != null) 712 { 713 boolean noArgCtor; 714 if(classMetaData == null) 715 { 716 noArgCtor = term.getSchema().isUseNoArgCtorIfFound(); 717 } 718 else 719 { 720 Boolean termUsesNoArgCtor = classMetaData.isUseNoArgCtor(); 721 noArgCtor = termUsesNoArgCtor == null ? 722 term.getSchema().isUseNoArgCtorIfFound() : termUsesNoArgCtor.booleanValue(); } 723 724 if(trace) 725 { 726 log.trace("startElement " + elementName + " new " + cls.getName() + ", noArgCtor=" + noArgCtor); 727 } 728 o = newInstance(cls, elementName, noArgCtor); 729 } 730 } 731 } 732 return o; 733 } 734 735 private void attributes(Object o, 736 QName elementName, 737 ElementBinding element, 738 Attributes attrs, 739 NamespaceContext nsCtx) 740 { 741 TypeBinding type = element.getType(); 742 for(int i = 0; i < attrs.getLength(); ++i) 743 { 744 QName attrName = new QName (attrs.getURI(i), attrs.getLocalName(i)); 745 AttributeBinding binding = type.getAttribute(attrName); 746 if(binding != null) 747 { 748 AttributeHandler handler = binding.getHandler(); 749 if(handler != null) 750 { 751 Object value = handler.unmarshal(elementName, attrName, binding, nsCtx, attrs.getValue(i)); 752 handler.attribute(elementName, attrName, binding, o, value); 753 } 754 else 755 { 756 throw new JBossXBRuntimeException( 757 "Attribute binding present but has no handler: element=" + elementName + ", attrinute=" + attrName 758 ); 759 } 760 } 761 else 762 { 763 if(!Constants.NS_XML_SCHEMA_INSTANCE.equals(attrs.getURI(i))) 764 { 765 CharactersHandler simpleType = type.getCharactersHandler(); 766 Object value; 767 if(simpleType == null) 768 { 769 value = attrs.getValue(i); 770 RtUtil.set(o, attrName, value, element.getSchema().isIgnoreLowLine()); 771 } 772 } 773 } 774 } 775 } 776 777 private boolean tryAdd(Object owner, 778 Object o, 779 QName qName, 780 TermBinding term, 781 WildcardBinding wildcard, 782 boolean trace) 783 { 784 AddMethodMetaData addMetaData = wildcard == null ? null : wildcard.getAddMethodMetaData(); 785 if(addMetaData == null) 786 { 787 addMetaData = term.getAddMethodMetaData(); 788 } 789 790 if(addMetaData == null) 791 { 792 return false; 793 } 794 795 if(trace) 796 { 797 log.trace("setParent " + qName + " add"); 798 } 799 invokeAdd(qName, addMetaData, owner, o); 800 return true; 801 } 802 803 private boolean tryPut(Object owner, Object o, QName qName, TermBinding term, boolean trace) 804 { 805 if(term.getPutMethodMetaData() != null || 806 term.getMapEntryMetaData() != null && owner instanceof Map ) 807 { 808 if(trace) 809 { 810 log.trace("setParent " + qName + " mapPut"); 811 } 812 invokePut(qName, term, owner, o); 813 return true; 814 } 815 return false; 816 } 817 818 private Class classForElement(ElementBinding element, Class parentClass) 819 { 820 Class cls; 821 TypeBinding type = element.getType(); 822 QName typeQName = type.getQName(); 823 if(typeQName != null && Constants.NS_XML_SCHEMA.equals(typeQName.getNamespaceURI())) 824 { 825 cls = SimpleTypeBindings.classForType(type.getQName().getLocalPart(), element.isNillable()); 826 } 827 else 828 { 829 ElementBinding arrayItem = null; 830 if(!type.isSimple() && type.getAttributes().isEmpty()) 831 { 832 ParticleBinding typeParticle = type.getParticle(); 833 ModelGroupBinding modelGroup = (ModelGroupBinding)(typeParticle == null ? null : typeParticle.getTerm()); 834 arrayItem = modelGroup == null ? null : modelGroup.getArrayItem(); 835 } 836 837 if(arrayItem != null) 838 { 839 cls = classForElement(arrayItem, parentClass); 840 cls = Array.newInstance(cls, 0).getClass(); 842 } 843 else 844 { 845 cls = classForNonArrayItem(element, parentClass); 846 } 847 } 848 return cls; 849 } 850 851 private static void setMapEntryValue(MapEntryMetaData mapEntryMetaData, Object parent, Object o) 852 { 853 String getValueMethodName = mapEntryMetaData.getGetValueMethod(); 854 if(getValueMethodName == null) 855 { 856 getValueMethodName = "getValue"; 857 } 858 859 String setValueMethodName = mapEntryMetaData.getSetValueMethod(); 860 if(setValueMethodName == null) 861 { 862 setValueMethodName = "setValue"; 863 } 864 865 Class parentCls = parent.getClass(); 866 Method setValueMethod = getSetMethod(parentCls, getValueMethodName, setValueMethodName); 867 invokeSetter(setValueMethod, parent, o, setValueMethodName); 868 } 869 870 private static void invokeSetter(Method setValueMethod, Object parent, Object o, String setValueMethodName) 871 { 872 try 873 { 874 setValueMethod.invoke(parent, new Object []{o}); 875 } 876 catch(Exception e) 877 { 878 throw new JBossXBRuntimeException("Failed to invoke " + 879 setValueMethodName + 880 " on " + 881 parent + 882 " with parameter " + 883 o + 884 ": " + 885 e.getMessage() 886 ); 887 } 888 } 889 890 private static Method getSetMethod(Class cls, String getMethodName, String setMethodName) 891 { 892 Method getKeyMethod; 893 try 894 { 895 getKeyMethod = cls.getMethod(getMethodName, null); 896 } 897 catch(NoSuchMethodException e) 898 { 899 throw new JBossXBRuntimeException("Method " + getMethodName + " not found in " + cls); 900 } 901 902 Method setKeyMethod; 903 try 904 { 905 setKeyMethod = cls.getMethod(setMethodName, new Class []{getKeyMethod.getReturnType()}); 906 } 907 catch(NoSuchMethodException e) 908 { 909 throw new JBossXBRuntimeException("Method " + 910 setMethodName + 911 "(" + 912 getKeyMethod.getReturnType().getName() + 913 " p) not found in " + 914 cls 915 ); 916 } 917 return setKeyMethod; 918 } 919 920 private static MapEntryMetaData getMapEntryMetaData(TermBinding term, QName qName) 921 { 922 MapEntryMetaData mapEntryMetaData = term.getMapEntryMetaData(); 923 if(mapEntryMetaData == null) 924 { 925 String msg; 926 if(term.isModelGroup()) 927 { 928 msg = "Term " + 929 qName + 930 " bound as map entry key or value but map entry metadata is not available for its parent term."; 931 } 932 else 933 { 934 ElementBinding element = (ElementBinding)term; 935 msg = "Element " + 936 qName + 937 " bound as map entry key or value but map entry metadata is not available for its parent element nor its " + 938 (element.getType().getQName() == null ? 939 "annonymous" : 940 element.getType().getQName().toString() 941 ) + 942 " type."; 943 } 944 throw new JBossXBRuntimeException(msg); 945 } 946 return mapEntryMetaData; 947 } 948 949 private static Object newInstance(Class cls, QName elementName, boolean useNoArgCtorIfFound) 950 { 951 Object o; 952 if(cls.isArray()) 953 { 954 o = GenericValueContainer.FACTORY.array(cls.getComponentType()); 955 } 956 else 957 { 958 Constructor [] ctors = cls.getConstructors(); 959 if(ctors.length == 0) 960 { 961 throw new JBossXBRuntimeException( 962 "Class " + cls.getName() + " has no public constructors or the class reflects a primitive type or void" 963 ); 964 } 965 966 if(useNoArgCtorIfFound) 967 { 968 try 969 { 970 Constructor ctor = cls.getConstructor(null); 971 o = ctor.newInstance(null); 972 } 973 catch(NoSuchMethodException e) 974 { 975 o = new ValueListInitializer().newValueList(ValueListHandler.NON_DEFAULT_CTOR, cls); 976 } 977 catch(Exception e) 978 { 979 throw new JBossXBRuntimeException("Failed to create an instance of " + 980 cls + 981 " using default constructor for element " + 982 elementName + ": " + e.getMessage(), e 983 ); 984 } 985 } 986 else if(ctors.length > 1 || ctors[0].getParameterTypes().length > 0) 987 { 988 o = new ValueListInitializer().newValueList(ValueListHandler.NON_DEFAULT_CTOR, cls); 989 } 990 else 991 { 992 try 993 { 994 o = ctors[0].newInstance(null); 995 } 996 catch(Exception e) 997 { 998 throw new JBossXBRuntimeException("Failed to create an instance of " + 999 cls + 1000 " using default constructor for element " + 1001 elementName + ": " + e.getMessage(), e 1002 ); 1003 } 1004 } 1005 } 1006 return o; 1007 } 1008 1009 private static Class loadClassForTerm(String className, 1010 boolean ignoreCNFE, 1011 QName elementName) 1012 { 1013 if(className == null) 1014 { 1015 throw new JBossXBRuntimeException("No class for " + elementName); 1016 } 1017 1018 Class cls = null; 1019 try 1020 { 1021 cls = Thread.currentThread().getContextClassLoader().loadClass(className); 1022 } 1023 catch(ClassNotFoundException e) 1024 { 1025 if(ignoreCNFE) 1026 { 1027 if(log.isTraceEnabled()) 1028 { 1029 log.trace("Failed to resolve class for element " + 1030 elementName + 1031 ": " + 1032 className 1033 ); 1034 } 1035 } 1036 else 1037 { 1038 throw new JBossXBRuntimeException("Failed to resolve class name for " + 1039 elementName + 1040 ": " + 1041 e.getMessage() 1042 ); 1043 } 1044 } 1045 return cls; 1046 } 1047 1048 private void invokeAdd(QName qName, AddMethodMetaData addMethodMetaData, Object owner, Object o) 1049 { 1050 Class valueType = Object .class; 1051 if(addMethodMetaData.getValueType() != null) 1052 { 1053 try 1054 { 1055 valueType = Thread.currentThread().getContextClassLoader(). 1056 loadClass(addMethodMetaData.getValueType()); 1057 } 1058 catch(ClassNotFoundException e) 1059 { 1060 throw new JBossXBRuntimeException("Failed to load value type for addMethod.name=" + 1061 addMethodMetaData.getMethodName() + 1062 ", valueType=" + 1063 addMethodMetaData.getValueType() + 1064 ": " + e.getMessage(), e 1065 ); 1066 } 1067 } 1068 else if(addMethodMetaData.isChildType()) 1069 { 1070 if(o == null) 1071 { 1072 throw new JBossXBRuntimeException("addMethod=" + 1073 addMethodMetaData.getMethodName() + 1074 " for element " + 1075 qName + 1076 " is configured with valueType='child'. The valueType cannot be determined because" + 1077 " the child is null" 1078 ); 1079 } 1080 valueType = o.getClass(); 1081 } 1082 1083 Class ownerClass = owner.getClass(); 1084 Method addMethod; 1085 try 1086 { 1087 addMethod = ownerClass.getMethod(addMethodMetaData.getMethodName(), new Class []{valueType}); 1088 } 1089 catch(NoSuchMethodException e) 1090 { 1091 throw new JBossXBRuntimeException("Failed to find addMethod.name=" + 1092 addMethodMetaData.getMethodName() + 1093 ", addMethod.valueType=" + 1094 valueType.getName() + 1095 " in class " + 1096 ownerClass.getName() + 1097 ": " + 1098 e.getMessage(), e 1099 ); 1100 } 1101 1102 try 1103 { 1104 addMethod.invoke(owner, new Object []{o}); 1105 } 1106 catch(Exception e) 1107 { 1108 throw new JBossXBRuntimeException("setParent failed for " + 1109 qName + 1110 "=" + 1111 o + 1112 ": addMethod=" + 1113 addMethodMetaData.getMethodName() + 1114 " threw an exception for owner=" + 1115 owner + 1116 ", value=" + 1117 o + 1118 ": " + 1119 e.getMessage(), 1120 e 1121 ); 1122 } 1123 } 1124 1125 private void invokePut(QName qName, TermBinding term, Object owner, Object o) 1126 { 1127 PutMethodMetaData putMethodMetaData = term.getPutMethodMetaData(); 1128 1129 MapEntryMetaData mapEntryMetaData = term.getMapEntryMetaData(); 1130 if(mapEntryMetaData == null) 1131 { 1132 throw new JBossXBRuntimeException((putMethodMetaData == null ? 1133 "Parent object is an instance of java.util.Map" : 1134 "putMethod is specified for element " + qName 1135 ) + 1136 " but mapEntry is specified for neither element " + 1137 qName + 1138 " nor it's type." 1139 ); 1140 } 1141 1142 Class oClass = o.getClass(); 1143 String getKeyMethodName = mapEntryMetaData.getGetKeyMethod(); 1144 if(getKeyMethodName == null) 1145 { 1146 getKeyMethodName = "getKey"; 1147 } 1148 1149 Method keyMethod; 1150 try 1151 { 1152 keyMethod = oClass.getMethod(getKeyMethodName, null); 1153 } 1154 catch(NoSuchMethodException e) 1155 { 1156 throw new JBossXBRuntimeException("setParent failed for " + 1157 qName + 1158 "=" + 1159 o + 1160 ": getKeyMethod=" + 1161 getKeyMethodName + 1162 " not found in " + oClass 1163 ); 1164 } 1165 1166 Object key; 1167 try 1168 { 1169 key = keyMethod.invoke(o, null); 1170 } 1171 catch(Exception e) 1172 { 1173 throw new JBossXBRuntimeException("setParent failed for " + 1174 qName + 1175 "=" + 1176 o + 1177 ": getKeyMethod=" + 1178 getKeyMethodName + 1179 " threw an exception: " + e.getMessage(), e 1180 ); 1181 } 1182 1183 Class keyType = Object .class; 1184 Class valueType = Object .class; 1185 String putMethodName = "put"; 1186 Class ownerClass = owner.getClass(); 1187 1188 if(putMethodMetaData != null) 1189 { 1190 if(putMethodMetaData.getKeyType() != null) 1191 { 1192 try 1193 { 1194 keyType = Thread.currentThread().getContextClassLoader().loadClass(putMethodMetaData.getKeyType()); 1195 } 1196 catch(ClassNotFoundException e) 1197 { 1198 throw new JBossXBRuntimeException("setParent failed for " + qName + ": " + e.getMessage(), e); 1199 } 1200 } 1201 1202 if(putMethodMetaData.getValueType() != null) 1203 { 1204 try 1205 { 1206 valueType = Thread.currentThread().getContextClassLoader().loadClass(putMethodMetaData.getValueType()); 1207 } 1208 catch(ClassNotFoundException e) 1209 { 1210 throw new JBossXBRuntimeException("setParent failed for " + qName + ": " + e.getMessage(), e); 1211 } 1212 } 1213 1214 String name = putMethodMetaData.getName(); 1215 if(name != null) 1216 { 1217 putMethodName = name; 1218 } 1219 } 1220 1221 Method putMethod; 1222 try 1223 { 1224 putMethod = ownerClass.getMethod(putMethodName, new Class []{keyType, valueType}); 1225 } 1226 catch(NoSuchMethodException e) 1227 { 1228 throw new JBossXBRuntimeException("setParent failed for " + 1229 qName + 1230 "=" + 1231 o + 1232 ": putMethod=" + 1233 putMethodName + 1234 "(" + keyType.getName() + " key, " + valueType.getName() + " value) not found in " + ownerClass 1235 ); 1236 } 1237 1238 Object value = o; 1239 String valueMethodName = mapEntryMetaData.getGetValueMethod(); 1240 if(valueMethodName != null) 1241 { 1242 Method valueMethod; 1243 try 1244 { 1245 valueMethod = oClass.getMethod(valueMethodName, null); 1246 } 1247 catch(NoSuchMethodException e) 1248 { 1249 throw new JBossXBRuntimeException("setParent failed for " + 1250 qName + 1251 "=" + 1252 o + 1253 ": getValueMethod=" + 1254 mapEntryMetaData.getGetValueMethod() + 1255 " not found in " + oClass 1256 ); 1257 } 1258 1259 try 1260 { 1261 value = valueMethod.invoke(o, null); 1262 } 1263 catch(Exception e) 1264 { 1265 throw new JBossXBRuntimeException("setParent failed for " + 1266 qName + 1267 "=" + 1268 o + 1269 ": getValueMethod=" + 1270 mapEntryMetaData.getGetValueMethod() + 1271 " threw an exception: " + e.getMessage(), e 1272 ); 1273 } 1274 } 1275 else if(o instanceof MapEntry) 1276 { 1277 value = ((MapEntry)o).getValue(); 1278 } 1279 1280 try 1281 { 1282 putMethod.invoke(owner, new Object []{key, value}); 1283 } 1284 catch(Exception e) 1285 { 1286 throw new JBossXBRuntimeException("setParent failed for " + 1287 qName + 1288 "=" + 1289 o + 1290 ": putMethod=" + 1291 putMethodName + 1292 " threw an exception for owner=" + 1293 owner + 1294 ", key=" + 1295 key + 1296 ", value=" + 1297 value + 1298 ": " + 1299 e.getMessage(), 1300 e 1301 ); 1302 } 1303 } 1304 1305 private Class classForNonArrayItem(ElementBinding element, Class parentClass) 1306 { 1307 String clsName; 1308 1309 ClassMetaData clsMetaData = element.getClassMetaData(); 1311 clsName = clsMetaData == null ? null : clsMetaData.getImpl(); 1312 if(clsName == null) 1313 { 1314 MapEntryMetaData mapEntryMetaData = element.getMapEntryMetaData(); 1315 if(mapEntryMetaData != null) 1316 { 1317 clsName = mapEntryMetaData.getImpl(); 1318 if(clsName == null) 1319 { 1320 clsName = MapEntry.class.getName(); 1321 } 1322 } 1323 } 1324 1325 if(clsName == null) 1327 { 1328 if(parentClass == null) 1329 { 1330 clsName = classFromQName(element); 1331 } 1332 else 1333 { 1334 PropertyMetaData propertyMetaData = element.getPropertyMetaData(); 1335 String propName = propertyMetaData == null ? null : propertyMetaData.getName(); 1336 if(propName == null) 1337 { 1338 if(element.getAddMethodMetaData() == null && element.getPutMethodMetaData() == null) 1340 { 1341 propName = 1342 Util.xmlNameToFieldName(element.getQName().getLocalPart(), element.getSchema().isIgnoreLowLine()); 1343 } 1344 } 1345 1346 if(propName != null) 1347 { 1348 FieldInfo fieldInfo = FieldInfo.getFieldInfo(parentClass, propName, false); 1349 Class fieldType = fieldInfo == null ? null : fieldInfo.getType(); 1350 1351 if(fieldType == null || 1352 Modifier.isAbstract(fieldType.getModifiers()) || 1353 Modifier.isInterface(fieldType.getModifiers()) || 1354 fieldType.isArray() || 1355 Collection .class.isAssignableFrom(fieldType)) 1356 { 1357 clsName = classFromQName(element); 1358 } 1359 else 1360 { 1361 return fieldType; 1362 } 1363 } 1364 } 1365 } 1366 1367 return loadClassForTerm(clsName, element.getSchema().isIgnoreUnresolvedFieldOrClass(), element.getQName()); 1368 } 1369 1370 private String classFromQName(ElementBinding element) 1371 { 1372 String clsName; 1373 QName typeBase = element.getType().getQName(); 1374 if(typeBase == null) 1375 { 1376 typeBase = element.getQName(); 1377 } 1378 1379 SchemaBinding schema = element.getSchema(); 1380 PackageMetaData pkgMetaData = schema.getPackageMetaData(); 1381 if(pkgMetaData == null) 1382 { 1383 clsName = 1384 Util.xmlNameToClassName(typeBase.getNamespaceURI(), 1385 typeBase.getLocalPart(), 1386 schema.isIgnoreLowLine() 1387 ); 1388 } 1389 else 1390 { 1391 String pkg = pkgMetaData.getName(); 1392 clsName = 1393 pkg == null || pkg.length() == 0 ? 1394 Util.xmlNameToClassName(typeBase.getLocalPart(), schema.isIgnoreLowLine()) : 1395 pkg + "." + Util.xmlNameToClassName(typeBase.getLocalPart(), schema.isIgnoreLowLine()); 1396 } 1397 return clsName; 1398 } 1399 1400 private static Class classForSimpleType(TypeBinding type, boolean nillable) 1401 { 1402 ValueMetaData valueMetaData = type.getValueMetaData(); 1403 if(valueMetaData != null && valueMetaData.getUnmarshalMethod() != null) 1404 { 1405 return RtUtil.getUnmarshalMethod(type.getQName(), valueMetaData).getReturnType(); 1406 } 1407 else if(type.getClassMetaData() != null && type.getClassMetaData().getImpl() != null) 1408 { 1409 return RtUtil.loadClass(type.getClassMetaData().getImpl(), true); 1410 } 1411 1412 TypeBinding itemType = type.getItemType(); 1413 if(itemType != null) 1414 { 1415 if(type.getSchemaBinding().isUnmarshalListsToArrays()) 1416 { 1417 Class itemClass = classForSimpleType(itemType, nillable); 1419 return Array.newInstance(itemClass, 0).getClass(); 1420 } 1421 else 1422 { 1423 return java.util.List .class; 1424 } 1425 } 1426 else 1427 { 1428 QName qName = type.getQName(); 1429 if(qName != null && Constants.NS_XML_SCHEMA.equals(qName.getNamespaceURI())) 1430 { 1431 return SimpleTypeBindings.classForType(qName.getLocalPart(), nillable); 1432 } 1433 else 1434 { 1435 TypeBinding baseType = type.getBaseType(); 1436 if(baseType == null) 1437 { 1438 throw new JBossXBRuntimeException("Expected a base type here."); 1439 } 1440 1441 return classForSimpleType(baseType, nillable); 1442 } 1443 } 1444 } 1445} 1446 | Popular Tags |