1 /*
2  * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Distribution License v. 1.0, which is available at
6  * http://www.eclipse.org/org/documents/edl-v10.php.
7  *
8  * SPDX-License-Identifier: BSD-3-Clause
9  */

10
11 package com.sun.xml.bind.v2.runtime;
12
13 import java.io.IOException;
14 import java.lang.ref.WeakReference;
15 import java.lang.reflect.Field;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Type;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Set;
29 import java.util.TreeSet;
30 import javax.xml.bind.Binder;
31 import javax.xml.bind.JAXBContext;
32 import javax.xml.bind.JAXBElement;
33 import javax.xml.bind.JAXBException;
34 import javax.xml.bind.JAXBIntrospector;
35 import javax.xml.bind.Marshaller;
36 import javax.xml.bind.SchemaOutputResolver;
37 import javax.xml.bind.Unmarshaller;
38 import javax.xml.bind.Validator;
39 import javax.xml.bind.annotation.XmlAttachmentRef;
40 import javax.xml.bind.annotation.XmlList;
41 import javax.xml.bind.annotation.XmlNs;
42 import javax.xml.bind.annotation.XmlSchema;
43 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
44 import javax.xml.namespace.QName;
45 import javax.xml.parsers.DocumentBuilder;
46 import javax.xml.parsers.DocumentBuilderFactory;
47 import javax.xml.parsers.FactoryConfigurationError;
48 import javax.xml.parsers.ParserConfigurationException;
49 import javax.xml.transform.Result;
50 import javax.xml.transform.Transformer;
51 import javax.xml.transform.TransformerConfigurationException;
52 import javax.xml.transform.TransformerFactory;
53 import javax.xml.transform.sax.SAXTransformerFactory;
54 import javax.xml.transform.sax.TransformerHandler;
55
56 import com.sun.istack.NotNull;
57 import com.sun.istack.Pool;
58 import com.sun.xml.bind.v2.WellKnownNamespace;
59 import com.sun.xml.bind.api.AccessorException;
60 import com.sun.xml.bind.api.Bridge;
61 import com.sun.xml.bind.api.BridgeContext;
62 import com.sun.xml.bind.api.CompositeStructure;
63 import com.sun.xml.bind.api.ErrorListener;
64 import com.sun.xml.bind.api.JAXBRIContext;
65 import com.sun.xml.bind.api.RawAccessor;
66 import com.sun.xml.bind.api.TypeReference;
67 import com.sun.xml.bind.unmarshaller.DOMScanner;
68 import com.sun.xml.bind.util.Which;
69 import com.sun.xml.bind.v2.model.annotation.RuntimeAnnotationReader;
70 import com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
71 import com.sun.xml.bind.v2.model.core.Adapter;
72 import com.sun.xml.bind.v2.model.core.NonElement;
73 import com.sun.xml.bind.v2.model.core.Ref;
74 import com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl;
75 import com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder;
76 import com.sun.xml.bind.v2.model.nav.Navigator;
77 import com.sun.xml.bind.v2.model.runtime.RuntimeArrayInfo;
78 import com.sun.xml.bind.v2.model.runtime.RuntimeBuiltinLeafInfo;
79 import com.sun.xml.bind.v2.model.runtime.RuntimeClassInfo;
80 import com.sun.xml.bind.v2.model.runtime.RuntimeElementInfo;
81 import com.sun.xml.bind.v2.model.runtime.RuntimeEnumLeafInfo;
82 import com.sun.xml.bind.v2.model.runtime.RuntimeLeafInfo;
83 import com.sun.xml.bind.v2.model.runtime.RuntimeTypeInfo;
84 import com.sun.xml.bind.v2.model.runtime.RuntimeTypeInfoSet;
85 import com.sun.xml.bind.v2.runtime.output.Encoded;
86 import com.sun.xml.bind.v2.runtime.property.AttributeProperty;
87 import com.sun.xml.bind.v2.runtime.property.Property;
88 import com.sun.xml.bind.v2.runtime.reflect.Accessor;
89 import com.sun.xml.bind.v2.runtime.unmarshaller.Loader;
90 import com.sun.xml.bind.v2.runtime.unmarshaller.TagName;
91 import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
92 import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext;
93 import com.sun.xml.bind.v2.schemagen.XmlSchemaGenerator;
94 import com.sun.xml.bind.v2.util.EditDistance;
95 import com.sun.xml.bind.v2.util.QNameMap;
96 import com.sun.xml.bind.v2.util.XmlFactory;
97 import com.sun.xml.txw2.output.ResultFactory;
98
99 import org.w3c.dom.Document;
100 import org.w3c.dom.Element;
101 import org.w3c.dom.Node;
102 import org.xml.sax.SAXException;
103 import org.xml.sax.SAXParseException;
104
105 /**
106  * This class provides the implementation of JAXBContext.
107  *
108  */

109 public final class JAXBContextImpl extends JAXBRIContext {
110
111     /**
112      * All the bridge classes.
113      */

114     private final Map<TypeReference,Bridge> bridges = new LinkedHashMap<TypeReference,Bridge>();
115
116     /**
117      * Shared instance of {@link DocumentBuilder}.
118      * Lock before use. Lazily created.
119      */

120     private static DocumentBuilder db;
121
122     private final QNameMap<JaxBeanInfo> rootMap = new QNameMap<JaxBeanInfo>();
123     private final HashMap<QName,JaxBeanInfo> typeMap = new HashMap<QName,JaxBeanInfo>();
124
125     /**
126      * Map from JAXB-bound {@link Class} to its {@link JaxBeanInfo}.
127      */

128     private final Map<Class,JaxBeanInfo> beanInfoMap = new LinkedHashMap<Class,JaxBeanInfo>();
129
130     /**
131      * All created {@link JaxBeanInfo}s.
132      * Updated from each {@link JaxBeanInfo}s constructors to avoid infinite recursion
133      * for a cyclic reference.
134      *
135      * <p>
136      * This map is only used while the {@link JAXBContextImpl} is built and set to null
137      * to avoid keeping references too long.
138      */

139     protected Map<RuntimeTypeInfo,JaxBeanInfo> beanInfos = new LinkedHashMap<RuntimeTypeInfo, JaxBeanInfo>();
140
141     private final Map<Class/*scope*/,Map<QName,ElementBeanInfoImpl>> elements = new LinkedHashMap<Class, Map<QName, ElementBeanInfoImpl>>();
142
143     /**
144      * Pool of {@link Marshaller}s.
145      */

146     public final Pool<Marshaller> marshallerPool = new Pool.Impl<Marshaller>() {
147         protected @NotNull Marshaller create() {
148             return createMarshaller();
149         }
150     };
151
152     public final Pool<Unmarshaller> unmarshallerPool = new Pool.Impl<Unmarshaller>() {
153         protected @NotNull Unmarshaller create() {
154             return createUnmarshaller();
155         }
156     };
157
158     /**
159      * Used to assign indices to known names in this grammar.
160      * Reset to null once the build phase is completed.
161      */

162     public NameBuilder nameBuilder = new NameBuilder();
163
164     /**
165      * Keeps the list of known names.
166      * This field is set once the build pahse is completed.
167      */

168     public final NameList nameList;
169
170     /**
171      * Input to the JAXBContext.newInstance, so that we can recreate
172      * {@link RuntimeTypeInfoSet} whenever we need.
173      */

174     private final String defaultNsUri;
175     private final Class[] classes;
176
177     /**
178      * true to reorder attributes lexicographically in preparation of the c14n support.
179      */

180     protected final boolean c14nSupport;
181
182     /**
183      * Flag that user has provided a custom AccessorFactory for JAXB to use
184      */

185     public final boolean xmlAccessorFactorySupport;
186
187     /**
188      * @see JAXBRIContext#TREAT_EVERYTHING_NILLABLE
189      */

190     public final boolean allNillable;
191
192     /**
193      * Store properties, so that they can be recovered in the run (is here because of JSON encoding of Jersey).
194      */

195     public final boolean retainPropertyInfo;
196
197     /**
198      * Suppress reflection accessor warnings.
199      */

200     public final boolean supressAccessorWarnings;
201
202     /**
203      * Improved xsi type handling.
204      */

205     public final boolean improvedXsiTypeHandling;
206
207     /**
208      * Disable security processing.
209      */

210     public final boolean disableSecurityProcessing;
211
212     private WeakReference<RuntimeTypeInfoSet> typeInfoSetCache;
213
214     private @NotNull RuntimeAnnotationReader annotationReader;
215
216     private /*almost final*/ boolean hasSwaRef;
217     private final @NotNull Map<Class,Class> subclassReplacements;
218
219     /**
220      * If true, we aim for faster {@link JAXBContext} instantiation performance,
221      * instead of going after efficient sustained unmarshalling/marshalling performance.
222      *
223      * @since 2.0.4
224      */

225     public final boolean fastBoot;
226
227     private Set<XmlNs> xmlNsSet = null;
228
229     /**
230      * If true, despite the specification, unmarshall child element with parent namespace, if child namespace is not specified.
231      * The default value is null for System {code}com.sun.xml.bind.backupWithParentNamespace{code} property to be used,
232      * and false is assumed if it's not set either.
233      *
234      * Boolean
235      * @since 2.3.0
236      */

237     public Boolean backupWithParentNamespace = null;
238
239     /**
240      * The maximum number of errors unmarshall operation reports.  Use negative value to report all errors.
241      * The default value is 10.
242      *
243      * @since 2.3.3
244      */

245     public final int maxErrorsCount;
246
247     /**
248      * Returns declared XmlNs annotations (from package-level annotation XmlSchema
249      *
250      * @return set of all present XmlNs annotations
251      */

252     public Set<XmlNs> getXmlNsSet() {
253         return xmlNsSet;
254     }
255
256     private JAXBContextImpl(JAXBContextBuilder builder) throws JAXBException {
257
258         this.defaultNsUri = builder.defaultNsUri;
259         this.retainPropertyInfo = builder.retainPropertyInfo;
260         this.annotationReader = builder.annotationReader;
261         this.subclassReplacements = builder.subclassReplacements;
262         this.c14nSupport = builder.c14nSupport;
263         this.classes = builder.classes;
264         this.xmlAccessorFactorySupport = builder.xmlAccessorFactorySupport;
265         this.allNillable = builder.allNillable;
266         this.supressAccessorWarnings = builder.supressAccessorWarnings;
267         this.improvedXsiTypeHandling = builder.improvedXsiTypeHandling;
268         this.disableSecurityProcessing = builder.disableSecurityProcessing;
269         this.backupWithParentNamespace = builder.backupWithParentNamespace;
270         this.maxErrorsCount = builder.maxErrorsCount;
271
272         Collection<TypeReference> typeRefs = builder.typeRefs;
273
274         boolean fastB;
275         try {
276             fastB = Boolean.getBoolean(JAXBContextImpl.class.getName()+".fastBoot");
277         } catch (SecurityException e) {
278             fastB = false;
279         }
280         this.fastBoot = fastB;
281
282         RuntimeTypeInfoSet typeSet = getTypeInfoSet();
283
284         // at least prepare the empty table so that we don't have to check for null later
285         elements.put(null,new LinkedHashMap<QName, ElementBeanInfoImpl>());
286
287         // recognize leaf bean infos
288         for( RuntimeBuiltinLeafInfo leaf : RuntimeBuiltinLeafInfoImpl.builtinBeanInfos ) {
289             LeafBeanInfoImpl<?> bi = new LeafBeanInfoImpl(this,leaf);
290             beanInfoMap.put(leaf.getClazz(),bi);
291             for( QName t : bi.getTypeNames() )
292                 typeMap.put(t,bi);
293         }
294
295         for (RuntimeEnumLeafInfo e : typeSet.enums().values()) {
296             JaxBeanInfo<?> bi = getOrCreate(e);
297             for (QName qn : bi.getTypeNames())
298                 typeMap.put( qn, bi );
299             if(e.isElement())
300                 rootMap.put( e.getElementName(), bi );
301         }
302
303         for (RuntimeArrayInfo a : typeSet.arrays().values()) {
304             JaxBeanInfo<?> ai = getOrCreate(a);
305             for (QName qn : ai.getTypeNames())
306                 typeMap.put( qn, ai );
307         }
308
309         for( Entry<Class, ? extends RuntimeClassInfo> e : typeSet.beans().entrySet() ) {
310             ClassBeanInfoImpl<?> bi = getOrCreate(e.getValue());
311
312             XmlSchema xs = this.annotationReader.getPackageAnnotation(XmlSchema.class, e.getKey(), null);
313             if(xs != null) {
314                 if(xs.xmlns() != null && xs.xmlns().length > 0) {
315                     if(xmlNsSet == null)
316                         xmlNsSet = new HashSet<XmlNs>();
317                     xmlNsSet.addAll(Arrays.asList(xs.xmlns()));
318                 }
319             }
320
321             if(bi.isElement())
322                 rootMap.put( e.getValue().getElementName(), bi );
323
324             for (QName qn : bi.getTypeNames())
325                 typeMap.put( qn, bi );
326         }
327
328         // fill in element mappings
329         for( RuntimeElementInfo n : typeSet.getAllElements() ) {
330             ElementBeanInfoImpl bi = getOrCreate(n);
331             if(n.getScope()==null)
332                 rootMap.put(n.getElementName(),bi);
333
334             RuntimeClassInfo scope = n.getScope();
335             Class scopeClazz = scope==null?null:scope.getClazz();
336             Map<QName,ElementBeanInfoImpl> m = elements.get(scopeClazz);
337             if(m==null) {
338                 m = new LinkedHashMap<QName, ElementBeanInfoImpl>();
339                 elements.put(scopeClazz,m);
340             }
341             m.put(n.getElementName(),bi);
342         }
343
344         // this one is so that we can handle plain JAXBElements.
345         beanInfoMap.put(JAXBElement.class,new ElementBeanInfoImpl(this));
346         // another special BeanInfoImpl just for marshalling
347         beanInfoMap.put(CompositeStructure.class,new CompositeStructureBeanInfo(this));
348
349         getOrCreate(typeSet.getAnyTypeInfo());
350
351         // then link them all!
352         for (JaxBeanInfo bi : beanInfos.values())
353             bi.link(this);
354
355         // register primitives for boxed types just to make GrammarInfo fool-proof
356         for( Map.Entry<Class,Class> e : RuntimeUtil.primitiveToBox.entrySet() )
357             beanInfoMap.put( e.getKey(), beanInfoMap.get(e.getValue()) );
358
359         // build bridges
360         Navigator<Type, Class, Field, Method> nav = typeSet.getNavigator();
361
362         for (TypeReference tr : typeRefs) {
363             XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
364             Adapter<Type,Class> a=null;
365             XmlList xl = tr.get(XmlList.class);
366
367             // eventually compute the in-memory type
368             Class erasedType = (Class) nav.erasure(tr.type);
369
370             if(xjta!=null) {
371                 a = new Adapter<Type,Class>(xjta.value(),nav);
372             }
373             if(tr.get(XmlAttachmentRef.class)!=null) {
374                 a = new Adapter<Type,Class>(SwaRefAdapter.class,nav);
375                 hasSwaRef = true;
376             }
377
378             if(a!=null) {
379                 erasedType = (Class) nav.erasure(a.defaultType);
380             }
381
382             Name name = nameBuilder.createElementName(tr.tagName);
383
384             InternalBridge bridge;
385             if(xl==null)
386                 bridge = new BridgeImpl(this, name,getBeanInfo(erasedType,true),tr);
387             else
388                 bridge = new BridgeImpl(this, name,new ValueListBeanInfoImpl(this,erasedType),tr);
389
390             if(a!=null)
391                 bridge = new BridgeAdapter(bridge,a.adapterType);
392
393             bridges.put(tr,bridge);
394         }
395
396         this.nameList = nameBuilder.conclude();
397
398         for (JaxBeanInfo bi : beanInfos.values())
399             bi.wrapUp();
400
401         // no use for them now
402         nameBuilder = null;
403         beanInfos = null;
404     }
405
406     /**
407      * True if this JAXBContext has {@link XmlAttachmentRef}.
408      */

409     public boolean hasSwaRef() {
410         return hasSwaRef;
411     }
412
413     public RuntimeTypeInfoSet getRuntimeTypeInfoSet() {
414         try {
415             return getTypeInfoSet();
416         } catch (IllegalAnnotationsException e) {
417             // impossible, once the model is constructred
418             throw new AssertionError(e);
419         }
420     }
421
422     /**
423      * Creates a {@link RuntimeTypeInfoSet}.
424      */

425     public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException {
426
427         // check cache
428         if(typeInfoSetCache!=null) {
429             RuntimeTypeInfoSet r = typeInfoSetCache.get();
430             if(r!=null)
431                 return r;
432         }
433
434         final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri);
435
436         IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder();
437         builder.setErrorHandler(errorHandler);
438
439         for( Class c : classes ) {
440             if(c==CompositeStructure.class)
441                 // CompositeStructure doesn't have TypeInfo, so skip it.
442                 // We'll add JaxBeanInfo for this later automatically
443                 continue;
444             builder.getTypeInfo(new Ref<Type,Class>(c));
445         }
446
447         this.hasSwaRef |= builder.hasSwaRef;
448         RuntimeTypeInfoSet r = builder.link();
449
450         errorHandler.check();
451         assert r!=null : "if no error was reported, the link must be a success";
452
453         typeInfoSetCache = new WeakReference<RuntimeTypeInfoSet>(r);
454
455         return r;
456     }
457
458
459     public ElementBeanInfoImpl getElement(Class scope, QName name) {
460         Map<QName,ElementBeanInfoImpl> m = elements.get(scope);
461         if(m!=null) {
462             ElementBeanInfoImpl bi = m.get(name);
463             if(bi!=null)
464                 return bi;
465         }
466         m = elements.get(null);
467         return m.get(name);
468     }
469
470
471
472
473
474     private ElementBeanInfoImpl getOrCreate( RuntimeElementInfo rei ) {
475         JaxBeanInfo bi = beanInfos.get(rei);
476         if(bi!=null)    return (ElementBeanInfoImpl)bi;
477
478         // all elements share the same type, so we can't register them to beanInfoMap
479         return new ElementBeanInfoImpl(this, rei);
480     }
481
482     protected JaxBeanInfo getOrCreate( RuntimeEnumLeafInfo eli ) {
483         JaxBeanInfo bi = beanInfos.get(eli);
484         if(bi!=null)    return bi;
485         bi = new LeafBeanInfoImpl(this,eli);
486         beanInfoMap.put(bi.jaxbType,bi);
487         return bi;
488     }
489
490     protected ClassBeanInfoImpl getOrCreate( RuntimeClassInfo ci ) {
491         ClassBeanInfoImpl bi = (ClassBeanInfoImpl)beanInfos.get(ci);
492         if(bi!=null)    return bi;
493         bi = new ClassBeanInfoImpl(this,ci);
494         beanInfoMap.put(bi.jaxbType,bi);
495         return bi;
496     }
497
498     protected JaxBeanInfo getOrCreate( RuntimeArrayInfo ai ) {
499         JaxBeanInfo abi = beanInfos.get(ai);
500         if(abi!=null)   return abi;
501
502         abi = new ArrayBeanInfoImpl(this,ai);
503
504         beanInfoMap.put(ai.getType(),abi);
505         return abi;
506     }
507
508     public JaxBeanInfo getOrCreate(RuntimeTypeInfo e) {
509         if(e instanceof RuntimeElementInfo)
510             return getOrCreate((RuntimeElementInfo)e);
511         if(e instanceof RuntimeClassInfo)
512             return getOrCreate((RuntimeClassInfo)e);
513         if(e instanceof RuntimeLeafInfo) {
514             JaxBeanInfo bi = beanInfos.get(e); // must have been created
515             assert bi!=null;
516             return bi;
517         }
518         if(e instanceof RuntimeArrayInfo)
519             return getOrCreate((RuntimeArrayInfo)e);
520         if(e.getType()==Object.class) {
521             // anyType
522             JaxBeanInfo bi = beanInfoMap.get(Object.class);
523             if(bi==null) {
524                 bi = new AnyTypeBeanInfo(this,e);
525                 beanInfoMap.put(Object.class,bi);
526             }
527             return bi;
528         }
529
530         throw new IllegalArgumentException();
531     }
532
533     /**
534      * Gets the {@link JaxBeanInfo} object that can handle
535      * the given JAXB-bound object.
536      *
537      * <p>
538      * This method traverses the base classes of the given object.
539      *
540      * @return null
541      *      if {@code c} isn't a JAXB-bound class and {@code fatal==false}.
542      */

543     public final JaxBeanInfo getBeanInfo(Object o) {
544         // don't allow xs:anyType beanInfo to handle all the unbound objects
545         for( Class c=o.getClass(); c!=Object.class; c=c.getSuperclass()) {
546             JaxBeanInfo bi = beanInfoMap.get(c);
547             if(bi!=null)    return bi;
548         }
549         if(o instanceof Element)
550             return beanInfoMap.get(Object.class);   // return the BeanInfo for xs:anyType
551         for( Class c : o.getClass().getInterfaces()) {
552             JaxBeanInfo bi = beanInfoMap.get(c);
553             if(bi!=null)    return bi;
554         }
555         return null;
556     }
557
558     /**
559      * Gets the {@link JaxBeanInfo} object that can handle
560      * the given JAXB-bound object.
561      *
562      * @param fatal
563      *      if true, the failure to look up will throw an exception.
564      *      Otherwise it will just return null.
565      */

566     public final JaxBeanInfo getBeanInfo(Object o,boolean fatal) throws JAXBException {
567         JaxBeanInfo bi = getBeanInfo(o);
568         if(bi!=null)    return bi;
569         if(fatal) {
570             if(o instanceof Document)
571                 throw new JAXBException(Messages.ELEMENT_NEEDED_BUT_FOUND_DOCUMENT.format(o.getClass()));
572             throw new JAXBException(Messages.UNKNOWN_CLASS.format(o.getClass()));
573         }
574         return null;
575     }
576
577     /**
578      * Gets the {@link JaxBeanInfo} object that can handle
579      * the given JAXB-bound class.
580      *
581      * <p>
582      * This method doesn't look for base classes.
583      *
584      * @return null
585      *      if {@code c} isn't a JAXB-bound class and {@code fatal==false}.
586      */

587     public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) {
588         return (JaxBeanInfo<T>)beanInfoMap.get(clazz);
589     }
590
591     /**
592      * Gets the {@link JaxBeanInfo} object that can handle
593      * the given JAXB-bound class.
594      *
595      * @param fatal
596      *      if true, the failure to look up will throw an exception.
597      *      Otherwise it will just return null.
598      */

599     public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz,boolean fatal) throws JAXBException {
600         JaxBeanInfo<T> bi = getBeanInfo(clazz);
601         if(bi!=null)    return bi;
602         if(fatal)
603             throw new JAXBException(clazz.getName()+" is not known to this context");
604         return null;
605     }
606
607     /**
608      * Based on the tag name, determine what object to unmarshal,
609      * and then set a new object and its loader to the current unmarshaller state.
610      *
611      * @return
612      *      null if the given name pair is not recognized.
613      */

614     public final Loader selectRootLoader( UnmarshallingContext.State state, TagName tag ) {
615         JaxBeanInfo beanInfo = rootMap.get(tag.uri,tag.local);
616         if(beanInfo==null)
617             return null;
618
619         return beanInfo.getLoader(this,true);
620     }
621
622     /**
623      * Gets the {@link JaxBeanInfo} for the given named XML Schema type.
624      *
625      * @return
626      *      null if the type name is not recognized. For schema
627      *      languages other than XML Schema, this method always
628      *      returns null.
629      */

630     public JaxBeanInfo getGlobalType(QName name) {
631         return typeMap.get(name);
632     }
633
634     /**
635      * Finds a type name that this context recognizes which is
636      * "closest" to the given type name.
637      *
638      * <p>
639      * This method is used for error recovery.
640      */

641     public String getNearestTypeName(QName name) {
642         String[] all = new String[typeMap.size()];
643         int i=0;
644         for (QName qn : typeMap.keySet()) {
645             if(qn.getLocalPart().equals(name.getLocalPart()))
646                 return qn.toString();  // probably a match, as people often gets confused about namespace.
647             all[i++] = qn.toString();
648         }
649
650         String nearest = EditDistance.findNearest(name.toString(), all);
651
652         if(EditDistance.editDistance(nearest,name.toString())>10)
653             return null;    // too far apart.
654
655         return nearest;
656     }
657
658     /**
659      * Returns the set of valid root tag names.
660      * For diagnostic use.
661      */

662     public Set<QName> getValidRootNames() {
663         Set<QName> r = new TreeSet<QName>(QNAME_COMPARATOR);
664         for (QNameMap.Entry e : rootMap.entrySet()) {
665             r.add(e.createQName());
666         }
667         return r;
668     }
669
670     /**
671      * Cache of UTF-8 encoded local names to improve the performance for the marshalling.
672      */

673     private Encoded[] utf8nameTable;
674
675     public synchronized Encoded[] getUTF8NameTable() {
676         if(utf8nameTable==null) {
677             Encoded[] x = new Encoded[nameList.localNames.length];
678             forint i=0; i<x.length; i++ ) {
679                 Encoded e = new Encoded(nameList.localNames[i]);
680                 e.compact();
681                 x[i] = e;
682             }
683             utf8nameTable = x;
684         }
685         return utf8nameTable;
686     }
687
688     public int getNumberOfLocalNames() {
689         return nameList.localNames.length;
690     }
691
692     public int getNumberOfElementNames() {
693         return nameList.numberOfElementNames;
694     }
695
696     public int getNumberOfAttributeNames() {
697         return nameList.numberOfAttributeNames;
698     }
699
700     /**
701      * Creates a new identity transformer.
702      */

703     static Transformer createTransformer(boolean disableSecureProcessing) {
704         try {
705             SAXTransformerFactory tf = (SAXTransformerFactory)XmlFactory.createTransformerFactory(disableSecureProcessing);
706             return tf.newTransformer();
707         } catch (TransformerConfigurationException e) {
708             throw new Error(e); // impossible
709         }
710     }
711
712     /**
713      * Creates a new identity transformer.
714      */

715     public static TransformerHandler createTransformerHandler(boolean disableSecureProcessing) {
716         try {
717             SAXTransformerFactory tf = (SAXTransformerFactory)XmlFactory.createTransformerFactory(disableSecureProcessing);
718             return tf.newTransformerHandler();
719         } catch (TransformerConfigurationException e) {
720             throw new Error(e); // impossible
721         }
722     }
723
724     /**
725      * Creates a new DOM document.
726      */

727     static Document createDom(boolean disableSecurityProcessing) {
728         synchronized(JAXBContextImpl.class) {
729             if(db==null) {
730                 try {
731                     DocumentBuilderFactory dbf = XmlFactory.createDocumentBuilderFactory(disableSecurityProcessing);
732                     db = dbf.newDocumentBuilder();
733                 } catch (ParserConfigurationException e) {
734                     // impossible
735                     throw new FactoryConfigurationError(e);
736                 }
737             }
738             return db.newDocument();
739         }
740     }
741
742     public MarshallerImpl createMarshaller() {
743         return new MarshallerImpl(this,null);
744     }
745
746     public UnmarshallerImpl createUnmarshaller() {
747         return new UnmarshallerImpl(this,null);
748     }
749
750     public Validator createValidator() {
751         throw new UnsupportedOperationException(Messages.NOT_IMPLEMENTED_IN_2_0.format());
752     }
753
754     @Override
755     public JAXBIntrospector createJAXBIntrospector() {
756         return new JAXBIntrospector() {
757             public boolean isElement(Object object) {
758                 return getElementName(object)!=null;
759             }
760
761             public QName getElementName(Object jaxbElement) {
762                 try {
763                     return JAXBContextImpl.this.getElementName(jaxbElement);
764                 } catch (JAXBException e) {
765                     return null;
766                 }
767             }
768         };
769     }
770
771     private NonElement<Type,Class> getXmlType(RuntimeTypeInfoSet tis, TypeReference tr) {
772         if(tr==null)
773             throw new IllegalArgumentException();
774
775         XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
776         XmlList xl = tr.get(XmlList.class);
777
778         Ref<Type,Class> ref = new Ref<Type,Class>(annotationReader, tis.getNavigator(), tr.type, xjta, xl );
779
780         return tis.getTypeInfo(ref);
781     }
782
783     @Override
784     public void generateEpisode(Result output) {
785         if(output==null)
786             throw new IllegalArgumentException();
787         createSchemaGenerator().writeEpisodeFile(ResultFactory.createSerializer(output));
788     }
789
790     @Override
791     @SuppressWarnings("ThrowableInitCause")
792     public void generateSchema(SchemaOutputResolver outputResolver) throws IOException {
793         if(outputResolver==null)
794             throw new IOException(Messages.NULL_OUTPUT_RESOLVER.format());
795
796         final SAXParseException[] e = new SAXParseException[1];
797         final SAXParseException[] w = new SAXParseException[1];
798
799         createSchemaGenerator().write(outputResolver, new ErrorListener() {
800             public void error(SAXParseException exception) {
801                 e[0] = exception;
802             }
803
804             public void fatalError(SAXParseException exception) {
805                 e[0] = exception;
806             }
807
808             public void warning(SAXParseException exception) {
809                 w[0] = exception;
810             }
811
812             public void info(SAXParseException exception) {}
813         });
814
815         if (e[0]!=null) {
816             IOException x = new IOException(Messages.FAILED_TO_GENERATE_SCHEMA.format());
817             x.initCause(e[0]);
818             throw x;
819         }
820         if (w[0]!=null) {
821             IOException x = new IOException(Messages.ERROR_PROCESSING_SCHEMA.format());
822             x.initCause(w[0]);
823             throw x;
824         }
825     }
826
827     private XmlSchemaGenerator<Type,Class,Field,Method> createSchemaGenerator() {
828         RuntimeTypeInfoSet tis;
829         try {
830             tis = getTypeInfoSet();
831         } catch (IllegalAnnotationsException e) {
832             // this shouldn't happen because we've already
833             throw new AssertionError(e);
834         }
835
836         XmlSchemaGenerator<Type,Class,Field,Method> xsdgen =
837                 new XmlSchemaGenerator<Type,Class,Field,Method>(tis.getNavigator(),tis);
838
839         // JAX-RPC uses Bridge objects that collide with
840         // @XmlRootElement.
841         // we will avoid collision here
842         Set<QName> rootTagNames = new HashSet<QName>();
843         for (RuntimeElementInfo ei : tis.getAllElements()) {
844             rootTagNames.add(ei.getElementName());
845         }
846         for (RuntimeClassInfo ci : tis.beans().values()) {
847             if(ci.isElement())
848                 rootTagNames.add(ci.asElement().getElementName());
849         }
850
851         for (TypeReference tr : bridges.keySet()) {
852             if(rootTagNames.contains(tr.tagName))
853                 continue;
854
855             if(tr.type==void.class || tr.type==Void.class) {
856                 xsdgen.add(tr.tagName,false,null);
857             } else
858             if(tr.type==CompositeStructure.class) {
859                 // this is a special class we introduced for JAX-WS that we *don't* want in the schema
860             } else {
861                 NonElement<Type,Class> typeInfo = getXmlType(tis,tr);
862                 xsdgen.add(tr.tagName, !tis.getNavigator().isPrimitive(tr.type),typeInfo);
863             }
864         }
865         return xsdgen;
866     }
867
868     public QName getTypeName(TypeReference tr) {
869         try {
870             NonElement<Type,Class> xt = getXmlType(getTypeInfoSet(),tr);
871             if(xt==null)    throw new IllegalArgumentException();
872             return xt.getTypeName();
873         } catch (IllegalAnnotationsException e) {
874             // impossible given that JAXBRIContext has been successfully built in the first place
875             throw new AssertionError(e);
876         }
877     }
878
879     @Override
880     public <T> Binder<T> createBinder(Class<T> domType) {
881         if(domType==Node.class)
882             return (Binder<T>)createBinder();
883         else
884             return super.createBinder(domType);
885     }
886
887     @Override
888     public Binder<Node> createBinder() {
889         return new BinderImpl<Node>(this,new DOMScanner());
890     }
891
892     public QName getElementName(Object o) throws JAXBException {
893         JaxBeanInfo bi = getBeanInfo(o,true);
894         if(!bi.isElement())
895             return null;
896         return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
897     }
898
899     public QName getElementName(Class o) throws JAXBException {
900         JaxBeanInfo bi = getBeanInfo(o,true);
901         if(!bi.isElement())
902             return null;
903         return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
904     }
905
906     public Bridge createBridge(TypeReference ref) {
907         return bridges.get(ref);
908     }
909
910     public @NotNull BridgeContext createBridgeContext() {
911         return new BridgeContextImpl(this);
912     }
913
914     public RawAccessor getElementPropertyAccessor(Class wrapperBean, String nsUri, String localName) throws JAXBException {
915         JaxBeanInfo bi = getBeanInfo(wrapperBean,true);
916         if(!(bi instanceof ClassBeanInfoImpl))
917             throw new JAXBException(wrapperBean+" is not a bean");
918
919         for( ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi; cb!=null; cb=cb.superClazz) {
920             for (Property p : cb.properties) {
921                 final Accessor acc = p.getElementPropertyAccessor(nsUri,localName);
922                 if(acc!=null)
923                     return new RawAccessor() {
924                         // Accessor.set/get are designed for unmarshaller/marshaller, and hence
925                         // they go through an adapter behind the scene.
926                         // this isn't desirable for JAX-WS, which essentially uses this method
927                         // just as a reflection library. So use the "unadapted" version to
928                         // achieve the desired semantics
929                         public Object get(Object bean) throws AccessorException {
930                             return acc.getUnadapted(bean);
931                         }
932
933                         public void set(Object bean, Object value) throws AccessorException {
934                             acc.setUnadapted(bean,value);
935                         }
936                     };
937             }
938         }
939         throw new JAXBException(new QName(nsUri,localName)+" is not a valid property on "+wrapperBean);
940     }
941
942     public List<String> getKnownNamespaceURIs() {
943         return Arrays.asList(nameList.namespaceURIs);
944     }
945
946     public String getBuildId() {
947         Package pkg = getClass().getPackage();
948         if(pkg==null)   return null;
949         return pkg.getImplementationVersion();
950     }
951
952     @Override
953     public String toString() {
954         StringBuilder buf = new StringBuilder(Which.which(getClass()) + " Build-Id: " + getBuildId());
955         buf.append("\nClasses known to this context:\n");
956
957         Set<String> names = new TreeSet<String>();  // sort them so that it's easy to read
958
959         for (Class key : beanInfoMap.keySet())
960             names.add(key.getName());
961
962         for(String name: names)
963             buf.append("  ").append(name).append('\n');
964
965         return buf.toString();
966     }
967
968     /**
969      * Gets the value of the xmime:contentType attribute on the given object, or null
970      * if for some reason it couldn't be found, including any error.
971      */

972     public String getXMIMEContentType( Object o ) {
973         JaxBeanInfo bi = getBeanInfo(o);
974         if(!(bi instanceof ClassBeanInfoImpl))
975             return null;
976
977         ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi;
978         for (Property p : cb.properties) {
979             if (p instanceof AttributeProperty) {
980                 AttributeProperty ap = (AttributeProperty) p;
981                 if(ap.attName.equals(WellKnownNamespace.XML_MIME_URI,"contentType"))
982                     try {
983                         return (String)ap.xacc.print(o);
984                     } catch (AccessorException e) {
985                         return null;
986                     } catch (SAXException e) {
987                         return null;
988                     } catch (ClassCastException e) {
989                         return null;
990                     }
991             }
992         }
993         return null;
994     }
995
996     /**
997      * Creates a {@link JAXBContextImpl} that includes the specified additional classes.
998      */

999     public JAXBContextImpl createAugmented(Class<?> clazz) throws JAXBException {
1000         Class[] newList = new Class[classes.length+1];
1001         System.arraycopy(classes,0,newList,0,classes.length);
1002         newList[classes.length] = clazz;
1003
1004         JAXBContextBuilder builder = new JAXBContextBuilder(this);
1005         builder.setClasses(newList);
1006         return builder.build();
1007     }
1008
1009     private static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
1010         public int compare(QName lhs, QName rhs) {
1011             int r = lhs.getLocalPart().compareTo(rhs.getLocalPart());
1012             if(r!=0)    return r;
1013
1014             return lhs.getNamespaceURI().compareTo(rhs.getNamespaceURI());
1015         }
1016     };
1017
1018     public static class JAXBContextBuilder {
1019
1020         private boolean retainPropertyInfo = false;
1021         private boolean supressAccessorWarnings = false;
1022         private String defaultNsUri = "";
1023         private @NotNull RuntimeAnnotationReader annotationReader = new RuntimeInlineAnnotationReader();
1024         private @NotNull Map<Class,Class> subclassReplacements = Collections.emptyMap();
1025         private boolean c14nSupport = false;
1026         private Class[] classes;
1027         private Collection<TypeReference> typeRefs;
1028         private boolean xmlAccessorFactorySupport = false;
1029         private boolean allNillable;
1030         private boolean improvedXsiTypeHandling = true;
1031         private boolean disableSecurityProcessing = true;
1032         private Boolean backupWithParentNamespace = null// null for System property to be used
1033         private int maxErrorsCount;
1034
1035         public JAXBContextBuilder() {};
1036
1037         public JAXBContextBuilder(JAXBContextImpl baseImpl) {
1038             this.supressAccessorWarnings = baseImpl.supressAccessorWarnings;
1039             this.retainPropertyInfo = baseImpl.retainPropertyInfo;
1040             this.defaultNsUri = baseImpl.defaultNsUri;
1041             this.annotationReader = baseImpl.annotationReader;
1042             this.subclassReplacements = baseImpl.subclassReplacements;
1043             this.c14nSupport = baseImpl.c14nSupport;
1044             this.classes = baseImpl.classes;
1045             this.typeRefs = baseImpl.bridges.keySet();
1046             this.xmlAccessorFactorySupport = baseImpl.xmlAccessorFactorySupport;
1047             this.allNillable = baseImpl.allNillable;
1048             this.disableSecurityProcessing = baseImpl.disableSecurityProcessing;
1049             this.backupWithParentNamespace = baseImpl.backupWithParentNamespace;
1050             this.maxErrorsCount = baseImpl.maxErrorsCount;
1051         }
1052
1053         public JAXBContextBuilder setRetainPropertyInfo(boolean val) {
1054             this.retainPropertyInfo = val;
1055             return this;
1056         }
1057
1058         public JAXBContextBuilder setSupressAccessorWarnings(boolean val) {
1059             this.supressAccessorWarnings = val;
1060             return this;
1061         }
1062
1063         public JAXBContextBuilder setC14NSupport(boolean val) {
1064             this.c14nSupport = val;
1065             return this;
1066         }
1067
1068         public JAXBContextBuilder setXmlAccessorFactorySupport(boolean val) {
1069             this.xmlAccessorFactorySupport = val;
1070             return this;
1071         }
1072
1073         public JAXBContextBuilder setDefaultNsUri(String val) {
1074             this.defaultNsUri = val;
1075             return this;
1076         }
1077
1078         public JAXBContextBuilder setAllNillable(boolean val) {
1079             this.allNillable = val;
1080             return this;
1081         }
1082
1083         public JAXBContextBuilder setClasses(Class[] val) {
1084             this.classes = val;
1085             return this;
1086         }
1087
1088         public JAXBContextBuilder setAnnotationReader(RuntimeAnnotationReader val) {
1089             this.annotationReader = val;
1090             return this;
1091         }
1092
1093         public JAXBContextBuilder setSubclassReplacements(Map<Class,Class> val) {
1094             this.subclassReplacements = val;
1095             return this;
1096         }
1097
1098         public JAXBContextBuilder setTypeRefs(Collection<TypeReference> val) {
1099             this.typeRefs = val;
1100             return this;
1101         }
1102
1103         public JAXBContextBuilder setImprovedXsiTypeHandling(boolean val) {
1104             this.improvedXsiTypeHandling = val;
1105             return this;
1106         }
1107
1108         public JAXBContextBuilder setDisableSecurityProcessing(boolean val) {
1109             this.disableSecurityProcessing = val;
1110             return this;
1111         }
1112
1113         public JAXBContextBuilder setBackupWithParentNamespace(Boolean backupWithParentNamespace) {
1114             this.backupWithParentNamespace = backupWithParentNamespace;
1115             return this;
1116         }
1117
1118         public JAXBContextBuilder setMaxErrorsCount(int maxErrorsCount) {
1119             this.maxErrorsCount = maxErrorsCount;
1120             return this;
1121         }
1122
1123         public JAXBContextImpl build() throws JAXBException {
1124
1125             // fool-proof
1126             if (this.defaultNsUri == null) {
1127                 this.defaultNsUri = "";
1128             }
1129
1130             if (this.subclassReplacements == null) {
1131                 this.subclassReplacements = Collections.emptyMap();
1132             }
1133
1134             if (this.annotationReader == null) {
1135                 this.annotationReader = new RuntimeInlineAnnotationReader();
1136             }
1137
1138             if (this.typeRefs == null) {
1139                 this.typeRefs = Collections.<TypeReference>emptyList();
1140             }
1141
1142             return new JAXBContextImpl(this);
1143         }
1144
1145     }
1146
1147 }
1148