1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.bind.v2.runtime;
  27 
  28 import java.io.IOException;
  29 import java.lang.ref.WeakReference;
  30 import java.lang.reflect.Field;
  31 import java.lang.reflect.Method;
  32 import java.lang.reflect.Type;
  33 import java.util.Arrays;
  34 import java.util.Collection;
  35 import java.util.Collections;
  36 import java.util.Comparator;
  37 import java.util.HashMap;
  38 import java.util.HashSet;
  39 import java.util.LinkedHashMap;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Map.Entry;
  43 import java.util.Set;
  44 import java.util.TreeSet;
  45 import javax.xml.bind.Binder;
  46 import javax.xml.bind.JAXBContext;
  47 import javax.xml.bind.JAXBElement;
  48 import javax.xml.bind.JAXBException;
  49 import javax.xml.bind.JAXBIntrospector;
  50 import javax.xml.bind.Marshaller;
  51 import javax.xml.bind.SchemaOutputResolver;
  52 import javax.xml.bind.Unmarshaller;
  53 import javax.xml.bind.Validator;
  54 import javax.xml.bind.annotation.XmlAttachmentRef;
  55 import javax.xml.bind.annotation.XmlList;
  56 import javax.xml.bind.annotation.XmlNs;
  57 import javax.xml.bind.annotation.XmlSchema;
  58 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
  59 import javax.xml.namespace.QName;
  60 import javax.xml.parsers.DocumentBuilder;
  61 import javax.xml.parsers.DocumentBuilderFactory;
  62 import javax.xml.parsers.FactoryConfigurationError;
  63 import javax.xml.parsers.ParserConfigurationException;
  64 import javax.xml.transform.Result;
  65 import javax.xml.transform.Transformer;
  66 import javax.xml.transform.TransformerConfigurationException;
  67 import javax.xml.transform.TransformerFactory;
  68 import javax.xml.transform.sax.SAXResult;
  69 import javax.xml.transform.sax.SAXTransformerFactory;
  70 import javax.xml.transform.sax.TransformerHandler;
  71 
  72 import com.sun.istack.internal.NotNull;
  73 import com.sun.istack.internal.Pool;
  74 import com.sun.xml.internal.bind.api.AccessorException;
  75 import com.sun.xml.internal.bind.api.Bridge;
  76 import com.sun.xml.internal.bind.api.BridgeContext;
  77 import com.sun.xml.internal.bind.api.CompositeStructure;
  78 import com.sun.xml.internal.bind.api.ErrorListener;
  79 import com.sun.xml.internal.bind.api.JAXBRIContext;
  80 import com.sun.xml.internal.bind.api.RawAccessor;
  81 import com.sun.xml.internal.bind.api.TypeReference;
  82 import com.sun.xml.internal.bind.unmarshaller.DOMScanner;
  83 import com.sun.xml.internal.bind.util.Which;
  84 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
  85 import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader;
  86 import com.sun.xml.internal.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
  87 import com.sun.xml.internal.bind.v2.model.core.Adapter;
  88 import com.sun.xml.internal.bind.v2.model.core.NonElement;
  89 import com.sun.xml.internal.bind.v2.model.core.Ref;
  90 import com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl;
  91 import com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder;
  92 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
  93 import com.sun.xml.internal.bind.v2.model.nav.ReflectionNavigator;
  94 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeArrayInfo;
  95 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeBuiltinLeafInfo;
  96 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
  97 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementInfo;
  98 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeEnumLeafInfo;
  99 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeLeafInfo;
 100 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfo;
 101 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfoSet;
 102 import com.sun.xml.internal.bind.v2.runtime.output.Encoded;
 103 import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
 104 import com.sun.xml.internal.bind.v2.runtime.property.Property;
 105 import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
 106 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
 107 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TagName;
 108 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
 109 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
 110 import com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator;
 111 import com.sun.xml.internal.bind.v2.util.EditDistance;
 112 import com.sun.xml.internal.bind.v2.util.QNameMap;
 113 import com.sun.xml.internal.txw2.output.ResultFactory;
 114 
 115 import org.w3c.dom.Document;
 116 import org.w3c.dom.Element;
 117 import org.w3c.dom.Node;
 118 import org.xml.sax.SAXException;
 119 import org.xml.sax.SAXParseException;
 120 import org.xml.sax.helpers.DefaultHandler;
 121 
 122 /**
 123  * This class provides the implementation of JAXBContext.
 124  *
 125  */
 126 public final class JAXBContextImpl extends JAXBRIContext {
 127 
 128     /**
 129      * All the bridge classes.
 130      */
 131     private final Map<TypeReference,Bridge> bridges = new LinkedHashMap<TypeReference,Bridge>();
 132 
 133     /**
 134      * Shared instance of {@link TransformerFactory}.
 135      * Lock before use, because a {@link TransformerFactory} is not thread-safe
 136      * whereas {@link JAXBContextImpl} is.
 137      * Lazily created.
 138      */
 139     private volatile static SAXTransformerFactory tf;
 140 
 141     /**
 142      * Shared instance of {@link DocumentBuilder}.
 143      * Lock before use. Lazily created.
 144      */
 145     private static DocumentBuilder db;
 146 
 147     private final QNameMap<JaxBeanInfo> rootMap = new QNameMap<JaxBeanInfo>();
 148     private final HashMap<QName,JaxBeanInfo> typeMap = new HashMap<QName,JaxBeanInfo>();
 149 
 150     /**
 151      * Map from JAXB-bound {@link Class} to its {@link JaxBeanInfo}.
 152      */
 153     private final Map<Class,JaxBeanInfo> beanInfoMap = new LinkedHashMap<Class,JaxBeanInfo>();
 154 
 155     /**
 156      * All created {@link JaxBeanInfo}s.
 157      * Updated from each {@link JaxBeanInfo}s constructors to avoid infinite recursion
 158      * for a cyclic reference.
 159      *
 160      * <p>
 161      * This map is only used while the {@link JAXBContextImpl} is built and set to null
 162      * to avoid keeping references too long.
 163      */
 164     protected Map<RuntimeTypeInfo,JaxBeanInfo> beanInfos = new LinkedHashMap<RuntimeTypeInfo, JaxBeanInfo>();
 165 
 166     private final Map<Class/*scope*/,Map<QName,ElementBeanInfoImpl>> elements = new LinkedHashMap<Class, Map<QName, ElementBeanInfoImpl>>();
 167 
 168     /**
 169      * Pool of {@link Marshaller}s.
 170      */
 171     public final Pool<Marshaller> marshallerPool = new Pool.Impl<Marshaller>() {
 172         protected @NotNull Marshaller create() {
 173             return createMarshaller();
 174         }
 175     };
 176 
 177     public final Pool<Unmarshaller> unmarshallerPool = new Pool.Impl<Unmarshaller>() {
 178         protected @NotNull Unmarshaller create() {
 179             return createUnmarshaller();
 180         }
 181     };
 182 
 183     /**
 184      * Used to assign indices to known names in this grammar.
 185      * Reset to null once the build phase is completed.
 186      */
 187     public NameBuilder nameBuilder = new NameBuilder();
 188 
 189     /**
 190      * Keeps the list of known names.
 191      * This field is set once the build pahse is completed.
 192      */
 193     public final NameList nameList;
 194 
 195     /**
 196      * Input to the JAXBContext.newInstance, so that we can recreate
 197      * {@link RuntimeTypeInfoSet} whenever we need.
 198      */
 199     private final String defaultNsUri;
 200     private final Class[] classes;
 201 
 202     /**
 203      * true to reorder attributes lexicographically in preparation of the c14n support.
 204      */
 205     protected final boolean c14nSupport;
 206 
 207     /**
 208      * Flag that user has provided a custom AccessorFactory for JAXB to use
 209      */
 210     public final boolean xmlAccessorFactorySupport;
 211 
 212     /**
 213      * @see JAXBRIContext#TREAT_EVERYTHING_NILLABLE
 214      */
 215     public final boolean allNillable;
 216 
 217     /**
 218      * Store properties, so that they can be recovered in the run (is here because of JSON encoding of Jersey).
 219      */
 220     public final boolean retainPropertyInfo;
 221 
 222     /**
 223      * Supress reflection accessor warnings.
 224      */
 225     public final boolean supressAccessorWarnings;
 226 
 227     /**
 228      * Improved xsi type handling.
 229      */
 230     public final boolean improvedXsiTypeHandling;
 231 
 232     private WeakReference<RuntimeTypeInfoSet> typeInfoSetCache;
 233 
 234     private @NotNull RuntimeAnnotationReader annotationReader;
 235 
 236     private /*almost final*/ boolean hasSwaRef;
 237     private final @NotNull Map<Class,Class> subclassReplacements;
 238 
 239     /**
 240      * If true, we aim for faster {@link JAXBContext} instanciation performance,
 241      * instead of going after efficient sustained unmarshalling/marshalling performance.
 242      *
 243      * @since 2.0.4
 244      */
 245     public final boolean fastBoot;
 246 
 247     private Set<XmlNs> xmlNsSet = null;
 248 
 249     /**
 250      * Returns declared XmlNs annotations (from package-level annotation XmlSchema
 251      *
 252      * @return set of all present XmlNs annotations
 253      */
 254     public Set<XmlNs> getXmlNsSet() {
 255         return xmlNsSet;
 256     }
 257 
 258     private JAXBContextImpl(JAXBContextBuilder builder) throws JAXBException {
 259 
 260         this.defaultNsUri = builder.defaultNsUri;
 261         this.retainPropertyInfo = builder.retainPropertyInfo;
 262         this.annotationReader = builder.annotationReader;
 263         this.subclassReplacements = builder.subclassReplacements;
 264         this.c14nSupport = builder.c14nSupport;
 265         this.classes = builder.classes;
 266         this.xmlAccessorFactorySupport = builder.xmlAccessorFactorySupport;
 267         this.allNillable = builder.allNillable;
 268         this.supressAccessorWarnings = builder.supressAccessorWarnings;
 269         this.improvedXsiTypeHandling = builder.improvedXsiTypeHandling;
 270 
 271         Collection<TypeReference> typeRefs = builder.typeRefs;
 272 
 273         boolean fastB;
 274         try {
 275             fastB = Boolean.getBoolean(JAXBContextImpl.class.getName()+".fastBoot");
 276         } catch (SecurityException e) {
 277             fastB = false;
 278         }
 279         this.fastBoot = fastB;
 280 
 281         System.arraycopy(classes,0,this.classes,0,classes.length);
 282 
 283         RuntimeTypeInfoSet typeSet = getTypeInfoSet();
 284 
 285         // at least prepare the empty table so that we don't have to check for null later
 286         elements.put(null,new LinkedHashMap<QName, ElementBeanInfoImpl>());
 287 
 288         // recognize leaf bean infos
 289         for( RuntimeBuiltinLeafInfo leaf : RuntimeBuiltinLeafInfoImpl.builtinBeanInfos ) {
 290             LeafBeanInfoImpl<?> bi = new LeafBeanInfoImpl(this,leaf);
 291             beanInfoMap.put(leaf.getClazz(),bi);
 292             for( QName t : bi.getTypeNames() )
 293                 typeMap.put(t,bi);
 294         }
 295 
 296         for (RuntimeEnumLeafInfo e : typeSet.enums().values()) {
 297             JaxBeanInfo<?> bi = getOrCreate(e);
 298             for (QName qn : bi.getTypeNames())
 299                 typeMap.put( qn, bi );
 300             if(e.isElement())
 301                 rootMap.put( e.getElementName(), bi );
 302         }
 303 
 304         for (RuntimeArrayInfo a : typeSet.arrays().values()) {
 305             JaxBeanInfo<?> ai = getOrCreate(a);
 306             for (QName qn : ai.getTypeNames())
 307                 typeMap.put( qn, ai );
 308         }
 309 
 310         for( Entry<Class, ? extends RuntimeClassInfo> e : typeSet.beans().entrySet() ) {
 311             ClassBeanInfoImpl<?> bi = getOrCreate(e.getValue());
 312 
 313             XmlSchema xs = this.annotationReader.getPackageAnnotation(XmlSchema.class, e.getKey(), null);
 314             if(xs != null) {
 315                 if(xs.xmlns() != null && xs.xmlns().length > 0) {
 316                     if(xmlNsSet == null)
 317                         xmlNsSet = new HashSet<XmlNs>();
 318                     xmlNsSet.addAll(Arrays.asList(xs.xmlns()));
 319                 }
 320             }
 321 
 322             if(bi.isElement())
 323                 rootMap.put( e.getValue().getElementName(), bi );
 324 
 325             for (QName qn : bi.getTypeNames())
 326                 typeMap.put( qn, bi );
 327         }
 328 
 329         // fill in element mappings
 330         for( RuntimeElementInfo n : typeSet.getAllElements() ) {
 331             ElementBeanInfoImpl bi = getOrCreate(n);
 332             if(n.getScope()==null)
 333                 rootMap.put(n.getElementName(),bi);
 334 
 335             RuntimeClassInfo scope = n.getScope();
 336             Class scopeClazz = scope==null?null:scope.getClazz();
 337             Map<QName,ElementBeanInfoImpl> m = elements.get(scopeClazz);
 338             if(m==null) {
 339                 m = new LinkedHashMap<QName, ElementBeanInfoImpl>();
 340                 elements.put(scopeClazz,m);
 341             }
 342             m.put(n.getElementName(),bi);
 343         }
 344 
 345         // this one is so that we can handle plain JAXBElements.
 346         beanInfoMap.put(JAXBElement.class,new ElementBeanInfoImpl(this));
 347         // another special BeanInfoImpl just for marshalling
 348         beanInfoMap.put(CompositeStructure.class,new CompositeStructureBeanInfo(this));
 349 
 350         getOrCreate(typeSet.getAnyTypeInfo());
 351 
 352         // then link them all!
 353         for (JaxBeanInfo bi : beanInfos.values())
 354             bi.link(this);
 355 
 356         // register primitives for boxed types just to make GrammarInfo fool-proof
 357         for( Map.Entry<Class,Class> e : RuntimeUtil.primitiveToBox.entrySet() )
 358             beanInfoMap.put( e.getKey(), beanInfoMap.get(e.getValue()) );
 359 
 360         // build bridges
 361         ReflectionNavigator nav = typeSet.getNavigator();
 362 
 363         for (TypeReference tr : typeRefs) {
 364             XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
 365             Adapter<Type,Class> a=null;
 366             XmlList xl = tr.get(XmlList.class);
 367 
 368             // eventually compute the in-memory type
 369             Class erasedType = nav.erasure(tr.type);
 370 
 371             if(xjta!=null) {
 372                 a = new Adapter<Type,Class>(xjta.value(),nav);
 373             }
 374             if(tr.get(XmlAttachmentRef.class)!=null) {
 375                 a = new Adapter<Type,Class>(SwaRefAdapter.class,nav);
 376                 hasSwaRef = true;
 377             }
 378 
 379             if(a!=null) {
 380                 erasedType = nav.erasure(a.defaultType);
 381             }
 382 
 383             Name name = nameBuilder.createElementName(tr.tagName);
 384 
 385             InternalBridge bridge;
 386             if(xl==null)
 387                 bridge = new BridgeImpl(this, name,getBeanInfo(erasedType,true),tr);
 388             else
 389                 bridge = new BridgeImpl(this, name,new ValueListBeanInfoImpl(this,erasedType),tr);
 390 
 391             if(a!=null)
 392                 bridge = new BridgeAdapter(bridge,a.adapterType);
 393 
 394             bridges.put(tr,bridge);
 395         }
 396 
 397         this.nameList = nameBuilder.conclude();
 398 
 399         for (JaxBeanInfo bi : beanInfos.values())
 400             bi.wrapUp();
 401 
 402         // no use for them now
 403         nameBuilder = null;
 404         beanInfos = null;
 405     }
 406 
 407     /**
 408      * True if this JAXBContext has {@link XmlAttachmentRef}.
 409      */
 410     public boolean hasSwaRef() {
 411         return hasSwaRef;
 412     }
 413 
 414     public RuntimeTypeInfoSet getRuntimeTypeInfoSet() {
 415         try {
 416             return getTypeInfoSet();
 417         } catch (IllegalAnnotationsException e) {
 418             // impossible, once the model is constructred
 419             throw new AssertionError(e);
 420         }
 421     }
 422 
 423     /**
 424      * Creates a {@link RuntimeTypeInfoSet}.
 425      */
 426     public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException {
 427 
 428         // check cache
 429         if(typeInfoSetCache!=null) {
 430             RuntimeTypeInfoSet r = typeInfoSetCache.get();
 431             if(r!=null)
 432                 return r;
 433         }
 434 
 435         final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri);
 436 
 437         IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder();
 438         builder.setErrorHandler(errorHandler);
 439 
 440         for( Class c : classes ) {
 441             if(c==CompositeStructure.class)
 442                 // CompositeStructure doesn't have TypeInfo, so skip it.
 443                 // We'll add JaxBeanInfo for this later automatically
 444                 continue;
 445             builder.getTypeInfo(new Ref<Type,Class>(c));
 446         }
 447 
 448         this.hasSwaRef |= builder.hasSwaRef;
 449         RuntimeTypeInfoSet r = builder.link();
 450 
 451         errorHandler.check();
 452         assert r!=null : "if no error was reported, the link must be a success";
 453 
 454         typeInfoSetCache = new WeakReference<RuntimeTypeInfoSet>(r);
 455 
 456         return r;
 457     }
 458 
 459 
 460     public ElementBeanInfoImpl getElement(Class scope, QName name) {
 461         Map<QName,ElementBeanInfoImpl> m = elements.get(scope);
 462         if(m!=null) {
 463             ElementBeanInfoImpl bi = m.get(name);
 464             if(bi!=null)
 465                 return bi;
 466         }
 467         m = elements.get(null);
 468         return m.get(name);
 469     }
 470 
 471 
 472 
 473 
 474 
 475     private ElementBeanInfoImpl getOrCreate( RuntimeElementInfo rei ) {
 476         JaxBeanInfo bi = beanInfos.get(rei);
 477         if(bi!=null)    return (ElementBeanInfoImpl)bi;
 478 
 479         // all elements share the same type, so we can't register them to beanInfoMap
 480         return new ElementBeanInfoImpl(this, rei);
 481     }
 482 
 483     protected JaxBeanInfo getOrCreate( RuntimeEnumLeafInfo eli ) {
 484         JaxBeanInfo bi = beanInfos.get(eli);
 485         if(bi!=null)    return bi;
 486         bi = new LeafBeanInfoImpl(this,eli);
 487         beanInfoMap.put(bi.jaxbType,bi);
 488         return bi;
 489     }
 490 
 491     protected ClassBeanInfoImpl getOrCreate( RuntimeClassInfo ci ) {
 492         ClassBeanInfoImpl bi = (ClassBeanInfoImpl)beanInfos.get(ci);
 493         if(bi!=null)    return bi;
 494         bi = new ClassBeanInfoImpl(this,ci);
 495         beanInfoMap.put(bi.jaxbType,bi);
 496         return bi;
 497     }
 498 
 499     protected JaxBeanInfo getOrCreate( RuntimeArrayInfo ai ) {
 500         JaxBeanInfo abi = beanInfos.get(ai);
 501         if(abi!=null)   return abi;
 502 
 503         abi = new ArrayBeanInfoImpl(this,ai);
 504 
 505         beanInfoMap.put(ai.getType(),abi);
 506         return abi;
 507     }
 508 
 509     public JaxBeanInfo getOrCreate(RuntimeTypeInfo e) {
 510         if(e instanceof RuntimeElementInfo)
 511             return getOrCreate((RuntimeElementInfo)e);
 512         if(e instanceof RuntimeClassInfo)
 513             return getOrCreate((RuntimeClassInfo)e);
 514         if(e instanceof RuntimeLeafInfo) {
 515             JaxBeanInfo bi = beanInfos.get(e); // must have been created
 516             assert bi!=null;
 517             return bi;
 518         }
 519         if(e instanceof RuntimeArrayInfo)
 520             return getOrCreate((RuntimeArrayInfo)e);
 521         if(e.getType()==Object.class) {
 522             // anyType
 523             JaxBeanInfo bi = beanInfoMap.get(Object.class);
 524             if(bi==null) {
 525                 bi = new AnyTypeBeanInfo(this,e);
 526                 beanInfoMap.put(Object.class,bi);
 527             }
 528             return bi;
 529         }
 530 
 531         throw new IllegalArgumentException();
 532     }
 533 
 534     /**
 535      * Gets the {@link JaxBeanInfo} object that can handle
 536      * the given JAXB-bound object.
 537      *
 538      * <p>
 539      * This method traverses the base classes of the given object.
 540      *
 541      * @return null
 542      *      if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>.
 543      */
 544     public final JaxBeanInfo getBeanInfo(Object o) {
 545         // don't allow xs:anyType beanInfo to handle all the unbound objects
 546         for( Class c=o.getClass(); c!=Object.class; c=c.getSuperclass()) {
 547             JaxBeanInfo bi = beanInfoMap.get(c);
 548             if(bi!=null)    return bi;
 549         }
 550         if(o instanceof Element)
 551             return beanInfoMap.get(Object.class);   // return the BeanInfo for xs:anyType
 552         for( Class c : o.getClass().getInterfaces()) {
 553             JaxBeanInfo bi = beanInfoMap.get(c);
 554             if(bi!=null)    return bi;
 555         }
 556         return null;
 557     }
 558 
 559     /**
 560      * Gets the {@link JaxBeanInfo} object that can handle
 561      * the given JAXB-bound object.
 562      *
 563      * @param fatal
 564      *      if true, the failure to look up will throw an exception.
 565      *      Otherwise it will just return null.
 566      */
 567     public final JaxBeanInfo getBeanInfo(Object o,boolean fatal) throws JAXBException {
 568         JaxBeanInfo bi = getBeanInfo(o);
 569         if(bi!=null)    return bi;
 570         if(fatal) {
 571             if(o instanceof Document)
 572                 throw new JAXBException(Messages.ELEMENT_NEEDED_BUT_FOUND_DOCUMENT.format(o.getClass()));
 573             throw new JAXBException(Messages.UNKNOWN_CLASS.format(o.getClass()));
 574         }
 575         return null;
 576     }
 577 
 578     /**
 579      * Gets the {@link JaxBeanInfo} object that can handle
 580      * the given JAXB-bound class.
 581      *
 582      * <p>
 583      * This method doesn't look for base classes.
 584      *
 585      * @return null
 586      *      if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>.
 587      */
 588     public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) {
 589         return (JaxBeanInfo<T>)beanInfoMap.get(clazz);
 590     }
 591 
 592     /**
 593      * Gets the {@link JaxBeanInfo} object that can handle
 594      * the given JAXB-bound class.
 595      *
 596      * @param fatal
 597      *      if true, the failure to look up will throw an exception.
 598      *      Otherwise it will just return null.
 599      */
 600     public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz,boolean fatal) throws JAXBException {
 601         JaxBeanInfo<T> bi = getBeanInfo(clazz);
 602         if(bi!=null)    return bi;
 603         if(fatal)
 604             throw new JAXBException(clazz.getName()+" is not known to this context");
 605         return null;
 606     }
 607 
 608     /**
 609      * Based on the tag name, determine what object to unmarshal,
 610      * and then set a new object and its loader to the current unmarshaller state.
 611      *
 612      * @return
 613      *      null if the given name pair is not recognized.
 614      */
 615     public final Loader selectRootLoader( UnmarshallingContext.State state, TagName tag ) {
 616         JaxBeanInfo beanInfo = rootMap.get(tag.uri,tag.local);
 617         if(beanInfo==null)
 618             return null;
 619 
 620         return beanInfo.getLoader(this,true);
 621     }
 622 
 623     /**
 624      * Gets the {@link JaxBeanInfo} for the given named XML Schema type.
 625      *
 626      * @return
 627      *      null if the type name is not recognized. For schema
 628      *      languages other than XML Schema, this method always
 629      *      returns null.
 630      */
 631     public JaxBeanInfo getGlobalType(QName name) {
 632         return typeMap.get(name);
 633     }
 634 
 635     /**
 636      * Finds a type name that this context recognizes which is
 637      * "closest" to the given type name.
 638      *
 639      * <p>
 640      * This method is used for error recovery.
 641      */
 642     public String getNearestTypeName(QName name) {
 643         String[] all = new String[typeMap.size()];
 644         int i=0;
 645         for (QName qn : typeMap.keySet()) {
 646             if(qn.getLocalPart().equals(name.getLocalPart()))
 647                 return qn.toString();  // probably a match, as people often gets confused about namespace.
 648             all[i++] = qn.toString();
 649         }
 650 
 651         String nearest = EditDistance.findNearest(name.toString(), all);
 652 
 653         if(EditDistance.editDistance(nearest,name.toString())>10)
 654             return null;    // too far apart.
 655 
 656         return nearest;
 657     }
 658 
 659     /**
 660      * Returns the set of valid root tag names.
 661      * For diagnostic use.
 662      */
 663     public Set<QName> getValidRootNames() {
 664         Set<QName> r = new TreeSet<QName>(QNAME_COMPARATOR);
 665         for (QNameMap.Entry e : rootMap.entrySet()) {
 666             r.add(e.createQName());
 667         }
 668         return r;
 669     }
 670 
 671     /**
 672      * Cache of UTF-8 encoded local names to improve the performance for the marshalling.
 673      */
 674     private Encoded[] utf8nameTable;
 675 
 676     public synchronized Encoded[] getUTF8NameTable() {
 677         if(utf8nameTable==null) {
 678             Encoded[] x = new Encoded[nameList.localNames.length];
 679             for( int i=0; i<x.length; i++ ) {
 680                 Encoded e = new Encoded(nameList.localNames[i]);
 681                 e.compact();
 682                 x[i] = e;
 683             }
 684             utf8nameTable = x;
 685         }
 686         return utf8nameTable;
 687     }
 688 
 689     public int getNumberOfLocalNames() {
 690         return nameList.localNames.length;
 691     }
 692 
 693     public int getNumberOfElementNames() {
 694         return nameList.numberOfElementNames;
 695     }
 696 
 697     public int getNumberOfAttributeNames() {
 698         return nameList.numberOfAttributeNames;
 699     }
 700 
 701     /**
 702      * Creates a new identity transformer.
 703      */
 704     static Transformer createTransformer() {
 705         try {
 706             if (tf==null) {
 707                 synchronized(JAXBContextImpl.class) {
 708                     if (tf==null) {
 709                         tf = (SAXTransformerFactory)TransformerFactory.newInstance();
 710                     }
 711                 }
 712             }
 713             return tf.newTransformer();
 714         } catch (TransformerConfigurationException e) {
 715             throw new Error(e); // impossible
 716         }
 717     }
 718 
 719     /**
 720      * Creates a new identity transformer.
 721      */
 722     public static TransformerHandler createTransformerHandler() {
 723         try {
 724             if (tf==null) {
 725                 synchronized(JAXBContextImpl.class) {
 726                     if (tf==null) {
 727                         tf = (SAXTransformerFactory)TransformerFactory.newInstance();
 728                     }
 729                 }
 730             }
 731             return tf.newTransformerHandler();
 732         } catch (TransformerConfigurationException e) {
 733             throw new Error(e); // impossible
 734         }
 735     }
 736 
 737     /**
 738      * Creates a new DOM document.
 739      */
 740     static Document createDom() {
 741         synchronized(JAXBContextImpl.class) {
 742             if(db==null) {
 743                 try {
 744                     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 745                     dbf.setNamespaceAware(true);
 746                     db = dbf.newDocumentBuilder();
 747                 } catch (ParserConfigurationException e) {
 748                     // impossible
 749                     throw new FactoryConfigurationError(e);
 750                 }
 751             }
 752             return db.newDocument();
 753         }
 754     }
 755 
 756     public MarshallerImpl createMarshaller() {
 757         return new MarshallerImpl(this,null);
 758     }
 759 
 760     public UnmarshallerImpl createUnmarshaller() {
 761         return new UnmarshallerImpl(this,null);
 762     }
 763 
 764     public Validator createValidator() {
 765         throw new UnsupportedOperationException(Messages.NOT_IMPLEMENTED_IN_2_0.format());
 766     }
 767 
 768     @Override
 769     public JAXBIntrospector createJAXBIntrospector() {
 770         return new JAXBIntrospector() {
 771             public boolean isElement(Object object) {
 772                 return getElementName(object)!=null;
 773             }
 774 
 775             public QName getElementName(Object jaxbElement) {
 776                 try {
 777                     return JAXBContextImpl.this.getElementName(jaxbElement);
 778                 } catch (JAXBException e) {
 779                     return null;
 780                 }
 781             }
 782         };
 783     }
 784 
 785     private NonElement<Type,Class> getXmlType(RuntimeTypeInfoSet tis, TypeReference tr) {
 786         if(tr==null)
 787             throw new IllegalArgumentException();
 788 
 789         XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
 790         XmlList xl = tr.get(XmlList.class);
 791 
 792         Ref<Type,Class> ref = new Ref<Type,Class>(annotationReader, tis.getNavigator(), tr.type, xjta, xl );
 793 
 794         return tis.getTypeInfo(ref);
 795     }
 796 
 797     @Override
 798     public void generateEpisode(Result output) {
 799         if(output==null)
 800             throw new IllegalArgumentException();
 801         createSchemaGenerator().writeEpisodeFile(ResultFactory.createSerializer(output));
 802     }
 803 
 804     @Override
 805     @SuppressWarnings("ThrowableInitCause")
 806     public void generateSchema(SchemaOutputResolver outputResolver) throws IOException {
 807         if(outputResolver==null)
 808             throw new IOException(Messages.NULL_OUTPUT_RESOLVER.format());
 809 
 810         final SAXParseException[] e = new SAXParseException[1];
 811         final SAXParseException[] w = new SAXParseException[1];
 812 
 813         createSchemaGenerator().write(outputResolver, new ErrorListener() {
 814             public void error(SAXParseException exception) {
 815                 e[0] = exception;
 816             }
 817 
 818             public void fatalError(SAXParseException exception) {
 819                 e[0] = exception;
 820             }
 821 
 822             public void warning(SAXParseException exception) {
 823                 w[0] = exception;
 824             }
 825 
 826             public void info(SAXParseException exception) {}
 827         });
 828 
 829         if (e[0]!=null) {
 830             IOException x = new IOException(Messages.FAILED_TO_GENERATE_SCHEMA.format());
 831             x.initCause(e[0]);
 832             throw x;
 833         }
 834         if (w[0]!=null) {
 835             IOException x = new IOException(Messages.ERROR_PROCESSING_SCHEMA.format());
 836             x.initCause(w[0]);
 837             throw x;
 838         }
 839     }
 840 
 841     private XmlSchemaGenerator<Type,Class,Field,Method> createSchemaGenerator() {
 842         RuntimeTypeInfoSet tis;
 843         try {
 844             tis = getTypeInfoSet();
 845         } catch (IllegalAnnotationsException e) {
 846             // this shouldn't happen because we've already
 847             throw new AssertionError(e);
 848         }
 849 
 850         XmlSchemaGenerator<Type,Class,Field,Method> xsdgen =
 851                 new XmlSchemaGenerator<Type,Class,Field,Method>(tis.getNavigator(),tis);
 852 
 853         // JAX-RPC uses Bridge objects that collide with
 854         // @XmlRootElement.
 855         // we will avoid collision here
 856         Set<QName> rootTagNames = new HashSet<QName>();
 857         for (RuntimeElementInfo ei : tis.getAllElements()) {
 858             rootTagNames.add(ei.getElementName());
 859         }
 860         for (RuntimeClassInfo ci : tis.beans().values()) {
 861             if(ci.isElement())
 862                 rootTagNames.add(ci.asElement().getElementName());
 863         }
 864 
 865         for (TypeReference tr : bridges.keySet()) {
 866             if(rootTagNames.contains(tr.tagName))
 867                 continue;
 868 
 869             if(tr.type==void.class || tr.type==Void.class) {
 870                 xsdgen.add(tr.tagName,false,null);
 871             } else
 872             if(tr.type==CompositeStructure.class) {
 873                 // this is a special class we introduced for JAX-WS that we *don't* want in the schema
 874             } else {
 875                 NonElement<Type,Class> typeInfo = getXmlType(tis,tr);
 876                 xsdgen.add(tr.tagName, !Navigator.REFLECTION.isPrimitive(tr.type),typeInfo);
 877             }
 878         }
 879         return xsdgen;
 880     }
 881 
 882     public QName getTypeName(TypeReference tr) {
 883         try {
 884             NonElement<Type,Class> xt = getXmlType(getTypeInfoSet(),tr);
 885             if(xt==null)    throw new IllegalArgumentException();
 886             return xt.getTypeName();
 887         } catch (IllegalAnnotationsException e) {
 888             // impossible given that JAXBRIContext has been successfully built in the first place
 889             throw new AssertionError(e);
 890         }
 891     }
 892 
 893     /**
 894      * Used for testing.
 895      */
 896     public SchemaOutputResolver createTestResolver() {
 897         return new SchemaOutputResolver() {
 898             public Result createOutput(String namespaceUri, String suggestedFileName) {
 899                 SAXResult r = new SAXResult(new DefaultHandler());
 900                 r.setSystemId(suggestedFileName);
 901                 return r;
 902             }
 903         };
 904     }
 905 
 906     @Override
 907     public <T> Binder<T> createBinder(Class<T> domType) {
 908         if(domType==Node.class)
 909             return (Binder<T>)createBinder();
 910         else
 911             return super.createBinder(domType);
 912     }
 913 
 914     @Override
 915     public Binder<Node> createBinder() {
 916         return new BinderImpl<Node>(this,new DOMScanner());
 917     }
 918 
 919     public QName getElementName(Object o) throws JAXBException {
 920         JaxBeanInfo bi = getBeanInfo(o,true);
 921         if(!bi.isElement())
 922             return null;
 923         return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
 924     }
 925 
 926     public QName getElementName(Class o) throws JAXBException {
 927         JaxBeanInfo bi = getBeanInfo(o,true);
 928         if(!bi.isElement())
 929             return null;
 930         return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
 931     }
 932 
 933     public Bridge createBridge(TypeReference ref) {
 934         return bridges.get(ref);
 935     }
 936 
 937     public @NotNull BridgeContext createBridgeContext() {
 938         return new BridgeContextImpl(this);
 939     }
 940 
 941     public RawAccessor getElementPropertyAccessor(Class wrapperBean, String nsUri, String localName) throws JAXBException {
 942         JaxBeanInfo bi = getBeanInfo(wrapperBean,true);
 943         if(!(bi instanceof ClassBeanInfoImpl))
 944             throw new JAXBException(wrapperBean+" is not a bean");
 945 
 946         for( ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi; cb!=null; cb=cb.superClazz) {
 947             for (Property p : cb.properties) {
 948                 final Accessor acc = p.getElementPropertyAccessor(nsUri,localName);
 949                 if(acc!=null)
 950                     return new RawAccessor() {
 951                         // Accessor.set/get are designed for unmarshaller/marshaller, and hence
 952                         // they go through an adapter behind the scene.
 953                         // this isn't desirable for JAX-WS, which essentially uses this method
 954                         // just as a reflection library. So use the "unadapted" version to
 955                         // achieve the desired semantics
 956                         public Object get(Object bean) throws AccessorException {
 957                             return acc.getUnadapted(bean);
 958                         }
 959 
 960                         public void set(Object bean, Object value) throws AccessorException {
 961                             acc.setUnadapted(bean,value);
 962                         }
 963                     };
 964             }
 965         }
 966         throw new JAXBException(new QName(nsUri,localName)+" is not a valid property on "+wrapperBean);
 967     }
 968 
 969     public List<String> getKnownNamespaceURIs() {
 970         return Arrays.asList(nameList.namespaceURIs);
 971     }
 972 
 973     public String getBuildId() {
 974         Package pkg = getClass().getPackage();
 975         if(pkg==null)   return null;
 976         return pkg.getImplementationVersion();
 977     }
 978 
 979     @Override
 980     public String toString() {
 981         StringBuilder buf = new StringBuilder(Which.which(getClass()) + " Build-Id: " + getBuildId());
 982         buf.append("\nClasses known to this context:\n");
 983 
 984         Set<String> names = new TreeSet<String>();  // sort them so that it's easy to read
 985 
 986         for (Class key : beanInfoMap.keySet())
 987             names.add(key.getName());
 988 
 989         for(String name: names)
 990             buf.append("  ").append(name).append('\n');
 991 
 992         return buf.toString();
 993     }
 994 
 995     /**
 996      * Gets the value of the xmime:contentType attribute on the given object, or null
 997      * if for some reason it couldn't be found, including any error.
 998      */
 999     public String getXMIMEContentType( Object o ) {
1000         JaxBeanInfo bi = getBeanInfo(o);
1001         if(!(bi instanceof ClassBeanInfoImpl))
1002             return null;
1003 
1004         ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi;
1005         for (Property p : cb.properties) {
1006             if (p instanceof AttributeProperty) {
1007                 AttributeProperty ap = (AttributeProperty) p;
1008                 if(ap.attName.equals(WellKnownNamespace.XML_MIME_URI,"contentType"))
1009                     try {
1010                         return (String)ap.xacc.print(o);
1011                     } catch (AccessorException e) {
1012                         return null;
1013                     } catch (SAXException e) {
1014                         return null;
1015                     } catch (ClassCastException e) {
1016                         return null;
1017                     }
1018             }
1019         }
1020         return null;
1021     }
1022 
1023     /**
1024      * Creates a {@link JAXBContextImpl} that includes the specified additional classes.
1025      */
1026     public JAXBContextImpl createAugmented(Class<?> clazz) throws JAXBException {
1027         Class[] newList = new Class[classes.length+1];
1028         System.arraycopy(classes,0,newList,0,classes.length);
1029         newList[classes.length] = clazz;
1030 
1031         JAXBContextBuilder builder = new JAXBContextBuilder(this);
1032         builder.setClasses(newList);
1033         return builder.build();
1034     }
1035 
1036     private static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
1037         public int compare(QName lhs, QName rhs) {
1038             int r = lhs.getLocalPart().compareTo(rhs.getLocalPart());
1039             if(r!=0)    return r;
1040 
1041             return lhs.getNamespaceURI().compareTo(rhs.getNamespaceURI());
1042         }
1043     };
1044 
1045     public static class JAXBContextBuilder {
1046 
1047         private boolean retainPropertyInfo = false;
1048         private boolean supressAccessorWarnings = false;
1049         private String defaultNsUri = "";
1050         private @NotNull RuntimeAnnotationReader annotationReader = new RuntimeInlineAnnotationReader();
1051         private @NotNull Map<Class,Class> subclassReplacements = Collections.emptyMap();
1052         private boolean c14nSupport = false;
1053         private Class[] classes;
1054         private Collection<TypeReference> typeRefs;
1055         private boolean xmlAccessorFactorySupport = false;
1056         private boolean allNillable;
1057         private boolean improvedXsiTypeHandling = true;
1058 
1059         public JAXBContextBuilder() {};
1060 
1061         public JAXBContextBuilder(JAXBContextImpl baseImpl) {
1062             this.supressAccessorWarnings = baseImpl.supressAccessorWarnings;
1063             this.retainPropertyInfo = baseImpl.retainPropertyInfo;
1064             this.defaultNsUri = baseImpl.defaultNsUri;
1065             this.annotationReader = baseImpl.annotationReader;
1066             this.subclassReplacements = baseImpl.subclassReplacements;
1067             this.c14nSupport = baseImpl.c14nSupport;
1068             this.classes = baseImpl.classes;
1069             this.typeRefs = baseImpl.bridges.keySet();
1070             this.xmlAccessorFactorySupport = baseImpl.xmlAccessorFactorySupport;
1071             this.allNillable = baseImpl.allNillable;
1072         }
1073 
1074         public JAXBContextBuilder setRetainPropertyInfo(boolean val) {
1075             this.retainPropertyInfo = val;
1076             return this;
1077         }
1078 
1079         public JAXBContextBuilder setSupressAccessorWarnings(boolean val) {
1080             this.supressAccessorWarnings = val;
1081             return this;
1082         }
1083 
1084         public JAXBContextBuilder setC14NSupport(boolean val) {
1085             this.c14nSupport = val;
1086             return this;
1087         }
1088 
1089         public JAXBContextBuilder setXmlAccessorFactorySupport(boolean val) {
1090             this.xmlAccessorFactorySupport = val;
1091             return this;
1092         }
1093 
1094         public JAXBContextBuilder setDefaultNsUri(String val) {
1095             this.defaultNsUri = val;
1096             return this;
1097         }
1098 
1099         public JAXBContextBuilder setAllNillable(boolean val) {
1100             this.allNillable = val;
1101             return this;
1102         }
1103 
1104         public JAXBContextBuilder setClasses(Class[] val) {
1105             this.classes = val;
1106             return this;
1107         }
1108 
1109         public JAXBContextBuilder setAnnotationReader(RuntimeAnnotationReader val) {
1110             this.annotationReader = val;
1111             return this;
1112         }
1113 
1114         public JAXBContextBuilder setSubclassReplacements(Map<Class,Class> val) {
1115             this.subclassReplacements = val;
1116             return this;
1117         }
1118 
1119         public JAXBContextBuilder setTypeRefs(Collection<TypeReference> val) {
1120             this.typeRefs = val;
1121             return this;
1122         }
1123 
1124         public JAXBContextBuilder setImprovedXsiTypeHandling(boolean val) {
1125             this.improvedXsiTypeHandling = val;
1126             return this;
1127         }
1128 
1129         public JAXBContextImpl build() throws JAXBException {
1130 
1131             // fool-proof
1132             if (this.defaultNsUri == null) {
1133                 this.defaultNsUri = "";
1134             }
1135 
1136             if (this.subclassReplacements == null) {
1137                 this.subclassReplacements = Collections.emptyMap();
1138             }
1139 
1140             if (this.annotationReader == null) {
1141                 this.annotationReader = new RuntimeInlineAnnotationReader();
1142             }
1143 
1144             if (this.typeRefs == null) {
1145                 this.typeRefs = Collections.<TypeReference>emptyList();
1146             }
1147 
1148             return new JAXBContextImpl(this);
1149         }
1150 
1151     }
1152 
1153 }