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