| 1 7 package org.jboss.xb.binding.metadata.unmarshalling.impl; 8 9 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBindingFactory; 10 import org.jboss.xb.binding.metadata.unmarshalling.NamespaceBinding; 11 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinding; 12 import org.jboss.xb.binding.metadata.unmarshalling.TopElementBinding; 13 import org.jboss.xb.binding.metadata.unmarshalling.ElementBinding; 14 import org.jboss.xb.binding.metadata.unmarshalling.BasicElementBinding; 15 import org.jboss.xb.binding.metadata.unmarshalling.AttributeBinding; 16 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBindingStack; 17 import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinder; 18 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueBinding; 19 import org.jboss.xb.binding.metadata.unmarshalling.XmlValueContainer; 20 import org.jboss.xb.binding.JBossXBRuntimeException; 21 22 import javax.xml.namespace.QName ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.List ; 26 import java.util.Map ; 27 import java.util.HashMap ; 28 import java.lang.reflect.Field ; 29 import java.lang.reflect.Method ; 30 import java.lang.reflect.Modifier ; 31 import java.lang.reflect.Constructor ; 32 33 37 public class DocumentBindingFactoryImpl 38 extends DocumentBindingFactory 39 { 40 public DocumentBindingStack newDocumentBindingStack() 41 { 42 return new DocumentBindingStackImpl(); 43 } 44 45 public NamespaceBinding bindNamespace(DocumentBinding doc, String namespaceUri, String javaPackage) 46 { 47 DocumentBindingStackImpl docStack = (DocumentBindingStackImpl)doc; 48 return docStack.bindNamespace(new DefaultNamespaceBinding(docStack, namespaceUri, javaPackage)); 49 } 50 51 public TopElementBinding bindTopElement(NamespaceBinding ns, String elementName, Class javaClass) 52 { 53 NamespaceBindingStack nsStack = (NamespaceBindingStack)ns; 54 return nsStack.bindTopElement(new DefaultTopElementBinding(nsStack, elementName, javaClass)); 55 } 56 57 public ElementBinding bindElement(BasicElementBinding parent, 58 String namespaceUri, 59 String elementName, 60 String fieldName, 61 Class javaType) 62 { 63 BasicElementBindingStack basicStack = (BasicElementBindingStack)parent; 64 return basicStack.bindChild( 65 new DefaultElementBinding(parent, new QName (namespaceUri, elementName), fieldName, javaType) 66 ); 67 } 68 69 public XmlValueBinding bindValue(BasicElementBinding element, String fieldName, Class javaType) 70 { 71 ElementBindingStack basicStack = (ElementBindingStack)element; 72 return basicStack.bindValue(new DefaultXmlValueBinding(element, fieldName, javaType)); 73 } 74 75 public XmlValueBinding bindValue(XmlValueContainer container, String fieldName, Class javaType) 76 { 77 XmlValueContainerStack stack = (XmlValueContainerStack)container; 78 return stack.bindValue(new DefaultXmlValueBinding(container, fieldName, javaType)); 79 } 80 81 public AttributeBinding bindAttribute(BasicElementBinding parent, 82 String namespaceUri, 83 String attributeName, 84 String fieldName, 85 Class javaType) 86 { 87 BasicElementBindingStack stack = (BasicElementBindingStack)parent; 88 AttributeBinding attr = new AttributeBindingImpl(new QName (namespaceUri, attributeName), 89 javaType, 90 parent.getJavaType(), 91 fieldName 92 ); 93 stack.bindAttribute(attr); 94 return attr; 95 } 96 97 public DocumentBinding newDocumentBinding() 98 { 99 return new DocumentBindingStackImpl(); 100 } 101 102 106 108 public static abstract class AbstractDocumentBinding 109 implements DocumentBinding 110 { 111 protected final DocumentBinding doc; 112 113 protected AbstractDocumentBinding(DocumentBinding doc) 114 { 115 if(doc == null) 116 { 117 doc = DocumentBindingFactory.newInstance().newDocumentBindingStack(); 119 ((DocumentBindingStackImpl)doc).push(this); 120 } 121 this.doc = doc; 122 } 123 124 public NamespaceBinding getNamespace(String namespaceUri) 125 { 126 return doc.getNamespace(namespaceUri); 127 } 128 129 protected abstract NamespaceBinding getNamespaceLocal(String namespaceUri); 130 } 131 132 public static abstract class AbstractNamespaceBinding 133 implements NamespaceBinding 134 { 135 protected final String namespaceUri; 136 private final DocumentBinding doc; 137 138 protected AbstractNamespaceBinding(DocumentBinding doc, String namespaceUri) 139 { 140 this.namespaceUri = namespaceUri; 141 this.doc = doc; 142 } 143 144 public DocumentBinding getDocument() 145 { 146 return doc; 147 } 148 149 public String getNamespaceUri() 150 { 151 return namespaceUri; 152 } 153 154 public String getJavaPackage() 155 { 156 return doc.getNamespace(namespaceUri).getJavaPackage(); 157 } 158 159 public TopElementBinding getTopElement(String elementName) 160 { 161 return doc.getNamespace(namespaceUri).getTopElement(elementName); 162 } 163 164 protected abstract String getJavaPackageLocal(); 165 166 protected abstract TopElementBinding getTopElementLocal(String elementName); 167 } 168 169 public static abstract class AbstractXmlValueContainer 170 implements XmlValueContainer 171 { 172 protected final QName name; 173 174 public AbstractXmlValueContainer(QName name) 175 { 176 this.name = name; 177 } 178 179 public QName getName() 180 { 181 return name; 182 } 183 184 public XmlValueBinding getValue() 185 { 186 return getValueStackReference().getValue(); 187 } 188 189 public Class getJavaType() 190 { 191 return getValueStackReference().getJavaType(); 192 } 193 194 protected abstract XmlValueContainer getValueStackReference(); 195 196 protected abstract XmlValueBinding getValueLocal(); 197 198 protected abstract Class getJavaTypeLocal(); 199 } 200 201 public static abstract class AbstractBasicElementBinding 202 extends AbstractXmlValueContainer 203 implements BasicElementBinding 204 { 205 protected AbstractBasicElementBinding(QName elementName) 206 { 207 super(elementName); 208 } 209 210 public DocumentBinding getDocument() 211 { 212 return getStackReference().getDocument(); 213 } 214 215 public ElementBinding getElement(QName elementName) 216 { 217 return getStackReference().getElement(elementName); 218 } 219 220 public AttributeBinding getAttribute(QName attributeName) 221 { 222 return getStackReference().getAttribute(attributeName); 223 } 224 225 public XmlValueBinding getValue() 226 { 227 return getStackReference().getValue(); 228 } 229 230 protected XmlValueContainer getValueStackReference() 231 { 232 return getStackReference(); 233 } 234 235 protected abstract Class getJavaTypeLocal(); 236 237 protected abstract ElementBinding getElementLocal(QName elementName); 238 239 protected abstract AttributeBinding getAttributeLocal(QName attributeName); 240 241 protected abstract XmlValueBinding getValueLocal(); 242 243 protected abstract BasicElementBinding getStackReference(); 244 } 245 246 public static abstract class AbstractTopElementBinding 247 extends AbstractBasicElementBinding 248 implements TopElementBinding 249 { 250 protected final NamespaceBinding ns; 251 252 protected AbstractTopElementBinding(NamespaceBinding ns, String elementName) 253 { 254 super(new QName (ns.getNamespaceUri(), elementName)); 255 this.ns = ns; 256 } 257 258 protected BasicElementBinding getStackReference() 259 { 260 return ns.getTopElement(name.getLocalPart()); 261 } 262 } 263 264 public static abstract class AbstractElementBinding 265 extends AbstractBasicElementBinding 266 implements ElementBinding 267 { 268 protected final BasicElementBinding parent; 269 270 protected AbstractElementBinding(BasicElementBinding parent, QName elementName) 271 { 272 super(elementName); 273 this.parent = parent; 274 } 275 276 public Field getField() 277 { 278 return ((ElementBinding)getStackReference()).getField(); 279 } 280 281 public Method getGetter() 282 { 283 return ((ElementBinding)getStackReference()).getGetter(); 284 } 285 286 public Method getSetter() 287 { 288 return ((ElementBinding)getStackReference()).getSetter(); 289 } 290 291 public Class getFieldType() 292 { 293 return ((ElementBinding)getStackReference()).getFieldType(); 294 } 295 296 protected BasicElementBinding getStackReference() 297 { 298 return parent.getElement(name); 299 } 300 301 protected abstract Field getFieldLocal(); 302 303 protected abstract Method getGetterLocal(); 304 305 protected abstract Method getSetterLocal(); 306 307 protected abstract Class getFieldTypeLocal(); 308 } 309 310 public static abstract class AbstractXmlValueBinding 311 extends AbstractXmlValueContainer 312 implements XmlValueBinding 313 { 314 private final XmlValueContainer container; 315 316 protected AbstractXmlValueBinding(XmlValueContainer container) 317 { 318 super(container.getName()); 319 this.container = container; 320 } 321 322 public Field getField() 323 { 324 return container.getValue().getField(); 325 } 326 327 public Method getGetter() 328 { 329 return container.getValue().getGetter(); 330 } 331 332 public Method getSetter() 333 { 334 return container.getValue().getSetter(); 335 } 336 337 public Class getFieldType() 338 { 339 return container.getValue().getFieldType(); 340 } 341 342 public XmlValueBinding getValue() 343 { 344 return container.getValue().getValue(); 345 } 346 347 protected XmlValueContainer getValueStackReference() 348 { 349 return container.getValue(); 350 } 351 352 protected abstract Field getFieldLocal(); 353 354 protected abstract Method getGetterLocal(); 355 356 protected abstract Method getSetterLocal(); 357 358 protected abstract Class getFieldTypeLocal(); 359 } 360 361 363 private static class DefaultNamespaceBinding 364 extends AbstractNamespaceBinding 365 { 366 private final String javaPackage; 367 368 public DefaultNamespaceBinding(DocumentBinding doc, String namespaceUri, String javaPackage) 369 { 370 super(doc, namespaceUri); 371 this.javaPackage = javaPackage; 372 } 373 374 protected String getJavaPackageLocal() 375 { 376 return javaPackage; 377 } 378 379 protected TopElementBinding getTopElementLocal(String elementName) 380 { 381 return null; 382 } 383 } 384 385 private static class DefaultTopElementBinding 386 extends AbstractTopElementBinding 387 { 388 private final Class javaType; 389 390 DefaultTopElementBinding(NamespaceBinding ns, String elementName, Class javaType) 391 { 392 super(ns, elementName); 393 this.javaType = javaType; 394 } 395 396 protected Class getJavaTypeLocal() 397 { 398 return javaType; 399 } 400 401 protected ElementBinding getElementLocal(QName elementName) 402 { 403 return null; 404 } 405 406 protected AttributeBinding getAttributeLocal(QName attributeName) 407 { 408 return null; 409 } 410 411 protected XmlValueBinding getValueLocal() 412 { 413 return null; 414 } 415 } 416 417 private static class DefaultElementBinding 418 extends AbstractElementBinding 419 { 420 private final Field field; 421 private final Method getter; 422 private final Method setter; 423 private final Class fieldType; 424 private final Class javaType; 425 426 public DefaultElementBinding(BasicElementBinding parent, QName elementName, String fieldName, Class javaType) 427 { 428 super(parent, elementName); 429 430 Class parentType = parent.getJavaType(); 431 if(Collection .class.isAssignableFrom(parentType)) 432 { 433 field = null; 434 getter = null; 435 setter = null; 436 fieldType = null; 437 } 438 else 439 { 440 Field tmpField = null; 441 Method tmpGetter = null; 442 Method tmpSetter = null; 443 Class tmpFieldType; 444 try 445 { 446 tmpField = parentType.getField(fieldName); 447 tmpFieldType = tmpField.getType(); 448 } 449 catch(NoSuchFieldException e) 450 { 451 String baseMethodName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); 452 try 453 { 454 tmpGetter = parentType.getMethod("get" + baseMethodName, null); 455 tmpFieldType = tmpGetter.getReturnType(); 456 try 457 { 458 tmpSetter = parentType.getMethod("set" + baseMethodName, new Class []{tmpGetter.getReturnType()}); 459 } 460 catch(NoSuchMethodException nosetter) 461 { 462 } 464 } 465 catch(NoSuchMethodException e1) 466 { 467 throw new JBossXBRuntimeException("Failed to bind " + 468 elementName + 469 " to field " + 470 fieldName + 471 " in " + 472 parentType + 473 ": neither field nor getter/setter were found." 474 ); 475 } 476 } 477 478 field = tmpField; 479 getter = tmpGetter; 480 setter = tmpSetter; 481 fieldType = tmpFieldType; 482 } 483 484 if(fieldType == null) 485 { 486 this.javaType = javaType == null ? String .class : javaType; 487 } 488 else 489 { 490 if(javaType == null) 491 { 492 this.javaType = fieldType; 493 } 494 else if(Collection .class == fieldType || 495 Collection .class.isAssignableFrom(fieldType) || 496 fieldType.isAssignableFrom(javaType)) 497 { 498 this.javaType = javaType; 499 } 500 else 501 { 502 throw new JBossXBRuntimeException("Failed to bind " + 503 elementName + 504 " to field " + 505 fieldName + 506 " in " + 507 parentType + 508 ": field type " + fieldType + " is not assignable from the specified Java type " + javaType 509 ); 510 } 511 512 if(this.javaType.isInterface() || Modifier.isAbstract(this.javaType.getModifiers())) 513 { 514 throw new JBossXBRuntimeException("Failed to bind " + 515 elementName + 516 " to field " + 517 fieldName + 518 " in " + 519 parentType + 520 ": Java type is abstract class or interface." 521 ); 522 } 523 } 524 } 525 526 protected Field getFieldLocal() 527 { 528 return field; 529 } 530 531 protected Method getGetterLocal() 532 { 533 return getter; 534 } 535 536 protected Method getSetterLocal() 537 { 538 return setter; 539 } 540 541 protected Class getFieldTypeLocal() 542 { 543 return fieldType; 544 } 545 546 protected Class getJavaTypeLocal() 547 { 548 return javaType; 549 } 550 551 protected ElementBinding getElementLocal(QName elementName) 552 { 553 return null; 554 } 555 556 protected AttributeBinding getAttributeLocal(QName attributeName) 557 { 558 return null; 559 } 560 561 protected XmlValueBinding getValueLocal() 562 { 563 return null; 564 } 565 } 566 567 private static class DefaultXmlValueBinding 568 extends AbstractXmlValueBinding 569 { 570 private final Field field; 571 private final Method getter; 572 private final Method setter; 573 private final Class fieldType; 574 private final Class javaType; 575 576 public DefaultXmlValueBinding(XmlValueContainer container, String fieldName, Class javaType) 577 { 578 super(container); 579 580 Class parentType = container.getJavaType(); 581 if(Collection .class.isAssignableFrom(parentType)) 582 { 583 field = null; 584 getter = null; 585 setter = null; 586 fieldType = null; 587 } 588 else 589 { 590 Field tmpField = null; 591 Method tmpGetter = null; 592 Method tmpSetter = null; 593 Class tmpFieldType = null; 594 try 595 { 596 tmpField = parentType.getField(fieldName); 597 tmpFieldType = tmpField.getType(); 598 } 599 catch(NoSuchFieldException e) 600 { 601 String baseMethodName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); 602 try 603 { 604 tmpGetter = parentType.getMethod("get" + baseMethodName, null); 605 tmpFieldType = tmpGetter.getReturnType(); 606 try 607 { 608 tmpSetter = parentType.getMethod("set" + baseMethodName, new Class []{tmpGetter.getReturnType()}); 609 } 610 catch(NoSuchMethodException nosetter) 611 { 612 } 614 } 615 catch(NoSuchMethodException e1) 616 { 617 throw new JBossXBRuntimeException("Failed to bind value of " + 618 container.getName() + 619 " to field " + 620 fieldName + 621 " in " + 622 parentType + 623 ": neither field nor getter/setter were found." 624 ); 625 } 626 } 627 628 field = tmpField; 629 getter = tmpGetter; 630 setter = tmpSetter; 631 fieldType = tmpFieldType; 632 } 633 634 if(fieldType == null) 635 { 636 this.javaType = javaType == null ? String .class : javaType; 637 } 638 else 639 { 640 if(javaType == null) 641 { 642 this.javaType = fieldType; 643 } 644 else if(Collection .class == fieldType || 645 Collection .class.isAssignableFrom(fieldType) || 646 fieldType.isAssignableFrom(javaType)) 647 { 648 this.javaType = javaType; 649 } 650 else 651 { 652 throw new JBossXBRuntimeException("Failed to bind value of " + 653 container.getName() + 654 " to field " + 655 fieldName + 656 " in " + 657 parentType + 658 ": field type " + fieldType + " is not assignable from the specified Java type " + javaType 659 ); 660 } 661 662 if(this.javaType.isInterface() || Modifier.isAbstract(this.javaType.getModifiers())) 663 { 664 throw new JBossXBRuntimeException("Failed to bind value of " + 665 container.getName() + 666 " to field " + 667 fieldName + 668 " in " + 669 parentType + 670 ": Java type is abstract class or interface." 671 ); 672 } 673 } 674 } 675 676 protected Field getFieldLocal() 677 { 678 return field; 679 } 680 681 protected Method getGetterLocal() 682 { 683 return getter; 684 } 685 686 protected Method getSetterLocal() 687 { 688 return setter; 689 } 690 691 protected Class getFieldTypeLocal() 692 { 693 return fieldType; 694 } 695 696 protected XmlValueBinding getValueLocal() 697 { 698 return null; 699 } 700 701 protected Class getJavaTypeLocal() 702 { 703 return javaType; 704 } 705 } 706 707 709 class DocumentBindingStackImpl 710 implements DocumentBindingStack 711 { 712 private final List stack = new ArrayList (); 713 private final Map namespaces = new HashMap (); 714 715 public DocumentBindingStackImpl() 716 { 717 } 718 719 public DocumentBindingStackImpl(DocumentBinding doc) 720 { 721 if(doc != null) 722 { 723 push(doc); 724 } 725 } 726 727 void push(DocumentBinding doc) 728 { 729 stack.add(doc); 730 } 731 732 NamespaceBindingStack bindNamespace(NamespaceBinding ns) 733 { 734 NamespaceBindingStack stack = (NamespaceBindingStack)getNamespace(ns.getNamespaceUri()); 735 if(stack == null) 736 { 737 stack = new NamespaceBindingStack(this, ns.getNamespaceUri()); 738 namespaces.put(ns.getNamespaceUri(), stack); 739  
|