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

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

     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.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<PropertyInfoImpl<T,C,F,M>> subTypes = new LinkedHashSet<PropertyInfoImpl<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         Iterator<PropertyInfoImpl<T,C,F,M>> i = subTypes.iterator();
   190         while (i.hasNext()) {
   192             ReferencePropertyInfoImpl<T,C,F,M> info = (ReferencePropertyInfoImpl<T, C, F, M>) i.next();
   193             PropertySeed sd = info.seed;
   194             refs = sd.readAnnotation(XmlElementRefs.class);
   195             ref = sd.readAnnotation(XmlElementRef.class);
   197             if (refs != null && ref != null) {
   198                 parent.builder.reportError(new IllegalAnnotationException(
   199                         Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format(
   200                         nav().getClassName(parent.getClazz())+'#'+seed.getName(),
   201                         ref.annotationType().getName(), refs.annotationType().getName()),
   202                         ref, refs ));
   203             }
   205             if (refs != null) {
   206                 ann = refs.value();
   207             } else {
   208                 if (ref != null) {
   209                     ann = new XmlElementRef[]{ref};
   210                 } else {
   211                     ann = null;
   212                 }
   213             }
   215             if (ann != null) {
   216                 Navigator<T,C,F,M> nav = nav();
   217                 AnnotationReader<T,C,F,M> reader = reader();
   219                 final T defaultType = nav.ref(XmlElementRef.DEFAULT.class);
   220                 final C je = nav.asDecl(JAXBElement.class);
   222                 for( XmlElementRef r : ann ) {
   223                     boolean yield;
   224                     T type = reader.getClassValue(r,"type");
   225                     if (nav().isSameType(type, defaultType)) {
   226                         type = nav.erasure(getIndividualType());
   227                     }
   228                     if (nav.getBaseClass(type,je) != null) {
   229                         yield = addGenericElement(r, info);
   231                     } else {
   232                         yield = addAllSubtypes(type);
   233                     }
   235                     if(last && !yield) {
   236                         // a reference didn't produce any type.
   237                         // diagnose the problem
   238                         if(nav().isSameType(type, nav.ref(JAXBElement.class))) {
   239                             // no XmlElementDecl
   240                             parent.builder.reportError(new IllegalAnnotationException(
   241                                 Messages.NO_XML_ELEMENT_DECL.format(
   242                                     getEffectiveNamespaceFor(r), r.name()),
   243                                 this
   244                             ));
   245                         } else {
   246                             parent.builder.reportError(new IllegalAnnotationException(
   247                                 Messages.INVALID_XML_ELEMENT_REF.format(),this));
   248                         }
   250                         // reporting one error would do.
   251                         // often the element ref field is using @XmlElementRefs
   252                         // to point to multiple JAXBElements.
   253                         // reporting one error for each @XmlElemetnRef is thus often redundant.
   254                         return;
   255                     }
   256                 }
   257             }
   258         }
   260         types = Collections.unmodifiableSet(types);
   261     }
   263     public boolean isRequired() {
   264         if(isRequired==null)
   265             calcTypes(false);
   266         return isRequired;
   267     }
   269     /**
   270      * If we find out that we are working with 2.1 API, remember the fact so that
   271      * we don't waste time generating exceptions every time we call {@link #isRequired(XmlElementRef)}.
   272      */
   273     private static boolean is2_2 = true;
   275     /**
   276      * Reads the value of {@code XmlElementRef.required()}.
   277      *
   278      * If we are working as 2.1 RI, this defaults to true.
   279      */
   280     private boolean isRequired(XmlElementRef ref) {
   281         if(!is2_2)  return true;
   283         try {
   284             return ref.required();
   285         } catch(LinkageError e) {
   286             is2_2 = false;
   287             return true;    // the value defaults to true
   288         }
   289     }
   291     /**
   292      * @return
   293      *      true if the reference yields at least one type
   294      */
   295     private boolean addGenericElement(XmlElementRef r) {
   296         String nsUri = getEffectiveNamespaceFor(r);
   297         // TODO: check spec. defaulting of localName.
   298         return addGenericElement(parent.owner.getElementInfo(parent.getClazz(),new QName(nsUri,r.name())));
   299     }
   301     private boolean addGenericElement(XmlElementRef r, ReferencePropertyInfoImpl<T,C,F,M> info) {
   302         String nsUri = info.getEffectiveNamespaceFor(r);
   303         ElementInfo ei = parent.owner.getElementInfo(info.parent.getClazz(), new QName(nsUri, r.name()));
   304         types.add(ei);
   305         return true;
   306     }
   308     private String getEffectiveNamespaceFor(XmlElementRef r) {
   309         String nsUri = r.namespace();
   311         XmlSchema xs = reader().getPackageAnnotation( XmlSchema.class, parent.getClazz(), this );
   312         if(xs!=null && xs.attributeFormDefault()== XmlNsForm.QUALIFIED) {
   313             // JAX-RPC doesn't want the default namespace URI swapping to take effect to
   314             // local "unqualified" elements. UGLY.
   315             if(nsUri.length()==0)
   316                 nsUri = parent.builder.defaultNsUri;
   317         }
   319         return nsUri;
   320     }
   322     private boolean addGenericElement(ElementInfo<T,C> ei) {
   323         if(ei==null)
   324             return false;
   325         types.add(ei);
   326         for( ElementInfo<T,C> subst : ei.getSubstitutionMembers() )
   327             addGenericElement(subst);
   328         return true;
   329     }
   331     private boolean addAllSubtypes(T type) {
   332         Navigator<T,C,F,M> nav = nav();
   334         // this allows the explicitly referenced type to be sucked in to the model
   335         NonElement<T,C> t = parent.builder.getClassInfo(nav.asDecl(type),this);
   336         if(!(t instanceof ClassInfo))
   337             // this is leaf.
   338             return false;
   340         boolean result = false;
   342         ClassInfo<T,C> c = (ClassInfo<T,C>) t;
   343         if(c.isElement()) {
   344             types.add(c.asElement());
   345             result = true;
   346         }
   348         // look for other possible types
   349         for( ClassInfo<T,C> ci : parent.owner.beans().values() ) {
   350             if(ci.isElement() && nav.isSubClassOf(ci.getType(),type)) {
   351                 types.add(ci.asElement());
   352                 result = true;
   353             }
   354         }
   356         // don't allow local elements to substitute.
   357         for( ElementInfo<T,C> ei : parent.owner.getElementMappings(null).values()) {
   358             if(nav.isSubClassOf(ei.getType(),type)) {
   359                 types.add(ei);
   360                 result = true;
   361             }
   362         }
   364         return result;
   365     }
   368     @Override
   369     protected void link() {
   370         super.link();
   372         // until we get the whole thing into TypeInfoSet,
   373         // we never really know what are all the possible types that can be assigned on this field.
   374         // so recompute this value when we have all the information.
   375         calcTypes(true);
   377     }
   379     public final void addType(PropertyInfoImpl<T,C,F,M> info) {
   380         subTypes.add(info);
   381     }
   383     public final boolean isMixed() {
   384         return isMixed;
   385     }
   387     public final WildcardMode getWildcard() {
   388         return wildcard;
   389     }
   391     public final C getDOMHandler() {
   392         return domHandler;
   393     }
   394 }

mercurial