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