325N/A/*
325N/A * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.xml.internal.bind.v2.runtime;
325N/A
325N/Aimport java.io.IOException;
325N/Aimport java.lang.ref.WeakReference;
325N/Aimport java.lang.reflect.Field;
325N/Aimport java.lang.reflect.Method;
325N/Aimport java.lang.reflect.Type;
325N/Aimport java.util.Arrays;
325N/Aimport java.util.Collection;
325N/Aimport java.util.Collections;
325N/Aimport java.util.Comparator;
325N/Aimport java.util.HashMap;
325N/Aimport java.util.HashSet;
325N/Aimport java.util.LinkedHashMap;
325N/Aimport java.util.List;
325N/Aimport java.util.Map;
325N/Aimport java.util.Map.Entry;
325N/Aimport java.util.Set;
325N/Aimport java.util.TreeSet;
325N/Aimport javax.xml.bind.Binder;
325N/Aimport javax.xml.bind.JAXBContext;
325N/Aimport javax.xml.bind.JAXBElement;
325N/Aimport javax.xml.bind.JAXBException;
325N/Aimport javax.xml.bind.JAXBIntrospector;
325N/Aimport javax.xml.bind.Marshaller;
325N/Aimport javax.xml.bind.SchemaOutputResolver;
325N/Aimport javax.xml.bind.Unmarshaller;
325N/Aimport javax.xml.bind.Validator;
325N/Aimport javax.xml.bind.annotation.XmlAttachmentRef;
325N/Aimport javax.xml.bind.annotation.XmlList;
325N/Aimport javax.xml.bind.annotation.XmlNs;
325N/Aimport javax.xml.bind.annotation.XmlSchema;
325N/Aimport javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
325N/Aimport javax.xml.namespace.QName;
325N/Aimport javax.xml.parsers.DocumentBuilder;
325N/Aimport javax.xml.parsers.DocumentBuilderFactory;
325N/Aimport javax.xml.parsers.FactoryConfigurationError;
325N/Aimport javax.xml.parsers.ParserConfigurationException;
325N/Aimport javax.xml.transform.Result;
325N/Aimport javax.xml.transform.Transformer;
325N/Aimport javax.xml.transform.TransformerConfigurationException;
325N/Aimport javax.xml.transform.TransformerFactory;
325N/Aimport javax.xml.transform.sax.SAXResult;
325N/Aimport javax.xml.transform.sax.SAXTransformerFactory;
325N/Aimport javax.xml.transform.sax.TransformerHandler;
325N/A
325N/Aimport com.sun.istack.internal.NotNull;
325N/Aimport com.sun.istack.internal.Pool;
325N/Aimport com.sun.xml.internal.bind.api.AccessorException;
325N/Aimport com.sun.xml.internal.bind.api.Bridge;
325N/Aimport com.sun.xml.internal.bind.api.BridgeContext;
325N/Aimport com.sun.xml.internal.bind.api.CompositeStructure;
325N/Aimport com.sun.xml.internal.bind.api.ErrorListener;
325N/Aimport com.sun.xml.internal.bind.api.JAXBRIContext;
325N/Aimport com.sun.xml.internal.bind.api.RawAccessor;
325N/Aimport com.sun.xml.internal.bind.api.TypeReference;
325N/Aimport com.sun.xml.internal.bind.unmarshaller.DOMScanner;
325N/Aimport com.sun.xml.internal.bind.util.Which;
325N/Aimport com.sun.xml.internal.bind.v2.WellKnownNamespace;
325N/Aimport com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader;
325N/Aimport com.sun.xml.internal.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.Adapter;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.NonElement;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.Ref;
325N/Aimport com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl;
325N/Aimport com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder;
325N/Aimport com.sun.xml.internal.bind.v2.model.nav.Navigator;
325N/Aimport com.sun.xml.internal.bind.v2.model.nav.ReflectionNavigator;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeArrayInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeBuiltinLeafInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeEnumLeafInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeLeafInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfo;
325N/Aimport com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfoSet;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.output.Encoded;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.property.Property;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.unmarshaller.TagName;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
325N/Aimport com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
325N/Aimport com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator;
325N/Aimport com.sun.xml.internal.bind.v2.util.EditDistance;
325N/Aimport com.sun.xml.internal.bind.v2.util.QNameMap;
325N/Aimport com.sun.xml.internal.txw2.output.ResultFactory;
325N/A
325N/Aimport org.w3c.dom.Document;
325N/Aimport org.w3c.dom.Element;
325N/Aimport org.w3c.dom.Node;
325N/Aimport org.xml.sax.SAXException;
325N/Aimport org.xml.sax.SAXParseException;
325N/Aimport org.xml.sax.helpers.DefaultHandler;
325N/A
325N/A/**
325N/A * This class provides the implementation of JAXBContext.
325N/A *
325N/A */
325N/Apublic final class JAXBContextImpl extends JAXBRIContext {
325N/A
325N/A /**
325N/A * All the bridge classes.
325N/A */
325N/A private final Map<TypeReference,Bridge> bridges = new LinkedHashMap<TypeReference,Bridge>();
325N/A
325N/A /**
325N/A * Shared instance of {@link TransformerFactory}.
325N/A * Lock before use, because a {@link TransformerFactory} is not thread-safe
325N/A * whereas {@link JAXBContextImpl} is.
325N/A * Lazily created.
325N/A */
325N/A private volatile static SAXTransformerFactory tf;
325N/A
325N/A /**
325N/A * Shared instance of {@link DocumentBuilder}.
325N/A * Lock before use. Lazily created.
325N/A */
325N/A private static DocumentBuilder db;
325N/A
325N/A private final QNameMap<JaxBeanInfo> rootMap = new QNameMap<JaxBeanInfo>();
325N/A private final HashMap<QName,JaxBeanInfo> typeMap = new HashMap<QName,JaxBeanInfo>();
325N/A
325N/A /**
325N/A * Map from JAXB-bound {@link Class} to its {@link JaxBeanInfo}.
325N/A */
325N/A private final Map<Class,JaxBeanInfo> beanInfoMap = new LinkedHashMap<Class,JaxBeanInfo>();
325N/A
325N/A /**
325N/A * All created {@link JaxBeanInfo}s.
325N/A * Updated from each {@link JaxBeanInfo}s constructors to avoid infinite recursion
325N/A * for a cyclic reference.
325N/A *
325N/A * <p>
325N/A * This map is only used while the {@link JAXBContextImpl} is built and set to null
325N/A * to avoid keeping references too long.
325N/A */
325N/A protected Map<RuntimeTypeInfo,JaxBeanInfo> beanInfos = new LinkedHashMap<RuntimeTypeInfo, JaxBeanInfo>();
325N/A
325N/A private final Map<Class/*scope*/,Map<QName,ElementBeanInfoImpl>> elements = new LinkedHashMap<Class, Map<QName, ElementBeanInfoImpl>>();
325N/A
325N/A /**
325N/A * Pool of {@link Marshaller}s.
325N/A */
325N/A public final Pool<Marshaller> marshallerPool = new Pool.Impl<Marshaller>() {
325N/A protected @NotNull Marshaller create() {
325N/A return createMarshaller();
325N/A }
325N/A };
325N/A
325N/A public final Pool<Unmarshaller> unmarshallerPool = new Pool.Impl<Unmarshaller>() {
325N/A protected @NotNull Unmarshaller create() {
325N/A return createUnmarshaller();
325N/A }
325N/A };
325N/A
325N/A /**
325N/A * Used to assign indices to known names in this grammar.
325N/A * Reset to null once the build phase is completed.
325N/A */
325N/A public NameBuilder nameBuilder = new NameBuilder();
325N/A
325N/A /**
325N/A * Keeps the list of known names.
325N/A * This field is set once the build pahse is completed.
325N/A */
325N/A public final NameList nameList;
325N/A
325N/A /**
325N/A * Input to the JAXBContext.newInstance, so that we can recreate
325N/A * {@link RuntimeTypeInfoSet} whenever we need.
325N/A */
325N/A private final String defaultNsUri;
325N/A private final Class[] classes;
325N/A
325N/A /**
325N/A * true to reorder attributes lexicographically in preparation of the c14n support.
325N/A */
325N/A protected final boolean c14nSupport;
325N/A
325N/A /**
325N/A * Flag that user has provided a custom AccessorFactory for JAXB to use
325N/A */
325N/A public final boolean xmlAccessorFactorySupport;
325N/A
325N/A /**
325N/A * @see JAXBRIContext#TREAT_EVERYTHING_NILLABLE
325N/A */
325N/A public final boolean allNillable;
325N/A
325N/A /**
325N/A * Store properties, so that they can be recovered in the run (is here because of JSON encoding of Jersey).
325N/A */
325N/A public final boolean retainPropertyInfo;
325N/A
325N/A /**
325N/A * Supress reflection accessor warnings.
325N/A */
325N/A public final boolean supressAccessorWarnings;
325N/A
325N/A /**
325N/A * Improved xsi type handling.
325N/A */
325N/A public final boolean improvedXsiTypeHandling;
325N/A
325N/A private WeakReference<RuntimeTypeInfoSet> typeInfoSetCache;
325N/A
325N/A private @NotNull RuntimeAnnotationReader annotationReader;
325N/A
325N/A private /*almost final*/ boolean hasSwaRef;
325N/A private final @NotNull Map<Class,Class> subclassReplacements;
325N/A
325N/A /**
325N/A * If true, we aim for faster {@link JAXBContext} instanciation performance,
325N/A * instead of going after efficient sustained unmarshalling/marshalling performance.
325N/A *
325N/A * @since 2.0.4
325N/A */
325N/A public final boolean fastBoot;
325N/A
325N/A private Set<XmlNs> xmlNsSet = null;
325N/A
325N/A /**
325N/A * Returns declared XmlNs annotations (from package-level annotation XmlSchema
325N/A *
325N/A * @return set of all present XmlNs annotations
325N/A */
325N/A public Set<XmlNs> getXmlNsSet() {
325N/A return xmlNsSet;
325N/A }
325N/A
325N/A private JAXBContextImpl(JAXBContextBuilder builder) throws JAXBException {
325N/A
325N/A this.defaultNsUri = builder.defaultNsUri;
325N/A this.retainPropertyInfo = builder.retainPropertyInfo;
325N/A this.annotationReader = builder.annotationReader;
325N/A this.subclassReplacements = builder.subclassReplacements;
325N/A this.c14nSupport = builder.c14nSupport;
325N/A this.classes = builder.classes;
325N/A this.xmlAccessorFactorySupport = builder.xmlAccessorFactorySupport;
325N/A this.allNillable = builder.allNillable;
325N/A this.supressAccessorWarnings = builder.supressAccessorWarnings;
325N/A this.improvedXsiTypeHandling = builder.improvedXsiTypeHandling;
325N/A
325N/A Collection<TypeReference> typeRefs = builder.typeRefs;
325N/A
325N/A boolean fastB;
325N/A try {
325N/A fastB = Boolean.getBoolean(JAXBContextImpl.class.getName()+".fastBoot");
325N/A } catch (SecurityException e) {
325N/A fastB = false;
325N/A }
325N/A this.fastBoot = fastB;
325N/A
325N/A System.arraycopy(classes,0,this.classes,0,classes.length);
325N/A
325N/A RuntimeTypeInfoSet typeSet = getTypeInfoSet();
325N/A
325N/A // at least prepare the empty table so that we don't have to check for null later
325N/A elements.put(null,new LinkedHashMap<QName, ElementBeanInfoImpl>());
325N/A
325N/A // recognize leaf bean infos
325N/A for( RuntimeBuiltinLeafInfo leaf : RuntimeBuiltinLeafInfoImpl.builtinBeanInfos ) {
325N/A LeafBeanInfoImpl<?> bi = new LeafBeanInfoImpl(this,leaf);
325N/A beanInfoMap.put(leaf.getClazz(),bi);
325N/A for( QName t : bi.getTypeNames() )
325N/A typeMap.put(t,bi);
325N/A }
325N/A
325N/A for (RuntimeEnumLeafInfo e : typeSet.enums().values()) {
325N/A JaxBeanInfo<?> bi = getOrCreate(e);
325N/A for (QName qn : bi.getTypeNames())
325N/A typeMap.put( qn, bi );
325N/A if(e.isElement())
325N/A rootMap.put( e.getElementName(), bi );
325N/A }
325N/A
325N/A for (RuntimeArrayInfo a : typeSet.arrays().values()) {
325N/A JaxBeanInfo<?> ai = getOrCreate(a);
325N/A for (QName qn : ai.getTypeNames())
325N/A typeMap.put( qn, ai );
325N/A }
325N/A
325N/A for( Entry<Class, ? extends RuntimeClassInfo> e : typeSet.beans().entrySet() ) {
325N/A ClassBeanInfoImpl<?> bi = getOrCreate(e.getValue());
325N/A
325N/A XmlSchema xs = this.annotationReader.getPackageAnnotation(XmlSchema.class, e.getKey(), null);
325N/A if(xs != null) {
325N/A if(xs.xmlns() != null && xs.xmlns().length > 0) {
325N/A if(xmlNsSet == null)
325N/A xmlNsSet = new HashSet<XmlNs>();
325N/A xmlNsSet.addAll(Arrays.asList(xs.xmlns()));
325N/A }
325N/A }
325N/A
325N/A if(bi.isElement())
325N/A rootMap.put( e.getValue().getElementName(), bi );
325N/A
325N/A for (QName qn : bi.getTypeNames())
325N/A typeMap.put( qn, bi );
325N/A }
325N/A
325N/A // fill in element mappings
325N/A for( RuntimeElementInfo n : typeSet.getAllElements() ) {
325N/A ElementBeanInfoImpl bi = getOrCreate(n);
325N/A if(n.getScope()==null)
325N/A rootMap.put(n.getElementName(),bi);
325N/A
325N/A RuntimeClassInfo scope = n.getScope();
325N/A Class scopeClazz = scope==null?null:scope.getClazz();
325N/A Map<QName,ElementBeanInfoImpl> m = elements.get(scopeClazz);
325N/A if(m==null) {
325N/A m = new LinkedHashMap<QName, ElementBeanInfoImpl>();
325N/A elements.put(scopeClazz,m);
325N/A }
325N/A m.put(n.getElementName(),bi);
325N/A }
325N/A
325N/A // this one is so that we can handle plain JAXBElements.
325N/A beanInfoMap.put(JAXBElement.class,new ElementBeanInfoImpl(this));
325N/A // another special BeanInfoImpl just for marshalling
325N/A beanInfoMap.put(CompositeStructure.class,new CompositeStructureBeanInfo(this));
325N/A
325N/A getOrCreate(typeSet.getAnyTypeInfo());
325N/A
325N/A // then link them all!
325N/A for (JaxBeanInfo bi : beanInfos.values())
325N/A bi.link(this);
325N/A
325N/A // register primitives for boxed types just to make GrammarInfo fool-proof
325N/A for( Map.Entry<Class,Class> e : RuntimeUtil.primitiveToBox.entrySet() )
325N/A beanInfoMap.put( e.getKey(), beanInfoMap.get(e.getValue()) );
325N/A
325N/A // build bridges
325N/A ReflectionNavigator nav = typeSet.getNavigator();
325N/A
325N/A for (TypeReference tr : typeRefs) {
325N/A XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
325N/A Adapter<Type,Class> a=null;
325N/A XmlList xl = tr.get(XmlList.class);
325N/A
325N/A // eventually compute the in-memory type
325N/A Class erasedType = nav.erasure(tr.type);
325N/A
325N/A if(xjta!=null) {
325N/A a = new Adapter<Type,Class>(xjta.value(),nav);
325N/A }
325N/A if(tr.get(XmlAttachmentRef.class)!=null) {
325N/A a = new Adapter<Type,Class>(SwaRefAdapter.class,nav);
325N/A hasSwaRef = true;
325N/A }
325N/A
325N/A if(a!=null) {
325N/A erasedType = nav.erasure(a.defaultType);
325N/A }
325N/A
325N/A Name name = nameBuilder.createElementName(tr.tagName);
325N/A
325N/A InternalBridge bridge;
325N/A if(xl==null)
325N/A bridge = new BridgeImpl(this, name,getBeanInfo(erasedType,true),tr);
325N/A else
325N/A bridge = new BridgeImpl(this, name,new ValueListBeanInfoImpl(this,erasedType),tr);
325N/A
325N/A if(a!=null)
325N/A bridge = new BridgeAdapter(bridge,a.adapterType);
325N/A
325N/A bridges.put(tr,bridge);
325N/A }
325N/A
325N/A this.nameList = nameBuilder.conclude();
325N/A
325N/A for (JaxBeanInfo bi : beanInfos.values())
325N/A bi.wrapUp();
325N/A
325N/A // no use for them now
325N/A nameBuilder = null;
325N/A beanInfos = null;
325N/A }
325N/A
325N/A /**
325N/A * True if this JAXBContext has {@link XmlAttachmentRef}.
325N/A */
325N/A public boolean hasSwaRef() {
325N/A return hasSwaRef;
325N/A }
325N/A
325N/A public RuntimeTypeInfoSet getRuntimeTypeInfoSet() {
325N/A try {
325N/A return getTypeInfoSet();
325N/A } catch (IllegalAnnotationsException e) {
325N/A // impossible, once the model is constructred
325N/A throw new AssertionError(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Creates a {@link RuntimeTypeInfoSet}.
325N/A */
325N/A public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException {
325N/A
325N/A // check cache
325N/A if(typeInfoSetCache!=null) {
325N/A RuntimeTypeInfoSet r = typeInfoSetCache.get();
325N/A if(r!=null)
325N/A return r;
325N/A }
325N/A
325N/A final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri);
325N/A
325N/A IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder();
325N/A builder.setErrorHandler(errorHandler);
325N/A
325N/A for( Class c : classes ) {
325N/A if(c==CompositeStructure.class)
325N/A // CompositeStructure doesn't have TypeInfo, so skip it.
325N/A // We'll add JaxBeanInfo for this later automatically
325N/A continue;
325N/A builder.getTypeInfo(new Ref<Type,Class>(c));
325N/A }
325N/A
325N/A this.hasSwaRef |= builder.hasSwaRef;
325N/A RuntimeTypeInfoSet r = builder.link();
325N/A
325N/A errorHandler.check();
325N/A assert r!=null : "if no error was reported, the link must be a success";
325N/A
325N/A typeInfoSetCache = new WeakReference<RuntimeTypeInfoSet>(r);
325N/A
325N/A return r;
325N/A }
325N/A
325N/A
325N/A public ElementBeanInfoImpl getElement(Class scope, QName name) {
325N/A Map<QName,ElementBeanInfoImpl> m = elements.get(scope);
325N/A if(m!=null) {
325N/A ElementBeanInfoImpl bi = m.get(name);
325N/A if(bi!=null)
325N/A return bi;
325N/A }
325N/A m = elements.get(null);
325N/A return m.get(name);
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A private ElementBeanInfoImpl getOrCreate( RuntimeElementInfo rei ) {
325N/A JaxBeanInfo bi = beanInfos.get(rei);
325N/A if(bi!=null) return (ElementBeanInfoImpl)bi;
325N/A
325N/A // all elements share the same type, so we can't register them to beanInfoMap
325N/A return new ElementBeanInfoImpl(this, rei);
325N/A }
325N/A
325N/A protected JaxBeanInfo getOrCreate( RuntimeEnumLeafInfo eli ) {
325N/A JaxBeanInfo bi = beanInfos.get(eli);
325N/A if(bi!=null) return bi;
325N/A bi = new LeafBeanInfoImpl(this,eli);
325N/A beanInfoMap.put(bi.jaxbType,bi);
325N/A return bi;
325N/A }
325N/A
325N/A protected ClassBeanInfoImpl getOrCreate( RuntimeClassInfo ci ) {
325N/A ClassBeanInfoImpl bi = (ClassBeanInfoImpl)beanInfos.get(ci);
325N/A if(bi!=null) return bi;
325N/A bi = new ClassBeanInfoImpl(this,ci);
325N/A beanInfoMap.put(bi.jaxbType,bi);
325N/A return bi;
325N/A }
325N/A
325N/A protected JaxBeanInfo getOrCreate( RuntimeArrayInfo ai ) {
325N/A JaxBeanInfo abi = beanInfos.get(ai);
325N/A if(abi!=null) return abi;
325N/A
325N/A abi = new ArrayBeanInfoImpl(this,ai);
325N/A
325N/A beanInfoMap.put(ai.getType(),abi);
325N/A return abi;
325N/A }
325N/A
325N/A public JaxBeanInfo getOrCreate(RuntimeTypeInfo e) {
325N/A if(e instanceof RuntimeElementInfo)
325N/A return getOrCreate((RuntimeElementInfo)e);
325N/A if(e instanceof RuntimeClassInfo)
325N/A return getOrCreate((RuntimeClassInfo)e);
325N/A if(e instanceof RuntimeLeafInfo) {
325N/A JaxBeanInfo bi = beanInfos.get(e); // must have been created
325N/A assert bi!=null;
325N/A return bi;
325N/A }
325N/A if(e instanceof RuntimeArrayInfo)
325N/A return getOrCreate((RuntimeArrayInfo)e);
325N/A if(e.getType()==Object.class) {
325N/A // anyType
325N/A JaxBeanInfo bi = beanInfoMap.get(Object.class);
325N/A if(bi==null) {
325N/A bi = new AnyTypeBeanInfo(this,e);
325N/A beanInfoMap.put(Object.class,bi);
325N/A }
325N/A return bi;
325N/A }
325N/A
325N/A throw new IllegalArgumentException();
325N/A }
325N/A
325N/A /**
325N/A * Gets the {@link JaxBeanInfo} object that can handle
325N/A * the given JAXB-bound object.
325N/A *
325N/A * <p>
325N/A * This method traverses the base classes of the given object.
325N/A *
325N/A * @return null
325N/A * if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>.
325N/A */
325N/A public final JaxBeanInfo getBeanInfo(Object o) {
325N/A // don't allow xs:anyType beanInfo to handle all the unbound objects
325N/A for( Class c=o.getClass(); c!=Object.class; c=c.getSuperclass()) {
325N/A JaxBeanInfo bi = beanInfoMap.get(c);
325N/A if(bi!=null) return bi;
325N/A }
325N/A if(o instanceof Element)
325N/A return beanInfoMap.get(Object.class); // return the BeanInfo for xs:anyType
325N/A for( Class c : o.getClass().getInterfaces()) {
325N/A JaxBeanInfo bi = beanInfoMap.get(c);
325N/A if(bi!=null) return bi;
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * Gets the {@link JaxBeanInfo} object that can handle
325N/A * the given JAXB-bound object.
325N/A *
325N/A * @param fatal
325N/A * if true, the failure to look up will throw an exception.
325N/A * Otherwise it will just return null.
325N/A */
325N/A public final JaxBeanInfo getBeanInfo(Object o,boolean fatal) throws JAXBException {
325N/A JaxBeanInfo bi = getBeanInfo(o);
325N/A if(bi!=null) return bi;
325N/A if(fatal) {
325N/A if(o instanceof Document)
325N/A throw new JAXBException(Messages.ELEMENT_NEEDED_BUT_FOUND_DOCUMENT.format(o.getClass()));
325N/A throw new JAXBException(Messages.UNKNOWN_CLASS.format(o.getClass()));
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * Gets the {@link JaxBeanInfo} object that can handle
325N/A * the given JAXB-bound class.
325N/A *
325N/A * <p>
325N/A * This method doesn't look for base classes.
325N/A *
325N/A * @return null
325N/A * if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>.
325N/A */
325N/A public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) {
325N/A return (JaxBeanInfo<T>)beanInfoMap.get(clazz);
325N/A }
325N/A
325N/A /**
325N/A * Gets the {@link JaxBeanInfo} object that can handle
325N/A * the given JAXB-bound class.
325N/A *
325N/A * @param fatal
325N/A * if true, the failure to look up will throw an exception.
325N/A * Otherwise it will just return null.
325N/A */
325N/A public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz,boolean fatal) throws JAXBException {
325N/A JaxBeanInfo<T> bi = getBeanInfo(clazz);
325N/A if(bi!=null) return bi;
325N/A if(fatal)
325N/A throw new JAXBException(clazz.getName()+" is not known to this context");
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * Based on the tag name, determine what object to unmarshal,
325N/A * and then set a new object and its loader to the current unmarshaller state.
325N/A *
325N/A * @return
325N/A * null if the given name pair is not recognized.
325N/A */
325N/A public final Loader selectRootLoader( UnmarshallingContext.State state, TagName tag ) {
325N/A JaxBeanInfo beanInfo = rootMap.get(tag.uri,tag.local);
325N/A if(beanInfo==null)
325N/A return null;
325N/A
325N/A return beanInfo.getLoader(this,true);
325N/A }
325N/A
325N/A /**
325N/A * Gets the {@link JaxBeanInfo} for the given named XML Schema type.
325N/A *
325N/A * @return
325N/A * null if the type name is not recognized. For schema
325N/A * languages other than XML Schema, this method always
325N/A * returns null.
325N/A */
325N/A public JaxBeanInfo getGlobalType(QName name) {
325N/A return typeMap.get(name);
325N/A }
325N/A
325N/A /**
325N/A * Finds a type name that this context recognizes which is
325N/A * "closest" to the given type name.
325N/A *
325N/A * <p>
325N/A * This method is used for error recovery.
325N/A */
325N/A public String getNearestTypeName(QName name) {
325N/A String[] all = new String[typeMap.size()];
325N/A int i=0;
325N/A for (QName qn : typeMap.keySet()) {
325N/A if(qn.getLocalPart().equals(name.getLocalPart()))
325N/A return qn.toString(); // probably a match, as people often gets confused about namespace.
325N/A all[i++] = qn.toString();
325N/A }
325N/A
325N/A String nearest = EditDistance.findNearest(name.toString(), all);
325N/A
325N/A if(EditDistance.editDistance(nearest,name.toString())>10)
325N/A return null; // too far apart.
325N/A
325N/A return nearest;
325N/A }
325N/A
325N/A /**
325N/A * Returns the set of valid root tag names.
325N/A * For diagnostic use.
325N/A */
325N/A public Set<QName> getValidRootNames() {
325N/A Set<QName> r = new TreeSet<QName>(QNAME_COMPARATOR);
325N/A for (QNameMap.Entry e : rootMap.entrySet()) {
325N/A r.add(e.createQName());
325N/A }
325N/A return r;
325N/A }
325N/A
325N/A /**
325N/A * Cache of UTF-8 encoded local names to improve the performance for the marshalling.
325N/A */
325N/A private Encoded[] utf8nameTable;
325N/A
325N/A public synchronized Encoded[] getUTF8NameTable() {
325N/A if(utf8nameTable==null) {
325N/A Encoded[] x = new Encoded[nameList.localNames.length];
325N/A for( int i=0; i<x.length; i++ ) {
325N/A Encoded e = new Encoded(nameList.localNames[i]);
325N/A e.compact();
325N/A x[i] = e;
325N/A }
325N/A utf8nameTable = x;
325N/A }
325N/A return utf8nameTable;
325N/A }
325N/A
325N/A public int getNumberOfLocalNames() {
325N/A return nameList.localNames.length;
325N/A }
325N/A
325N/A public int getNumberOfElementNames() {
325N/A return nameList.numberOfElementNames;
325N/A }
325N/A
325N/A public int getNumberOfAttributeNames() {
325N/A return nameList.numberOfAttributeNames;
325N/A }
325N/A
325N/A /**
325N/A * Creates a new identity transformer.
325N/A */
325N/A static Transformer createTransformer() {
325N/A try {
325N/A if (tf==null) {
325N/A synchronized(JAXBContextImpl.class) {
325N/A if (tf==null) {
325N/A tf = (SAXTransformerFactory)TransformerFactory.newInstance();
325N/A }
325N/A }
325N/A }
325N/A return tf.newTransformer();
325N/A } catch (TransformerConfigurationException e) {
325N/A throw new Error(e); // impossible
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Creates a new identity transformer.
325N/A */
325N/A public static TransformerHandler createTransformerHandler() {
325N/A try {
325N/A if (tf==null) {
325N/A synchronized(JAXBContextImpl.class) {
325N/A if (tf==null) {
325N/A tf = (SAXTransformerFactory)TransformerFactory.newInstance();
325N/A }
325N/A }
325N/A }
325N/A return tf.newTransformerHandler();
325N/A } catch (TransformerConfigurationException e) {
325N/A throw new Error(e); // impossible
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Creates a new DOM document.
325N/A */
325N/A static Document createDom() {
325N/A synchronized(JAXBContextImpl.class) {
325N/A if(db==null) {
325N/A try {
325N/A DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
325N/A dbf.setNamespaceAware(true);
325N/A db = dbf.newDocumentBuilder();
325N/A } catch (ParserConfigurationException e) {
325N/A // impossible
325N/A throw new FactoryConfigurationError(e);
325N/A }
325N/A }
325N/A return db.newDocument();
325N/A }
325N/A }
325N/A
325N/A public MarshallerImpl createMarshaller() {
325N/A return new MarshallerImpl(this,null);
325N/A }
325N/A
325N/A public UnmarshallerImpl createUnmarshaller() {
325N/A return new UnmarshallerImpl(this,null);
325N/A }
325N/A
325N/A public Validator createValidator() {
325N/A throw new UnsupportedOperationException(Messages.NOT_IMPLEMENTED_IN_2_0.format());
325N/A }
325N/A
325N/A @Override
325N/A public JAXBIntrospector createJAXBIntrospector() {
325N/A return new JAXBIntrospector() {
325N/A public boolean isElement(Object object) {
325N/A return getElementName(object)!=null;
325N/A }
325N/A
325N/A public QName getElementName(Object jaxbElement) {
325N/A try {
325N/A return JAXBContextImpl.this.getElementName(jaxbElement);
325N/A } catch (JAXBException e) {
325N/A return null;
325N/A }
325N/A }
325N/A };
325N/A }
325N/A
325N/A private NonElement<Type,Class> getXmlType(RuntimeTypeInfoSet tis, TypeReference tr) {
325N/A if(tr==null)
325N/A throw new IllegalArgumentException();
325N/A
325N/A XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class);
325N/A XmlList xl = tr.get(XmlList.class);
325N/A
325N/A Ref<Type,Class> ref = new Ref<Type,Class>(annotationReader, tis.getNavigator(), tr.type, xjta, xl );
325N/A
325N/A return tis.getTypeInfo(ref);
325N/A }
325N/A
325N/A @Override
325N/A public void generateEpisode(Result output) {
325N/A if(output==null)
325N/A throw new IllegalArgumentException();
325N/A createSchemaGenerator().writeEpisodeFile(ResultFactory.createSerializer(output));
325N/A }
325N/A
325N/A @Override
325N/A @SuppressWarnings("ThrowableInitCause")
325N/A public void generateSchema(SchemaOutputResolver outputResolver) throws IOException {
325N/A if(outputResolver==null)
325N/A throw new IOException(Messages.NULL_OUTPUT_RESOLVER.format());
325N/A
325N/A final SAXParseException[] e = new SAXParseException[1];
325N/A final SAXParseException[] w = new SAXParseException[1];
325N/A
325N/A createSchemaGenerator().write(outputResolver, new ErrorListener() {
325N/A public void error(SAXParseException exception) {
325N/A e[0] = exception;
325N/A }
325N/A
325N/A public void fatalError(SAXParseException exception) {
325N/A e[0] = exception;
325N/A }
325N/A
325N/A public void warning(SAXParseException exception) {
325N/A w[0] = exception;
325N/A }
325N/A
325N/A public void info(SAXParseException exception) {}
325N/A });
325N/A
325N/A if (e[0]!=null) {
325N/A IOException x = new IOException(Messages.FAILED_TO_GENERATE_SCHEMA.format());
325N/A x.initCause(e[0]);
325N/A throw x;
325N/A }
325N/A if (w[0]!=null) {
325N/A IOException x = new IOException(Messages.ERROR_PROCESSING_SCHEMA.format());
325N/A x.initCause(w[0]);
325N/A throw x;
325N/A }
325N/A }
325N/A
325N/A private XmlSchemaGenerator<Type,Class,Field,Method> createSchemaGenerator() {
325N/A RuntimeTypeInfoSet tis;
325N/A try {
325N/A tis = getTypeInfoSet();
325N/A } catch (IllegalAnnotationsException e) {
325N/A // this shouldn't happen because we've already
325N/A throw new AssertionError(e);
325N/A }
325N/A
325N/A XmlSchemaGenerator<Type,Class,Field,Method> xsdgen =
325N/A new XmlSchemaGenerator<Type,Class,Field,Method>(tis.getNavigator(),tis);
325N/A
325N/A // JAX-RPC uses Bridge objects that collide with
325N/A // @XmlRootElement.
325N/A // we will avoid collision here
325N/A Set<QName> rootTagNames = new HashSet<QName>();
325N/A for (RuntimeElementInfo ei : tis.getAllElements()) {
325N/A rootTagNames.add(ei.getElementName());
325N/A }
325N/A for (RuntimeClassInfo ci : tis.beans().values()) {
325N/A if(ci.isElement())
325N/A rootTagNames.add(ci.asElement().getElementName());
325N/A }
325N/A
325N/A for (TypeReference tr : bridges.keySet()) {
325N/A if(rootTagNames.contains(tr.tagName))
325N/A continue;
325N/A
325N/A if(tr.type==void.class || tr.type==Void.class) {
325N/A xsdgen.add(tr.tagName,false,null);
325N/A } else
325N/A if(tr.type==CompositeStructure.class) {
325N/A // this is a special class we introduced for JAX-WS that we *don't* want in the schema
325N/A } else {
325N/A NonElement<Type,Class> typeInfo = getXmlType(tis,tr);
325N/A xsdgen.add(tr.tagName, !Navigator.REFLECTION.isPrimitive(tr.type),typeInfo);
325N/A }
325N/A }
325N/A return xsdgen;
325N/A }
325N/A
325N/A public QName getTypeName(TypeReference tr) {
325N/A try {
325N/A NonElement<Type,Class> xt = getXmlType(getTypeInfoSet(),tr);
325N/A if(xt==null) throw new IllegalArgumentException();
325N/A return xt.getTypeName();
325N/A } catch (IllegalAnnotationsException e) {
325N/A // impossible given that JAXBRIContext has been successfully built in the first place
325N/A throw new AssertionError(e);
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Used for testing.
325N/A */
325N/A public SchemaOutputResolver createTestResolver() {
325N/A return new SchemaOutputResolver() {
325N/A public Result createOutput(String namespaceUri, String suggestedFileName) {
325N/A SAXResult r = new SAXResult(new DefaultHandler());
325N/A r.setSystemId(suggestedFileName);
325N/A return r;
325N/A }
325N/A };
325N/A }
325N/A
325N/A @Override
325N/A public <T> Binder<T> createBinder(Class<T> domType) {
325N/A if(domType==Node.class)
325N/A return (Binder<T>)createBinder();
325N/A else
325N/A return super.createBinder(domType);
325N/A }
325N/A
325N/A @Override
325N/A public Binder<Node> createBinder() {
325N/A return new BinderImpl<Node>(this,new DOMScanner());
325N/A }
325N/A
325N/A public QName getElementName(Object o) throws JAXBException {
325N/A JaxBeanInfo bi = getBeanInfo(o,true);
325N/A if(!bi.isElement())
325N/A return null;
325N/A return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
325N/A }
325N/A
325N/A public QName getElementName(Class o) throws JAXBException {
325N/A JaxBeanInfo bi = getBeanInfo(o,true);
325N/A if(!bi.isElement())
325N/A return null;
325N/A return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o));
325N/A }
325N/A
325N/A public Bridge createBridge(TypeReference ref) {
325N/A return bridges.get(ref);
325N/A }
325N/A
325N/A public @NotNull BridgeContext createBridgeContext() {
325N/A return new BridgeContextImpl(this);
325N/A }
325N/A
325N/A public RawAccessor getElementPropertyAccessor(Class wrapperBean, String nsUri, String localName) throws JAXBException {
325N/A JaxBeanInfo bi = getBeanInfo(wrapperBean,true);
325N/A if(!(bi instanceof ClassBeanInfoImpl))
325N/A throw new JAXBException(wrapperBean+" is not a bean");
325N/A
325N/A for( ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi; cb!=null; cb=cb.superClazz) {
325N/A for (Property p : cb.properties) {
325N/A final Accessor acc = p.getElementPropertyAccessor(nsUri,localName);
325N/A if(acc!=null)
325N/A return new RawAccessor() {
325N/A // Accessor.set/get are designed for unmarshaller/marshaller, and hence
325N/A // they go through an adapter behind the scene.
325N/A // this isn't desirable for JAX-WS, which essentially uses this method
325N/A // just as a reflection library. So use the "unadapted" version to
325N/A // achieve the desired semantics
325N/A public Object get(Object bean) throws AccessorException {
325N/A return acc.getUnadapted(bean);
325N/A }
325N/A
325N/A public void set(Object bean, Object value) throws AccessorException {
325N/A acc.setUnadapted(bean,value);
325N/A }
325N/A };
325N/A }
325N/A }
325N/A throw new JAXBException(new QName(nsUri,localName)+" is not a valid property on "+wrapperBean);
325N/A }
325N/A
325N/A public List<String> getKnownNamespaceURIs() {
325N/A return Arrays.asList(nameList.namespaceURIs);
325N/A }
325N/A
325N/A public String getBuildId() {
325N/A Package pkg = getClass().getPackage();
325N/A if(pkg==null) return null;
325N/A return pkg.getImplementationVersion();
325N/A }
325N/A
325N/A @Override
325N/A public String toString() {
325N/A StringBuilder buf = new StringBuilder(Which.which(getClass()) + " Build-Id: " + getBuildId());
325N/A buf.append("\nClasses known to this context:\n");
325N/A
325N/A Set<String> names = new TreeSet<String>(); // sort them so that it's easy to read
325N/A
325N/A for (Class key : beanInfoMap.keySet())
325N/A names.add(key.getName());
325N/A
325N/A for(String name: names)
325N/A buf.append(" ").append(name).append('\n');
325N/A
325N/A return buf.toString();
325N/A }
325N/A
325N/A /**
325N/A * Gets the value of the xmime:contentType attribute on the given object, or null
325N/A * if for some reason it couldn't be found, including any error.
325N/A */
325N/A public String getXMIMEContentType( Object o ) {
325N/A JaxBeanInfo bi = getBeanInfo(o);
325N/A if(!(bi instanceof ClassBeanInfoImpl))
325N/A return null;
325N/A
325N/A ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi;
325N/A for (Property p : cb.properties) {
325N/A if (p instanceof AttributeProperty) {
325N/A AttributeProperty ap = (AttributeProperty) p;
325N/A if(ap.attName.equals(WellKnownNamespace.XML_MIME_URI,"contentType"))
325N/A try {
325N/A return (String)ap.xacc.print(o);
325N/A } catch (AccessorException e) {
325N/A return null;
325N/A } catch (SAXException e) {
325N/A return null;
325N/A } catch (ClassCastException e) {
325N/A return null;
325N/A }
325N/A }
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A /**
325N/A * Creates a {@link JAXBContextImpl} that includes the specified additional classes.
325N/A */
325N/A public JAXBContextImpl createAugmented(Class<?> clazz) throws JAXBException {
325N/A Class[] newList = new Class[classes.length+1];
325N/A System.arraycopy(classes,0,newList,0,classes.length);
325N/A newList[classes.length] = clazz;
325N/A
325N/A JAXBContextBuilder builder = new JAXBContextBuilder(this);
325N/A builder.setClasses(newList);
325N/A return builder.build();
325N/A }
325N/A
325N/A private static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
325N/A public int compare(QName lhs, QName rhs) {
325N/A int r = lhs.getLocalPart().compareTo(rhs.getLocalPart());
325N/A if(r!=0) return r;
325N/A
325N/A return lhs.getNamespaceURI().compareTo(rhs.getNamespaceURI());
325N/A }
325N/A };
325N/A
325N/A public static class JAXBContextBuilder {
325N/A
325N/A private boolean retainPropertyInfo = false;
325N/A private boolean supressAccessorWarnings = false;
325N/A private String defaultNsUri = "";
325N/A private @NotNull RuntimeAnnotationReader annotationReader = new RuntimeInlineAnnotationReader();
325N/A private @NotNull Map<Class,Class> subclassReplacements = Collections.emptyMap();
325N/A private boolean c14nSupport = false;
325N/A private Class[] classes;
325N/A private Collection<TypeReference> typeRefs;
325N/A private boolean xmlAccessorFactorySupport = false;
325N/A private boolean allNillable;
325N/A private boolean improvedXsiTypeHandling = true;
325N/A
325N/A public JAXBContextBuilder() {};
325N/A
325N/A public JAXBContextBuilder(JAXBContextImpl baseImpl) {
325N/A this.supressAccessorWarnings = baseImpl.supressAccessorWarnings;
325N/A this.retainPropertyInfo = baseImpl.retainPropertyInfo;
325N/A this.defaultNsUri = baseImpl.defaultNsUri;
325N/A this.annotationReader = baseImpl.annotationReader;
325N/A this.subclassReplacements = baseImpl.subclassReplacements;
325N/A this.c14nSupport = baseImpl.c14nSupport;
325N/A this.classes = baseImpl.classes;
325N/A this.typeRefs = baseImpl.bridges.keySet();
325N/A this.xmlAccessorFactorySupport = baseImpl.xmlAccessorFactorySupport;
325N/A this.allNillable = baseImpl.allNillable;
325N/A }
325N/A
325N/A public JAXBContextBuilder setRetainPropertyInfo(boolean val) {
325N/A this.retainPropertyInfo = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setSupressAccessorWarnings(boolean val) {
325N/A this.supressAccessorWarnings = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setC14NSupport(boolean val) {
325N/A this.c14nSupport = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setXmlAccessorFactorySupport(boolean val) {
325N/A this.xmlAccessorFactorySupport = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setDefaultNsUri(String val) {
325N/A this.defaultNsUri = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setAllNillable(boolean val) {
325N/A this.allNillable = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setClasses(Class[] val) {
325N/A this.classes = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setAnnotationReader(RuntimeAnnotationReader val) {
325N/A this.annotationReader = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setSubclassReplacements(Map<Class,Class> val) {
325N/A this.subclassReplacements = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setTypeRefs(Collection<TypeReference> val) {
325N/A this.typeRefs = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextBuilder setImprovedXsiTypeHandling(boolean val) {
325N/A this.improvedXsiTypeHandling = val;
325N/A return this;
325N/A }
325N/A
325N/A public JAXBContextImpl build() throws JAXBException {
325N/A
325N/A // fool-proof
325N/A if (this.defaultNsUri == null) {
325N/A this.defaultNsUri = "";
325N/A }
325N/A
325N/A if (this.subclassReplacements == null) {
325N/A this.subclassReplacements = Collections.emptyMap();
325N/A }
325N/A
325N/A if (this.annotationReader == null) {
325N/A this.annotationReader = new RuntimeInlineAnnotationReader();
325N/A }
325N/A
325N/A if (this.typeRefs == null) {
325N/A this.typeRefs = Collections.<TypeReference>emptyList();
325N/A }
325N/A
325N/A return new JAXBContextImpl(this);
325N/A }
325N/A
325N/A }
325N/A
325N/A}