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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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.LinkedHashSet;
    30 import java.util.Set;
    32 import javax.xml.bind.JAXBElement;
    33 import javax.xml.bind.annotation.XmlAnyElement;
    34 import javax.xml.bind.annotation.XmlElementRef;
    35 import javax.xml.bind.annotation.XmlElementRefs;
    36 import javax.xml.bind.annotation.XmlMixed;
    37 import javax.xml.bind.annotation.XmlSchema;
    38 import javax.xml.bind.annotation.XmlNsForm;
    39 import javax.xml.namespace.QName;
    41 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
    42 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
    43 import com.sun.xml.internal.bind.v2.model.core.Element;
    44 import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
    45 import com.sun.xml.internal.bind.v2.model.core.NonElement;
    46 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
    47 import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
    48 import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
    49 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
    50 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
    51 import java.util.Iterator;
    53 /**
    54  * Implementation of {@link ReferencePropertyInfo}.
    55  *
    56  * @author Kohsuke Kawaguchi
    57  */
    58 class ReferencePropertyInfoImpl<T,C,F,M>
    59     extends ERPropertyInfoImpl<T,C,F,M>
    60     implements ReferencePropertyInfo<T,C>, DummyPropertyInfo<T, C, F, M>
    61 {
    62     /**
    63      * Lazily computed.
    64      * @see #getElements()
    65      */
    66     private Set<Element<T,C>> types;
    67     private Set<ReferencePropertyInfoImpl<T,C,F,M>> subTypes = new LinkedHashSet<ReferencePropertyInfoImpl<T,C,F,M>>();
    69     private final boolean isMixed;
    71     private final WildcardMode wildcard;
    72     private final C domHandler;
    73     /**
    74      * Lazily computed.
    75      * @see #isRequired()
    76      */
    77     private Boolean isRequired;
    79     public ReferencePropertyInfoImpl(
    80         ClassInfoImpl<T,C,F,M> classInfo,
    81         PropertySeed<T,C,F,M> seed) {
    83         super(classInfo, seed);
    85         isMixed = seed.readAnnotation(XmlMixed.class) != null;
    87         XmlAnyElement xae = seed.readAnnotation(XmlAnyElement.class);
    88         if(xae==null) {
    89             wildcard = null;
    90             domHandler = null;
    91         } else {
    92             wildcard = xae.lax()?WildcardMode.LAX:WildcardMode.SKIP;
    93             domHandler = nav().asDecl(reader().getClassValue(xae,"value"));
    94         }
    95     }
    97     public Set<? extends Element<T,C>> ref() {
    98         return getElements();
    99     }
   101     public PropertyKind kind() {
   102         return PropertyKind.REFERENCE;
   103     }
   105     public Set<? extends Element<T,C>> getElements() {
   106         if(types==null)
   107             calcTypes(false);
   108         assert types!=null;
   109         return types;
   110     }
   112     /**
   113      * Compute {@link #types}.
   114      *
   115      * @param last
   116      *      if true, every {@link XmlElementRef} must yield at least one type.
   117      */
   118     private void calcTypes(boolean last) {
   119         XmlElementRef[] ann;
   120         types = new LinkedHashSet<Element<T,C>>();
   121         XmlElementRefs refs = seed.readAnnotation(XmlElementRefs.class);
   122         XmlElementRef ref = seed.readAnnotation(XmlElementRef.class);
   124         if(refs!=null && ref!=null) {
   125             parent.builder.reportError(new IllegalAnnotationException(
   126                     Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format(
   127                     nav().getClassName(parent.getClazz())+'#'+seed.getName(),
   128                     ref.annotationType().getName(), refs.annotationType().getName()),
   129                     ref, refs ));
   130         }
   132         if(refs!=null)
   133             ann = refs.value();
   134         else {
   135             if(ref!=null)
   136                 ann = new XmlElementRef[]{ref};
   137             else
   138                 ann = null;
   139         }
   141         isRequired = !isCollection();  // this is by default, to remain compatible with 2.1
   143         if(ann!=null) {
   144             Navigator<T,C,F,M> nav = nav();
   145             AnnotationReader<T,C,F,M> reader = reader();
   147             final T defaultType = nav.ref(XmlElementRef.DEFAULT.class);
   148             final C je = nav.asDecl(JAXBElement.class);
   150             for( XmlElementRef r : ann ) {
   151                 boolean yield;
   152                 T type = reader.getClassValue(r,"type");
   153                 if(nav().isSameType(type, defaultType))
   154                     type = nav.erasure(getIndividualType());
   155                 if(nav.getBaseClass(type,je)!=null)
   156                     yield = addGenericElement(r);
   157                 else
   158                     yield = addAllSubtypes(type);
   160                 // essentially "isRequired &= isRequired(r)" except that we'd like to skip evaluating isRequird(r)
   161                 // if the value is already false.
   162                 if(isRequired && !isRequired(r))
   163                     isRequired = false;
   165                 if(last && !yield) {
   166                     // a reference didn't produce any type.
   167                     // diagnose the problem
   168                     if(nav().isSameType(type, nav.ref(JAXBElement.class))) {
   169                         // no XmlElementDecl
   170                         parent.builder.reportError(new IllegalAnnotationException(
   171                             Messages.NO_XML_ELEMENT_DECL.format(
   172                                 getEffectiveNamespaceFor(r), r.name()),
   173                             this
   174                         ));
   175                     } else {
   176                         parent.builder.reportError(new IllegalAnnotationException(
   177                             Messages.INVALID_XML_ELEMENT_REF.format(type),this));
   178                     }
   180                     // reporting one error would do.
   181                     // often the element ref field is using @XmlElementRefs
   182                     // to point to multiple JAXBElements.
   183                     // reporting one error for each @XmlElemetnRef is thus often redundant.
   184                     return;
   185                 }
   186             }
   187         }
   189         for (ReferencePropertyInfoImpl<T, C, F, M> info : subTypes) {
   190             PropertySeed sd = info.seed;
   191             refs = sd.readAnnotation(XmlElementRefs.class);
   192             ref = sd.readAnnotation(XmlElementRef.class);
   194             if (refs != null && ref != null) {
   195                 parent.builder.reportError(new IllegalAnnotationException(
   196                         Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format(
   197                         nav().getClassName(parent.getClazz())+'#'+seed.getName(),
   198                         ref.annotationType().getName(), refs.annotationType().getName()),
   199                         ref, refs ));
   200             }
   202             if (refs != null) {
   203                 ann = refs.value();
   204             } else {
   205                 if (ref != null) {
   206                     ann = new XmlElementRef[]{ref};
   207                 } else {
   208                     ann = null;
   209                 }
   210             }
   212             if (ann != null) {
   213                 Navigator<T,C,F,M> nav = nav();
   214                 AnnotationReader<T,C,F,M> reader = reader();
   216                 final T defaultType = nav.ref(XmlElementRef.DEFAULT.class);
   217                 final C je = nav.asDecl(JAXBElement.class);
   219                 for( XmlElementRef r : ann ) {
   220                     boolean yield;
   221                     T type = reader.getClassValue(r,"type");
   222                     if (nav().isSameType(type, defaultType)) {
   223                         type = nav.erasure(getIndividualType());
   224                     }
   225                     if (nav.getBaseClass(type,je) != null) {
   226                         yield = addGenericElement(r, info);
   228                     } else {
   229                         yield = addAllSubtypes(type);
   230                     }
   232                     if(last && !yield) {
   233                         // a reference didn't produce any type.
   234                         // diagnose the problem
   235                         if(nav().isSameType(type, nav.ref(JAXBElement.class))) {
   236                             // no XmlElementDecl
   237                             parent.builder.reportError(new IllegalAnnotationException(
   238                                 Messages.NO_XML_ELEMENT_DECL.format(
   239                                     getEffectiveNamespaceFor(r), r.name()),
   240                                 this
   241                             ));
   242                         } else {
   243                             parent.builder.reportError(new IllegalAnnotationException(
   244                                 Messages.INVALID_XML_ELEMENT_REF.format(),this));
   245                         }
   247                         // reporting one error would do.
   248                         // often the element ref field is using @XmlElementRefs
   249                         // to point to multiple JAXBElements.
   250                         // reporting one error for each @XmlElemetnRef is thus often redundant.
   251                         return;
   252                     }
   253                 }
   254             }
   255         }
   257         types = Collections.unmodifiableSet(types);
   258     }
   260     public boolean isRequired() {
   261         if(isRequired==null)
   262             calcTypes(false);
   263         return isRequired;
   264     }
   266     /**
   267      * If we find out that we are working with 2.1 API, remember the fact so that
   268      * we don't waste time generating exceptions every time we call {@link #isRequired(XmlElementRef)}.
   269      */
   270     private static boolean is2_2 = true;
   272     /**
   273      * Reads the value of {@code XmlElementRef.required()}.
   274      *
   275      * If we are working as 2.1 RI, this defaults to true.
   276      */
   277     private boolean isRequired(XmlElementRef ref) {
   278         if(!is2_2)  return true;
   280         try {
   281             return ref.required();
   282         } catch(LinkageError e) {
   283             is2_2 = false;
   284             return true;    // the value defaults to true
   285         }
   286     }
   288     /**
   289      * @return
   290      *      true if the reference yields at least one type
   291      */
   292     private boolean addGenericElement(XmlElementRef r) {
   293         String nsUri = getEffectiveNamespaceFor(r);
   294         // TODO: check spec. defaulting of localName.
   295         return addGenericElement(parent.owner.getElementInfo(parent.getClazz(),new QName(nsUri,r.name())));
   296     }
   298     private boolean addGenericElement(XmlElementRef r, ReferencePropertyInfoImpl<T,C,F,M> info) {
   299         String nsUri = info.getEffectiveNamespaceFor(r);
   300         ElementInfo ei = parent.owner.getElementInfo(info.parent.getClazz(), new QName(nsUri, r.name()));
   301         types.add(ei);
   302         return true;
   303     }
   305     private String getEffectiveNamespaceFor(XmlElementRef r) {
   306         String nsUri = r.namespace();
   308         XmlSchema xs = reader().getPackageAnnotation( XmlSchema.class, parent.getClazz(), this );
   309         if(xs!=null && xs.attributeFormDefault()== XmlNsForm.QUALIFIED) {
   310             // JAX-RPC doesn't want the default namespace URI swapping to take effect to
   311             // local "unqualified" elements. UGLY.
   312             if(nsUri.length()==0)
   313                 nsUri = parent.builder.defaultNsUri;
   314         }
   316         return nsUri;
   317     }
   319     private boolean addGenericElement(ElementInfo<T,C> ei) {
   320         if(ei==null)
   321             return false;
   322         types.add(ei);
   323         for( ElementInfo<T,C> subst : ei.getSubstitutionMembers() )
   324             addGenericElement(subst);
   325         return true;
   326     }
   328     private boolean addAllSubtypes(T type) {
   329         Navigator<T,C,F,M> nav = nav();
   331         // this allows the explicitly referenced type to be sucked in to the model
   332         NonElement<T,C> t = parent.builder.getClassInfo(nav.asDecl(type),this);
   333         if(!(t instanceof ClassInfo))
   334             // this is leaf.
   335             return false;
   337         boolean result = false;
   339         ClassInfo<T,C> c = (ClassInfo<T,C>) t;
   340         if(c.isElement()) {
   341             types.add(c.asElement());
   342             result = true;
   343         }
   345         // look for other possible types
   346         for( ClassInfo<T,C> ci : parent.owner.beans().values() ) {
   347             if(ci.isElement() && nav.isSubClassOf(ci.getType(),type)) {
   348                 types.add(ci.asElement());
   349                 result = true;
   350             }
   351         }
   353         // don't allow local elements to substitute.
   354         for( ElementInfo<T,C> ei : parent.owner.getElementMappings(null).values()) {
   355             if(nav.isSubClassOf(ei.getType(),type)) {
   356                 types.add(ei);
   357                 result = true;
   358             }
   359         }
   361         return result;
   362     }
   365     @Override
   366     protected void link() {
   367         super.link();
   369         // until we get the whole thing into TypeInfoSet,
   370         // we never really know what are all the possible types that can be assigned on this field.
   371         // so recompute this value when we have all the information.
   372         calcTypes(true);
   374     }
   376     public final void addType(PropertyInfoImpl<T,C,F,M> info) {
   377         //noinspection unchecked
   378         subTypes.add((ReferencePropertyInfoImpl)info);
   379     }
   381     public final boolean isMixed() {
   382         return isMixed;
   383     }
   385     public final WildcardMode getWildcard() {
   386         return wildcard;
   387     }
   389     public final C getDOMHandler() {
   390         return domHandler;
   391     }
   392 }

mercurial