src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/DefaultClassBinder.java

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

     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.tools.internal.xjc.reader.xmlschema;
    27 import static com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder.getName;
    29 import java.util.Set;
    31 import javax.xml.namespace.QName;
    33 import com.sun.codemodel.internal.JJavaName;
    34 import com.sun.codemodel.internal.JPackage;
    35 import com.sun.istack.internal.NotNull;
    36 import com.sun.istack.internal.Nullable;
    37 import com.sun.tools.internal.xjc.ErrorReceiver;
    38 import com.sun.tools.internal.xjc.model.CClassInfo;
    39 import com.sun.tools.internal.xjc.model.CClassInfoParent;
    40 import com.sun.tools.internal.xjc.model.CClassRef;
    41 import com.sun.tools.internal.xjc.model.CCustomizations;
    42 import com.sun.tools.internal.xjc.model.CElement;
    43 import com.sun.tools.internal.xjc.model.CElementInfo;
    44 import com.sun.tools.internal.xjc.model.Model;
    45 import com.sun.tools.internal.xjc.reader.Ring;
    46 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIClass;
    47 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIGlobalBinding;
    48 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BISchemaBinding;
    49 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
    50 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIXSubstitutable;
    51 import com.sun.tools.internal.xjc.reader.xmlschema.ct.ComplexTypeFieldBuilder;
    52 import com.sun.tools.internal.xjc.reader.xmlschema.ct.ComplexTypeBindingMode;
    53 import com.sun.xml.internal.xsom.XSAnnotation;
    54 import com.sun.xml.internal.xsom.XSAttGroupDecl;
    55 import com.sun.xml.internal.xsom.XSAttributeDecl;
    56 import com.sun.xml.internal.xsom.XSAttributeUse;
    57 import com.sun.xml.internal.xsom.XSComplexType;
    58 import com.sun.xml.internal.xsom.XSComponent;
    59 import com.sun.xml.internal.xsom.XSContentType;
    60 import com.sun.xml.internal.xsom.XSDeclaration;
    61 import com.sun.xml.internal.xsom.XSElementDecl;
    62 import com.sun.xml.internal.xsom.XSFacet;
    63 import com.sun.xml.internal.xsom.XSIdentityConstraint;
    64 import com.sun.xml.internal.xsom.XSModelGroup;
    65 import com.sun.xml.internal.xsom.XSModelGroupDecl;
    66 import com.sun.xml.internal.xsom.XSNotation;
    67 import com.sun.xml.internal.xsom.XSParticle;
    68 import com.sun.xml.internal.xsom.XSSchema;
    69 import com.sun.xml.internal.xsom.XSSchemaSet;
    70 import com.sun.xml.internal.xsom.XSSimpleType;
    71 import com.sun.xml.internal.xsom.XSType;
    72 import com.sun.xml.internal.xsom.XSWildcard;
    73 import com.sun.xml.internal.xsom.XSXPath;
    75 import org.xml.sax.Locator;
    77 /**
    78  * Default classBinder implementation. Honors <jaxb:class> customizations
    79  * and default bindings.
    80  */
    81 final class DefaultClassBinder implements ClassBinder
    82 {
    83     private final SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class);
    84     private final Model model = Ring.get(Model.class);
    86     protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
    87     protected final ClassSelector selector = Ring.get(ClassSelector.class);
    89     protected final XSSchemaSet schemas = Ring.get(XSSchemaSet.class);
    91     public CElement attGroupDecl(XSAttGroupDecl decl) {
    92         return allow(decl,decl.getName());
    93     }
    95     public CElement attributeDecl(XSAttributeDecl decl) {
    96         return allow(decl,decl.getName());
    97     }
    99     public CElement modelGroup(XSModelGroup mgroup) {
   100         return never();
   101     }
   103     public CElement modelGroupDecl(XSModelGroupDecl decl) {
   104         return never();
   105     }
   108     public CElement complexType(XSComplexType type) {
   109         CElement ci = allow(type,type.getName());
   110         if(ci!=null)    return ci;
   112         // no customization is given -- do as the default binding.
   114         BindInfo bi = builder.getBindInfo(type);
   116         if(type.isGlobal()) {
   117             QName tagName = null;
   118             String className = deriveName(type);
   119             Locator loc = type.getLocator();
   121             if(getGlobalBinding().isSimpleMode()) {
   122                 // in the simple mode, we may optimize it away
   123                 XSElementDecl referer = getSoleElementReferer(type);
   124                 if(referer!=null && isCollapsable(referer)) {
   125                     // if a global element contains
   126                     // a collpsable complex type, we bind this element to a named one
   127                     // and collapses element and complex type.
   128                     tagName = getName(referer);
   129                     className = deriveName(referer);
   130                     loc = referer.getLocator();
   131                 }
   132             }
   134             // by default, global ones get their own classes.
   136             JPackage pkg = selector.getPackage(type.getTargetNamespace());
   138             return new CClassInfo(model,pkg,className, loc,getTypeName(type),tagName,type,bi.toCustomizationList());
   139         } else {
   140             XSElementDecl element = type.getScope();
   142             if( element.isGlobal() && isCollapsable(element)) {
   143                 if(builder.getBindInfo(element).get(BIClass.class)!=null)
   144                     // the parent element was bound to a class. Don't bind this again to
   145                     // cause unnecessary wrapping
   146                     return null;
   148                 // generate one class from element and complex type together.
   149                 // this needs to be done before selector.isBound to avoid infinite recursion.
   151                 // but avoid doing so when the element is mapped to a class,
   152                 // which creates unnecessary classes
   153                 return new CClassInfo( model, selector.getClassScope(),
   154                     deriveName(element), element.getLocator(), null,
   155                     getName(element), element, bi.toCustomizationList() );
   156             }
   159             CElement parentType = selector.isBound(element,type);
   161             String className;
   162             CClassInfoParent scope;
   165             if( parentType!=null
   166              && parentType instanceof CElementInfo
   167              && ((CElementInfo)parentType).hasClass() ) {
   168                 // special case where we put a nested 'Type' element
   169                 scope = (CElementInfo)parentType;
   170                 className = "Type";
   171             } else {
   172                 // since the parent element isn't bound to a type, merge the customizations associated to it, too.
   173 //                custs = CCustomizations.merge( custs, builder.getBindInfo(type.getScope()).toCustomizationList());
   174                 className = builder.getNameConverter().toClassName(element.getName());
   176                 BISchemaBinding sb = builder.getBindInfo(
   177                     type.getOwnerSchema() ).get(BISchemaBinding.class);
   178                 if(sb!=null)    className = sb.mangleAnonymousTypeClassName(className);
   179                 scope = selector.getClassScope();
   180             }
   182             return new CClassInfo(model, scope, className, type.getLocator(), null, null, type, bi.toCustomizationList() );
   183         }
   184     }
   186     private QName getTypeName(XSComplexType type) {
   187         if(type.getRedefinedBy()!=null)
   188             return null;
   189         else
   190             return getName(type);
   191     }
   193     /**
   194      * Returns true if the complex type of the given element can be "optimized away"
   195      * and unified with its parent element decl to form a single class.
   196      */
   197     private boolean isCollapsable(XSElementDecl decl) {
   198         XSType type = decl.getType();
   200         if(!type.isComplexType())
   201             return false;   // not a complex type
   203         if(decl.getSubstitutables().size()>1 || decl.getSubstAffiliation()!=null)
   204             // because element substitution calls for a proper JAXBElement hierarchy
   205             return false;
   207         if(decl.isNillable())
   208             // because nillable needs JAXBElement to represent correctly
   209             return false;
   211         BIXSubstitutable bixSubstitutable = builder.getBindInfo(decl).get(BIXSubstitutable.class);
   212         if(bixSubstitutable !=null) {
   213             // see https://jaxb.dev.java.net/issues/show_bug.cgi?id=289
   214             // this customization forces non-collapsing behavior.
   215             bixSubstitutable.markAsAcknowledged();
   216             return false;
   217         }
   219         if( getGlobalBinding().isSimpleMode() && decl.isGlobal()) {
   220             // in the simple mode, we do more aggressive optimization, and get rid of
   221             // a complex type class if it's only used once from a global element
   222             XSElementDecl referer = getSoleElementReferer(decl.getType());
   223             if(referer!=null) {
   224                 assert referer==decl;  // I must be the sole referer
   225                 return true;
   226             }
   227         }
   229         if(!type.isLocal() || !type.isComplexType())
   230             return false;
   232         return true;
   233     }
   235     /**
   236      * If only one global {@link XSElementDecl} is refering to {@link XSType},
   237      * return that element, otherwise null.
   238      */
   239     private @Nullable XSElementDecl getSoleElementReferer(@NotNull XSType t) {
   240         Set<XSComponent> referer = builder.getReferer(t);
   242         XSElementDecl sole = null;
   243         for (XSComponent r : referer) {
   244             if(r instanceof XSElementDecl) {
   245                 XSElementDecl x = (XSElementDecl) r;
   246                 if(!x.isGlobal())
   247                     // local element references can be ignored, as their names are either given
   248                     // by the property, or by the JAXBElement (for things like mixed contents)
   249                     continue;
   250                 if(sole==null)  sole=x;
   251                 else            return null;    // more than one
   252             } else {
   253                 // if another type refers to this type, that means
   254                 // this type has a sub-type, so type substitution is possible now.
   255                 return null;
   256             }
   257         }
   259         return sole;
   260     }
   262     public CElement elementDecl(XSElementDecl decl) {
   263         CElement r = allow(decl,decl.getName());
   265         if(r==null) {
   266             QName tagName = getName(decl);
   267             CCustomizations custs = builder.getBindInfo(decl).toCustomizationList();
   269             if(decl.isGlobal()) {
   270                 if(isCollapsable(decl)) {
   271                     // we want the returned type to be built as a complex type,
   272                     // so the binding cannot be delayed.
   273                     return selector.bindToType(decl.getType().asComplexType(),decl,true);
   274                 } else {
   275                     String className = null;
   276                     if(getGlobalBinding().isGenerateElementClass())
   277                         className = deriveName(decl);
   279                     // otherwise map global elements to JAXBElement
   280                     CElementInfo cei = new CElementInfo(
   281                         model, tagName, selector.getClassScope(), className, custs, decl.getLocator());
   282                     selector.boundElements.put(decl,cei);
   284                     stb.refererStack.push(decl);    // referer is element
   285                     cei.initContentType( selector.bindToType(decl.getType(),decl), decl, decl.getDefaultValue() );
   286                     stb.refererStack.pop();
   287                     r = cei;
   288                 }
   289             }
   290         }
   292         // have the substitution member derive from the substitution head
   293         XSElementDecl top = decl.getSubstAffiliation();
   294         if(top!=null) {
   295             CElement topci = selector.bindToType(top,decl);
   297             if(r instanceof CClassInfo && topci instanceof CClassInfo)
   298                 ((CClassInfo)r).setBaseClass((CClassInfo)topci);
   299             if (r instanceof CElementInfo && topci instanceof CElementInfo)
   300                 ((CElementInfo)r).setSubstitutionHead((CElementInfo)topci);
   301         }
   303         return r;
   304     }
   306     public CClassInfo empty( XSContentType ct ) { return null; }
   308     public CClassInfo identityConstraint(XSIdentityConstraint xsIdentityConstraint) {
   309         return never();
   310     }
   312     public CClassInfo xpath(XSXPath xsxPath) {
   313         return never();
   314     }
   316     public CClassInfo attributeUse(XSAttributeUse use) {
   317         return never();
   318     }
   320     public CElement simpleType(XSSimpleType type) {
   321         CElement c = allow(type,type.getName());
   322         if(c!=null) return c;
   324         if(getGlobalBinding().isSimpleTypeSubstitution() && type.isGlobal()) {
   325             return new CClassInfo(model,selector.getClassScope(),
   326                     deriveName(type), type.getLocator(), getName(type), null, type, null );
   327         }
   329         return never();
   330     }
   332     public CClassInfo particle(XSParticle particle) {
   333         return never();
   334     }
   336     public CClassInfo wildcard(XSWildcard wc) {
   337         return never();
   338     }
   341     // these methods won't be used
   342     public CClassInfo annotation(XSAnnotation annon) {
   343         assert false;
   344         return null;
   345     }
   347     public CClassInfo notation(XSNotation not) {
   348         assert false;
   349         return null;
   350     }
   352     public CClassInfo facet(XSFacet decl) {
   353         assert false;
   354         return null;
   355     }
   356     public CClassInfo schema(XSSchema schema) {
   357         assert false;
   358         return null;
   359     }
   365     /**
   366      * Makes sure that the component doesn't carry a {@link BIClass}
   367      * customization.
   368      *
   369      * @return
   370      *      return value is unused. Since most of the caller needs to
   371      *      return null, to make the code a little bit shorter, this
   372      *      method always return null (so that the caller can always
   373      *      say <code>return never(sc);</code>.
   374      */
   375     private CClassInfo never() {
   376         // all we need to do here is just not to acknowledge
   377         // any class customization. Then this class customization
   378         // will be reported as an error later when we check all
   379         // unacknowledged customizations.
   382 //        BIDeclaration cust=owner.getBindInfo(component).get(BIClass.NAME);
   383 //        if(cust!=null) {
   384 //            // error
   385 //            owner.errorReporter.error(
   386 //                cust.getLocation(),
   387 //                "test {0}", NameGetter.get(component) );
   388 //        }
   389         return null;
   390     }
   392     /**
   393      * Checks if a component carries a customization to map it to a class.
   394      * If so, make it a class.
   395      *
   396      * @param defaultBaseName
   397      *      The token which will be used as the basis of the class name
   398      *      if the class name is not specified in the customization.
   399      *      This is usually the name of an element declaration, and so on.
   400      *
   401      *      This parameter can be null, in that case it would be an error
   402      *      if a name is not given by the customization.
   403      */
   404     private CElement allow( XSComponent component, String defaultBaseName ) {
   406         BIClass decl = null;
   408         if(component instanceof XSComplexType) {
   409             XSType complexType = (XSType)component;
   411             BIClass lastFoundRecursiveBiClass = null;
   413             if(complexType.getName() != null) {
   414                 while( ! schemas.getAnyType().equals(complexType)) {
   415                     BindInfo bindInfo = builder.getBindInfo(complexType);
   416                     BIClass biClass = bindInfo.get(BIClass.class);
   418                     if(biClass != null && "true".equals(biClass.getRecursive()))
   419                         lastFoundRecursiveBiClass = biClass;
   421                     complexType = complexType.getBaseType();
   422                 }
   423             }
   425             // use this as biclass for current component
   426             decl = lastFoundRecursiveBiClass;
   428         }
   430         BindInfo bindInfo = builder.getBindInfo(component);
   431         if(decl == null) {
   432             decl = bindInfo.get(BIClass.class);
   433             if(decl==null)  return null;
   434         }
   436         decl.markAsAcknowledged();
   438         // first consider binding to the class reference.
   439         String ref = decl.getExistingClassRef();
   440         if(ref!=null) {
   441             if(!JJavaName.isFullyQualifiedClassName(ref)) {
   442                 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
   443                     Messages.format(Messages.ERR_INCORRECT_CLASS_NAME,ref) );
   444                 // recover by ignoring @ref
   445             } else {
   446                 if(component instanceof XSComplexType) {
   447                     // UGLY UGLY UGLY
   448                     // since we are not going to bind this complex type, we need to figure out
   449                     // its binding mode without actually binding it (and also expose this otherwise
   450                     // hidden mechanism into this part of the code.)
   451                     //
   452                     // this code is potentially dangerous as the base class might have been bound
   453                     // in different ways. To be correct, we need to figure out how the content type
   454                     // would have been bound, from the schema.
   455                     Ring.get(ComplexTypeFieldBuilder.class).recordBindingMode(
   456                         (XSComplexType)component, ComplexTypeBindingMode.NORMAL
   457                     );
   458                 }
   459                 return new CClassRef(model, component, decl, bindInfo.toCustomizationList() );
   460             }
   461         }
   463         String clsName = decl.getClassName();
   464         if(clsName==null) {
   465             // if the customiztion doesn't give us a name, derive one
   466             // from the current component.
   467             if( defaultBaseName==null ) {
   468                 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
   469                     Messages.format(Messages.ERR_CLASS_NAME_IS_REQUIRED) );
   471                 // recover by generating a pseudo-random name
   472                 defaultBaseName = "undefined"+component.hashCode();
   473             }
   474             clsName = builder.deriveName( defaultBaseName, component );
   475         } else {
   476             if( !JJavaName.isJavaIdentifier(clsName) ) {
   477                 // not a valid Java class name
   478                 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
   479                     Messages.format( Messages.ERR_INCORRECT_CLASS_NAME, clsName ));
   480                 // recover by a dummy name
   481                 clsName = "Undefined"+component.hashCode();
   482             }
   483         }
   485         QName typeName = null;
   486         QName elementName = null;
   488         if(component instanceof XSType) {
   489             XSType t = (XSType) component;
   490             typeName = getName(t);
   491         }
   493         if (component instanceof XSElementDecl) {
   494             XSElementDecl e = (XSElementDecl) component;
   495             elementName = getName(e);
   496         }
   498         if (component instanceof XSElementDecl && !isCollapsable((XSElementDecl)component)) {
   499             XSElementDecl e = ((XSElementDecl)component);
   501             CElementInfo cei = new CElementInfo(model, elementName,
   502                     selector.getClassScope(), clsName,
   503                     bindInfo.toCustomizationList(), decl.getLocation() );
   504             selector.boundElements.put(e,cei);
   506             stb.refererStack.push(component);    // referer is element
   507             cei.initContentType(
   508                 selector.bindToType(e.getType(),e),
   509                 e,e.getDefaultValue());
   510             stb.refererStack.pop();
   511             return cei;
   512             // TODO: support javadoc and userSpecifiedImplClass
   513         } else {
   514             CClassInfo bt = new CClassInfo(model,selector.getClassScope(),
   515                     clsName, decl.getLocation(), typeName, elementName, component, bindInfo.toCustomizationList() );
   517             // set javadoc class comment.
   518             if(decl.getJavadoc()!=null )
   519                 bt.javadoc = decl.getJavadoc()+"\n\n";
   520                 // add extra blank lines so that the schema fragment
   521                 // and user-specified javadoc would be separated
   524             // if the implClass is given, set it to ClassItem
   525             String implClass = decl.getUserSpecifiedImplClass();
   526             if( implClass!=null )
   527                 bt.setUserSpecifiedImplClass( implClass );
   529             return bt;
   530         }
   531     }
   533     private BIGlobalBinding getGlobalBinding() {
   534         return builder.getGlobalBinding();
   535     }
   537     /**
   538      * Derives a name from a schema component.
   539      * Use the name of the schema component as the default name.
   540      */
   541     private String deriveName( XSDeclaration comp ) {
   542         return builder.deriveName( comp.getName(), comp );
   543     }
   545     /**
   546      * Derives a name from a schema component.
   547      * For complex types, we take redefinition into account when
   548      * deriving a default name.
   549      */
   550     private String deriveName( XSComplexType comp ) {
   551         String seed = builder.deriveName( comp.getName(), comp );
   552         int cnt = comp.getRedefinedCount();
   553         for( ; cnt>0; cnt-- )
   554             seed = "Original"+seed;
   555         return seed;
   556     }
   558 }

mercurial