src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/TypeInfoSetImpl.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2011, 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.model.impl;
    28 import java.util.Collections;
    29 import java.util.HashMap;
    30 import java.util.Iterator;
    31 import java.util.LinkedHashMap;
    32 import java.util.Map;
    34 import javax.xml.bind.JAXBContext;
    35 import javax.xml.bind.JAXBException;
    36 import javax.xml.bind.Marshaller;
    37 import javax.xml.bind.annotation.XmlNs;
    38 import javax.xml.bind.annotation.XmlNsForm;
    39 import javax.xml.bind.annotation.XmlRegistry;
    40 import javax.xml.bind.annotation.XmlSchema;
    41 import javax.xml.bind.annotation.XmlTransient;
    42 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    43 import javax.xml.namespace.QName;
    44 import javax.xml.transform.Result;
    46 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
    47 import com.sun.xml.internal.bind.v2.model.core.BuiltinLeafInfo;
    48 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
    49 import com.sun.xml.internal.bind.v2.model.core.LeafInfo;
    50 import com.sun.xml.internal.bind.v2.model.core.NonElement;
    51 import com.sun.xml.internal.bind.v2.model.core.Ref;
    52 import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
    53 import com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
    54 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
    55 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
    56 import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil;
    57 import com.sun.xml.internal.bind.v2.util.FlattenIterator;
    59 /**
    60  * Set of {@link TypeInfo}s.
    61  *
    62  * <p>
    63  * This contains a fixed set of {@link LeafInfo}s and arbitrary set of {@link ClassInfo}s.
    64  *
    65  * <p>
    66  * Members are annotated with JAXB annotations so that we can dump it easily.
    67  *
    68  * @author Kohsuke Kawaguchi
    69  */
    70 class TypeInfoSetImpl<T,C,F,M> implements TypeInfoSet<T,C,F,M> {
    72     @XmlTransient
    73     public final Navigator<T,C,F,M> nav;
    75     @XmlTransient
    76     public final AnnotationReader<T,C,F,M> reader;
    78     /**
    79      * All the leaves.
    80      */
    81     private final Map<T,BuiltinLeafInfo<T,C>> builtins =
    82             new LinkedHashMap<T,BuiltinLeafInfo<T,C>>();
    84     /** All {@link EnumLeafInfoImpl}s. */
    85     private final Map<C,EnumLeafInfoImpl<T,C,F,M>> enums =
    86             new LinkedHashMap<C,EnumLeafInfoImpl<T,C,F,M>>();
    88     /** All {@link ArrayInfoImpl}s. */
    89     private final Map<T,ArrayInfoImpl<T,C,F,M>> arrays =
    90             new LinkedHashMap<T,ArrayInfoImpl<T,C,F,M>>();
    92     /**
    93      * All the user-defined classes.
    94      *
    95      * Using {@link LinkedHashMap} allows us to process classes
    96      * in the order they are given to us. When the user incorrectly
    97      * puts an unexpected class into a reference graph, this causes
    98      * an error to be reported on a class closer to the user's code.
    99      */
   100     @XmlJavaTypeAdapter(RuntimeUtil.ToStringAdapter.class)
   101     private final Map<C,ClassInfoImpl<T,C,F,M>> beans
   102             = new LinkedHashMap<C,ClassInfoImpl<T,C,F,M>>();
   104     @XmlTransient
   105     private final Map<C,ClassInfoImpl<T,C,F,M>> beansView =
   106         Collections.unmodifiableMap(beans);
   108     /**
   109      * The element mapping.
   110      */
   111     private final Map<C,Map<QName,ElementInfoImpl<T,C,F,M>>> elementMappings =
   112         new LinkedHashMap<C,Map<QName,ElementInfoImpl<T,C,F,M>>>();
   114     private final Iterable<? extends ElementInfoImpl<T,C,F,M>> allElements =
   115         new Iterable<ElementInfoImpl<T,C,F,M>>() {
   116             public Iterator<ElementInfoImpl<T,C,F,M>> iterator() {
   117                 return new FlattenIterator<ElementInfoImpl<T,C,F,M>>(elementMappings.values());
   118             }
   119         };
   121     /**
   122      * {@link TypeInfo} for <tt>xs:anyType</tt>.
   123      *
   124      * anyType is the only {@link TypeInfo} that works with an interface,
   125      * and accordingly it requires a lot of special casing.
   126      */
   127     private final NonElement<T,C> anyType;
   129     /**
   130      * Lazily parsed set of {@link XmlNs}s.
   131      *
   132      * @see #getXmlNs(String)
   133      */
   134     private Map<String,Map<String,String>> xmlNsCache;
   136     public TypeInfoSetImpl(Navigator<T,C,F,M> nav,
   137                            AnnotationReader<T,C,F,M> reader,
   138                            Map<T,? extends BuiltinLeafInfoImpl<T,C>> leaves) {
   139         this.nav = nav;
   140         this.reader = reader;
   141         this.builtins.putAll(leaves);
   143         this.anyType = createAnyType();
   145         // register primitive types.
   146         for (Map.Entry<Class, Class> e : RuntimeUtil.primitiveToBox.entrySet()) {
   147             this.builtins.put( nav.getPrimitive(e.getKey()), leaves.get(nav.ref(e.getValue())) );
   148         }
   150         // make sure at lease we got a map for global ones.
   151         elementMappings.put(null,new LinkedHashMap<QName,ElementInfoImpl<T,C,F,M>>());
   152     }
   154     protected NonElement<T,C> createAnyType() {
   155         return new AnyTypeImpl<T,C>(nav);
   156     }
   158     public Navigator<T,C,F,M> getNavigator() {
   159         return nav;
   160     }
   162     /**
   163      * Adds a new {@link ClassInfo} to the set.
   164      */
   165     public void add( ClassInfoImpl<T,C,F,M> ci ) {
   166         beans.put( ci.getClazz(), ci );
   167     }
   169     /**
   170      * Adds a new {@link LeafInfo} to the set.
   171      */
   172     public void add( EnumLeafInfoImpl<T,C,F,M> li ) {
   173         enums.put( li.clazz,  li );
   174     }
   176     public void add(ArrayInfoImpl<T, C, F, M> ai) {
   177         arrays.put( ai.getType(), ai );
   178     }
   180     /**
   181      * Returns a {@link TypeInfo} for the given type.
   182      *
   183      * @return
   184      *      null if the specified type cannot be bound by JAXB, or
   185      *      not known to this set.
   186      */
   187     public NonElement<T,C> getTypeInfo( T type ) {
   188         type = nav.erasure(type);   // replace type variables by their bounds
   190         LeafInfo<T,C> l = builtins.get(type);
   191         if(l!=null)     return l;
   193         if( nav.isArray(type) ) {
   194             return arrays.get(type);
   195         }
   197         C d = nav.asDecl(type);
   198         if(d==null)     return null;
   199         return getClassInfo(d);
   200     }
   202     public NonElement<T,C> getAnyTypeInfo() {
   203         return anyType;
   204     }
   206     /**
   207      * This method is used to add a root reference to a model.
   208      */
   209     public NonElement<T,C> getTypeInfo(Ref<T,C> ref) {
   210         // TODO: handle XmlValueList
   211         assert !ref.valueList;
   212         C c = nav.asDecl(ref.type);
   213         if(c!=null && reader.getClassAnnotation(XmlRegistry.class,c,null/*TODO: is this right?*/)!=null) {
   214             return null;    // TODO: is this correct?
   215         } else
   216             return getTypeInfo(ref.type);
   217     }
   219     /**
   220      * Returns all the {@link ClassInfo}s known to this set.
   221      */
   222     public Map<C,? extends ClassInfoImpl<T,C,F,M>> beans() {
   223         return beansView;
   224     }
   226     public Map<T, ? extends BuiltinLeafInfo<T,C>> builtins() {
   227         return builtins;
   228     }
   230     public Map<C, ? extends EnumLeafInfoImpl<T,C,F,M>> enums() {
   231         return enums;
   232     }
   234     public Map<? extends T, ? extends ArrayInfoImpl<T,C,F,M>> arrays() {
   235         return arrays;
   236     }
   238     /**
   239      * Returns a {@link ClassInfo} for the given bean.
   240      *
   241      * <p>
   242      * This method is almost like refinement of {@link #getTypeInfo(Object)} except
   243      * our C cannot derive from T.
   244      *
   245      * @return
   246      *      null if the specified type is not bound by JAXB or otherwise
   247      *      unknown to this set.
   248      */
   249     public NonElement<T,C> getClassInfo( C type ) {
   250         LeafInfo<T,C> l = builtins.get(nav.use(type));
   251         if(l!=null)     return l;
   253         l = enums.get(type);
   254         if(l!=null)     return l;
   256         if(nav.asDecl(Object.class).equals(type))
   257             return anyType;
   259         return beans.get(type);
   260     }
   262     public ElementInfoImpl<T,C,F,M> getElementInfo( C scope, QName name ) {
   263         while(scope!=null) {
   264             Map<QName,ElementInfoImpl<T,C,F,M>> m = elementMappings.get(scope);
   265             if(m!=null) {
   266                 ElementInfoImpl<T,C,F,M> r = m.get(name);
   267                 if(r!=null)     return r;
   268             }
   269             scope = nav.getSuperClass(scope);
   270         }
   271         return elementMappings.get(null).get(name);
   272     }
   274     /**
   275      * @param builder
   276      *      used for reporting errors.
   277      */
   278     public final void add( ElementInfoImpl<T,C,F,M> ei, ModelBuilder<T,C,F,M> builder ) {
   279         C scope = null;
   280         if(ei.getScope()!=null)
   281             scope = ei.getScope().getClazz();
   283         Map<QName,ElementInfoImpl<T,C,F,M>> m = elementMappings.get(scope);
   284         if(m==null)
   285             elementMappings.put(scope,m=new LinkedHashMap<QName,ElementInfoImpl<T,C,F,M>>());
   287         ElementInfoImpl<T,C,F,M> existing = m.put(ei.getElementName(),ei);
   289         if(existing!=null) {
   290             QName en = ei.getElementName();
   291             builder.reportError(
   292                 new IllegalAnnotationException(
   293                     Messages.CONFLICTING_XML_ELEMENT_MAPPING.format(en.getNamespaceURI(),en.getLocalPart()),
   294                     ei, existing ));
   295         }
   296     }
   298     public Map<QName,? extends ElementInfoImpl<T,C,F,M>> getElementMappings( C scope ) {
   299         return elementMappings.get(scope);
   300     }
   302     public Iterable<? extends ElementInfoImpl<T,C,F,M>> getAllElements() {
   303         return allElements;
   304     }
   306     public Map<String,String> getXmlNs(String namespaceUri) {
   307         if(xmlNsCache==null) {
   308             xmlNsCache = new HashMap<String,Map<String,String>>();
   310             for (ClassInfoImpl<T, C, F, M> ci : beans().values()) {
   311                 XmlSchema xs = reader.getPackageAnnotation( XmlSchema.class, ci.getClazz(), null );
   312                 if(xs==null)
   313                     continue;
   315                 String uri = xs.namespace();
   316                 Map<String,String> m = xmlNsCache.get(uri);
   317                 if(m==null)
   318                     xmlNsCache.put(uri,m=new HashMap<String, String>());
   320                 for( XmlNs xns : xs.xmlns() ) {
   321                     m.put(xns.prefix(),xns.namespaceURI());
   322                 }
   323             }
   324         }
   326         Map<String,String> r = xmlNsCache.get(namespaceUri);
   327         if(r!=null)     return r;
   328         else            return Collections.emptyMap();
   329     }
   331     public Map<String,String> getSchemaLocations() {
   332         Map<String, String> r = new HashMap<String,String>();
   333         for (ClassInfoImpl<T, C, F, M> ci : beans().values()) {
   334             XmlSchema xs = reader.getPackageAnnotation( XmlSchema.class, ci.getClazz(), null );
   335             if(xs==null)
   336                 continue;
   338             String loc = xs.location();
   339             if(loc.equals(XmlSchema.NO_LOCATION))
   340                 continue;   // unspecified
   342             r.put(xs.namespace(),loc);
   343         }
   344         return r;
   345     }
   347     public final XmlNsForm getElementFormDefault(String nsUri) {
   348         for (ClassInfoImpl<T, C, F, M> ci : beans().values()) {
   349             XmlSchema xs = reader.getPackageAnnotation( XmlSchema.class, ci.getClazz(), null );
   350             if(xs==null)
   351                 continue;
   353             if(!xs.namespace().equals(nsUri))
   354                 continue;
   356             XmlNsForm xnf = xs.elementFormDefault();
   357             if(xnf!=XmlNsForm.UNSET)
   358                 return xnf;
   359         }
   360         return XmlNsForm.UNSET;
   361     }
   363     public final XmlNsForm getAttributeFormDefault(String nsUri) {
   364         for (ClassInfoImpl<T,C,F,M> ci : beans().values()) {
   365             XmlSchema xs = reader.getPackageAnnotation( XmlSchema.class, ci.getClazz(), null );
   366             if(xs==null)
   367                 continue;
   369             if(!xs.namespace().equals(nsUri))
   370                 continue;
   372             XmlNsForm xnf = xs.attributeFormDefault();
   373             if(xnf!=XmlNsForm.UNSET)
   374                 return xnf;
   375         }
   376         return XmlNsForm.UNSET;
   377     }
   379     /**
   380      * Dumps this model into XML.
   381      *
   382      * For debug only.
   383      *
   384      * TODO: not sure if this actually works. We don't really know what are T,C.
   385      */
   386     public void dump( Result out ) throws JAXBException {
   387         JAXBContext context = JAXBContext.newInstance(this.getClass());
   388         Marshaller m = context.createMarshaller();
   389         m.marshal(this,out);
   390     }
   391 }

mercurial