Wed, 12 Jun 2013 14:47:09 +0100
8013021: Rebase 8005432 & 8003542 against the latest jdk8/jaxws
8003542: Improve processing of MTOM attachments
8005432: Update access to JAX-WS
Reviewed-by: mullan
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 */
26 package com.sun.xml.internal.bind.v2.runtime;
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;
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;
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;
123 /**
124 * This class provides the implementation of JAXBContext.
125 *
126 */
127 public final class JAXBContextImpl extends JAXBRIContext {
129 /**
130 * All the bridge classes.
131 */
132 private final Map<TypeReference,Bridge> bridges = new LinkedHashMap<TypeReference,Bridge>();
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;
142 /**
143 * Shared instance of {@link DocumentBuilder}.
144 * Lock before use. Lazily created.
145 */
146 private static DocumentBuilder db;
148 private final QNameMap<JaxBeanInfo> rootMap = new QNameMap<JaxBeanInfo>();
149 private final HashMap<QName,JaxBeanInfo> typeMap = new HashMap<QName,JaxBeanInfo>();
151 /**
152 * Map from JAXB-bound {@link Class} to its {@link JaxBeanInfo}.
153 */
154 private final Map<Class,JaxBeanInfo> beanInfoMap = new LinkedHashMap<Class,JaxBeanInfo>();
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>();
167 private final Map<Class/*scope*/,Map<QName,ElementBeanInfoImpl>> elements = new LinkedHashMap<Class, Map<QName, ElementBeanInfoImpl>>();
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 };
178 public final Pool<Unmarshaller> unmarshallerPool = new Pool.Impl<Unmarshaller>() {
179 protected @NotNull Unmarshaller create() {
180 return createUnmarshaller();
181 }
182 };
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();
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;
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;
203 /**
204 * true to reorder attributes lexicographically in preparation of the c14n support.
205 */
206 protected final boolean c14nSupport;
208 /**
209 * Flag that user has provided a custom AccessorFactory for JAXB to use
210 */
211 public final boolean xmlAccessorFactorySupport;
213 /**
214 * @see JAXBRIContext#TREAT_EVERYTHING_NILLABLE
215 */
216 public final boolean allNillable;
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;
223 /**
224 * Suppress reflection accessor warnings.
225 */
226 public final boolean supressAccessorWarnings;
228 /**
229 * Improved xsi type handling.
230 */
231 public final boolean improvedXsiTypeHandling;
233 /**
234 * Disable security processing.
235 */
236 public final boolean disableSecurityProcessing;
238 private WeakReference<RuntimeTypeInfoSet> typeInfoSetCache;
240 private @NotNull RuntimeAnnotationReader annotationReader;
242 private /*almost final*/ boolean hasSwaRef;
243 private final @NotNull Map<Class,Class> subclassReplacements;
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;
253 private Set<XmlNs> xmlNsSet = null;
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 }
264 private JAXBContextImpl(JAXBContextBuilder builder) throws JAXBException {
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;
278 Collection<TypeReference> typeRefs = builder.typeRefs;
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;
288 RuntimeTypeInfoSet typeSet = getTypeInfoSet();
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>());
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 }
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 }
309 for (RuntimeArrayInfo a : typeSet.arrays().values()) {
310 JaxBeanInfo<?> ai = getOrCreate(a);
311 for (QName qn : ai.getTypeNames())
312 typeMap.put( qn, ai );
313 }
315 for( Entry<Class, ? extends RuntimeClassInfo> e : typeSet.beans().entrySet() ) {
316 ClassBeanInfoImpl<?> bi = getOrCreate(e.getValue());
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 }
327 if(bi.isElement())
328 rootMap.put( e.getValue().getElementName(), bi );
330 for (QName qn : bi.getTypeNames())
331 typeMap.put( qn, bi );
332 }
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);
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 }
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));
355 getOrCreate(typeSet.getAnyTypeInfo());
357 // then link them all!
358 for (JaxBeanInfo bi : beanInfos.values())
359 bi.link(this);
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()) );
365 // build bridges
366 ReflectionNavigator nav = typeSet.getNavigator();
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);
373 // eventually compute the in-memory type
374 Class erasedType = nav.erasure(tr.type);
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 }
384 if(a!=null) {
385 erasedType = nav.erasure(a.defaultType);
386 }
388 Name name = nameBuilder.createElementName(tr.tagName);
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);
396 if(a!=null)
397 bridge = new BridgeAdapter(bridge,a.adapterType);
399 bridges.put(tr,bridge);
400 }
402 this.nameList = nameBuilder.conclude();
404 for (JaxBeanInfo bi : beanInfos.values())
405 bi.wrapUp();
407 // no use for them now
408 nameBuilder = null;
409 beanInfos = null;
410 }
412 /**
413 * True if this JAXBContext has {@link XmlAttachmentRef}.
414 */
415 public boolean hasSwaRef() {
416 return hasSwaRef;
417 }
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 }
428 /**
429 * Creates a {@link RuntimeTypeInfoSet}.
430 */
431 public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException {
433 // check cache
434 if(typeInfoSetCache!=null) {
435 RuntimeTypeInfoSet r = typeInfoSetCache.get();
436 if(r!=null)
437 return r;
438 }
440 final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri);
442 IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder();
443 builder.setErrorHandler(errorHandler);
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 }
453 this.hasSwaRef |= builder.hasSwaRef;
454 RuntimeTypeInfoSet r = builder.link();
456 errorHandler.check();
457 assert r!=null : "if no error was reported, the link must be a success";
459 typeInfoSetCache = new WeakReference<RuntimeTypeInfoSet>(r);
461 return r;
462 }
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 }
480 private ElementBeanInfoImpl getOrCreate( RuntimeElementInfo rei ) {
481 JaxBeanInfo bi = beanInfos.get(rei);
482 if(bi!=null) return (ElementBeanInfoImpl)bi;
484 // all elements share the same type, so we can't register them to beanInfoMap
485 return new ElementBeanInfoImpl(this, rei);
486 }
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 }
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 }
504 protected JaxBeanInfo getOrCreate( RuntimeArrayInfo ai ) {
505 JaxBeanInfo abi = beanInfos.get(ai);
506 if(abi!=null) return abi;
508 abi = new ArrayBeanInfoImpl(this,ai);
510 beanInfoMap.put(ai.getType(),abi);
511 return abi;
512 }
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 }
536 throw new IllegalArgumentException();
537 }
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 }
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 }
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 }
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 }
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;
625 return beanInfo.getLoader(this,true);
626 }
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 }
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 }
656 String nearest = EditDistance.findNearest(name.toString(), all);
658 if(EditDistance.editDistance(nearest,name.toString())>10)
659 return null; // too far apart.
661 return nearest;
662 }
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 }
676 /**
677 * Cache of UTF-8 encoded local names to improve the performance for the marshalling.
678 */
679 private Encoded[] utf8nameTable;
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 }
694 public int getNumberOfLocalNames() {
695 return nameList.localNames.length;
696 }
698 public int getNumberOfElementNames() {
699 return nameList.numberOfElementNames;
700 }
702 public int getNumberOfAttributeNames() {
703 return nameList.numberOfAttributeNames;
704 }
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 }
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 }
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 }
760 public MarshallerImpl createMarshaller() {
761 return new MarshallerImpl(this,null);
762 }
764 public UnmarshallerImpl createUnmarshaller() {
765 return new UnmarshallerImpl(this,null);
766 }
768 public Validator createValidator() {
769 throw new UnsupportedOperationException(Messages.NOT_IMPLEMENTED_IN_2_0.format());
770 }
772 @Override
773 public JAXBIntrospector createJAXBIntrospector() {
774 return new JAXBIntrospector() {
775 public boolean isElement(Object object) {
776 return getElementName(object)!=null;
777 }
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 }
789 private NonElement<Type,Class> getXmlType(RuntimeTypeInfoSet tis, TypeReference tr) {
790 if(tr==null)
791 throw new IllegalArgumentException();
793 XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
794 XmlList xl = tr.get(XmlList.class);
796 Ref<Type,Class> ref = new Ref<Type,Class>(annotationReader, tis.getNavigator(), tr.type, xjta, xl );
798 return tis.getTypeInfo(ref);
799 }
801 @Override
802 public void generateEpisode(Result output) {
803 if(output==null)
804 throw new IllegalArgumentException();
805 createSchemaGenerator().writeEpisodeFile(ResultFactory.createSerializer(output));
806 }
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());
814 final SAXParseException[] e = new SAXParseException[1];
815 final SAXParseException[] w = new SAXParseException[1];
817 createSchemaGenerator().write(outputResolver, new ErrorListener() {
818 public void error(SAXParseException exception) {
819 e[0] = exception;
820 }
822 public void fatalError(SAXParseException exception) {
823 e[0] = exception;
824 }
826 public void warning(SAXParseException exception) {
827 w[0] = exception;
828 }
830 public void info(SAXParseException exception) {}
831 });
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 }
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 }
854 XmlSchemaGenerator<Type,Class,Field,Method> xsdgen =
855 new XmlSchemaGenerator<Type,Class,Field,Method>(tis.getNavigator(),tis);
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 }
869 for (TypeReference tr : bridges.keySet()) {
870 if(rootTagNames.contains(tr.tagName))
871 continue;
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 }
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 }
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 }
905 @Override
906 public Binder<Node> createBinder() {
907 return new BinderImpl<Node>(this,new DOMScanner());
908 }
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 }
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 }
924 public Bridge createBridge(TypeReference ref) {
925 return bridges.get(ref);
926 }
928 public @NotNull BridgeContext createBridgeContext() {
929 return new BridgeContextImpl(this);
930 }
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");
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 }
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 }
960 public List<String> getKnownNamespaceURIs() {
961 return Arrays.asList(nameList.namespaceURIs);
962 }
964 public String getBuildId() {
965 Package pkg = getClass().getPackage();
966 if(pkg==null) return null;
967 return pkg.getImplementationVersion();
968 }
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");
975 Set<String> names = new TreeSet<String>(); // sort them so that it's easy to read
977 for (Class key : beanInfoMap.keySet())
978 names.add(key.getName());
980 for(String name: names)
981 buf.append(" ").append(name).append('\n');
983 return buf.toString();
984 }
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;
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 }
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;
1022 JAXBContextBuilder builder = new JAXBContextBuilder(this);
1023 builder.setClasses(newList);
1024 return builder.build();
1025 }
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;
1032 return lhs.getNamespaceURI().compareTo(rhs.getNamespaceURI());
1033 }
1034 };
1036 public static class JAXBContextBuilder {
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;
1051 public JAXBContextBuilder() {};
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 }
1067 public JAXBContextBuilder setRetainPropertyInfo(boolean val) {
1068 this.retainPropertyInfo = val;
1069 return this;
1070 }
1072 public JAXBContextBuilder setSupressAccessorWarnings(boolean val) {
1073 this.supressAccessorWarnings = val;
1074 return this;
1075 }
1077 public JAXBContextBuilder setC14NSupport(boolean val) {
1078 this.c14nSupport = val;
1079 return this;
1080 }
1082 public JAXBContextBuilder setXmlAccessorFactorySupport(boolean val) {
1083 this.xmlAccessorFactorySupport = val;
1084 return this;
1085 }
1087 public JAXBContextBuilder setDefaultNsUri(String val) {
1088 this.defaultNsUri = val;
1089 return this;
1090 }
1092 public JAXBContextBuilder setAllNillable(boolean val) {
1093 this.allNillable = val;
1094 return this;
1095 }
1097 public JAXBContextBuilder setClasses(Class[] val) {
1098 this.classes = val;
1099 return this;
1100 }
1102 public JAXBContextBuilder setAnnotationReader(RuntimeAnnotationReader val) {
1103 this.annotationReader = val;
1104 return this;
1105 }
1107 public JAXBContextBuilder setSubclassReplacements(Map<Class,Class> val) {
1108 this.subclassReplacements = val;
1109 return this;
1110 }
1112 public JAXBContextBuilder setTypeRefs(Collection<TypeReference> val) {
1113 this.typeRefs = val;
1114 return this;
1115 }
1117 public JAXBContextBuilder setImprovedXsiTypeHandling(boolean val) {
1118 this.improvedXsiTypeHandling = val;
1119 return this;
1120 }
1122 public JAXBContextBuilder setDisableSecurityProcessing(boolean val) {
1123 this.disableSecurityProcessing = val;
1124 return this;
1125 }
1127 public JAXBContextImpl build() throws JAXBException {
1129 // fool-proof
1130 if (this.defaultNsUri == null) {
1131 this.defaultNsUri = "";
1132 }
1134 if (this.subclassReplacements == null) {
1135 this.subclassReplacements = Collections.emptyMap();
1136 }
1138 if (this.annotationReader == null) {
1139 this.annotationReader = new RuntimeInlineAnnotationReader();
1140 }
1142 if (this.typeRefs == null) {
1143 this.typeRefs = Collections.<TypeReference>emptyList();
1144 }
1146 return new JAXBContextImpl(this);
1147 }
1149 }
1151 }