src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/bean/ObjectFactoryGeneratorImpl.java

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

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
parent 0
373ffda63c9a
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.tools.internal.xjc.generator.bean;
    28 import java.util.Collection;
    29 import java.util.HashMap;
    30 import java.util.Map;
    32 import javax.xml.bind.JAXBException;
    33 import javax.xml.bind.annotation.XmlInlineBinaryData;
    34 import javax.xml.namespace.QName;
    36 import com.sun.codemodel.internal.JClass;
    37 import com.sun.codemodel.internal.JCodeModel;
    38 import com.sun.codemodel.internal.JDefinedClass;
    39 import com.sun.codemodel.internal.JExpr;
    40 import com.sun.codemodel.internal.JExpression;
    41 import com.sun.codemodel.internal.JFieldVar;
    42 import com.sun.codemodel.internal.JInvocation;
    43 import com.sun.codemodel.internal.JMethod;
    44 import com.sun.codemodel.internal.JMod;
    45 import com.sun.codemodel.internal.JPackage;
    46 import com.sun.codemodel.internal.JType;
    47 import com.sun.codemodel.internal.JVar;
    48 import com.sun.tools.internal.xjc.generator.annotation.spec.XmlElementDeclWriter;
    49 import com.sun.tools.internal.xjc.generator.annotation.spec.XmlRegistryWriter;
    50 import com.sun.tools.internal.xjc.model.CElementInfo;
    51 import com.sun.tools.internal.xjc.model.CPropertyInfo;
    52 import com.sun.tools.internal.xjc.model.Constructor;
    53 import com.sun.tools.internal.xjc.model.Model;
    54 import com.sun.tools.internal.xjc.outline.Aspect;
    55 import com.sun.tools.internal.xjc.outline.FieldAccessor;
    56 import com.sun.tools.internal.xjc.outline.FieldOutline;
    57 import com.sun.xml.internal.bind.v2.TODO;
    59 /**
    60  * Generates <code>ObjectFactory</code> then wraps it and provides
    61  * access to it.
    62  *
    63  * <p>
    64  * The ObjectFactory contains
    65  * factory methods for each schema derived content class
    66  *
    67  * @author
    68  *      Ryan Shoemaker
    69  */
    70 abstract class ObjectFactoryGeneratorImpl extends ObjectFactoryGenerator {
    72     private final BeanGenerator outline;
    73     private final Model model;
    74     private final JCodeModel codeModel;
    75     /**
    76      * Ref to {@link Class}.
    77      */
    78     private final JClass classRef;
    80     /**
    81      * Reference to the generated ObjectFactory class.
    82      */
    83     private final JDefinedClass objectFactory;
    85     /** map of qname to the QName constant field. */
    86     private final HashMap<QName,JFieldVar> qnameMap = new HashMap<QName,JFieldVar>();
    88     /**
    89      * Names of the element factory methods that are created.
    90      * Used to detect collisions.
    91      *
    92      * The value is used for reporting error locations.
    93      */
    94     private final Map<String,CElementInfo> elementFactoryNames = new HashMap<String,CElementInfo>();
    96     /**
    97      * Names of the value factory methods that are created.
    98      * Used to detect collisions.
    99      *
   100      * The value is used for reporting error locations.
   101      */
   102     private final Map<String,ClassOutlineImpl> valueFactoryNames = new HashMap<String,ClassOutlineImpl>();
   104     /**
   105      * Returns a reference to the generated (public) ObjectFactory
   106      */
   107     public JDefinedClass getObjectFactory() {
   108         return objectFactory;
   109     }
   114     public ObjectFactoryGeneratorImpl( BeanGenerator outline, Model model, JPackage targetPackage ) {
   115         this.outline = outline;
   116         this.model = model;
   117         this.codeModel = this.model.codeModel;
   118         this.classRef = codeModel.ref(Class.class);
   120         // create the ObjectFactory class skeleton
   121         objectFactory = this.outline.getClassFactory().createClass(
   122                 targetPackage, "ObjectFactory", null );
   123         objectFactory.annotate2(XmlRegistryWriter.class);
   125         // generate the default constructor
   126         //
   127         // m1 result:
   128         //        public ObjectFactory() {}
   129         JMethod m1 = objectFactory.constructor(JMod.PUBLIC);
   130         m1.javadoc().append("Create a new ObjectFactory that can be used to " +
   131                          "create new instances of schema derived classes " +
   132                          "for package: " + targetPackage.name());
   134         // add some class javadoc
   135         objectFactory.javadoc().append(
   136             "This object contains factory methods for each \n" +
   137             "Java content interface and Java element interface \n" +
   138             "generated in the " + targetPackage.name() + " package. \n" +
   139             "<p>An ObjectFactory allows you to programatically \n" +
   140             "construct new instances of the Java representation \n" +
   141             "for XML content. The Java representation of XML \n" +
   142             "content can consist of schema derived interfaces \n" +
   143             "and classes representing the binding of schema \n" +
   144             "type definitions, element declarations and model \n" +
   145             "groups.  Factory methods for each of these are \n" +
   146             "provided in this class." );
   148     }
   150     /**
   151      * Adds code for the given {@link CElementInfo} to ObjectFactory.
   152      */
   153     protected final void populate( CElementInfo ei, Aspect impl, Aspect exposed ) {
   154         JType exposedElementType = ei.toType(outline,exposed);
   155         JType exposedType = ei.getContentInMemoryType().toType(outline,exposed);
   156         JType implType = ei.getContentInMemoryType().toType(outline,impl);
   157         String namespaceURI = ei.getElementName().getNamespaceURI();
   158         String localPart = ei.getElementName().getLocalPart();
   160         JClass scope=null;
   161         if(ei.getScope()!=null)
   162             scope = outline.getClazz(ei.getScope()).implClass;
   165         JMethod m;
   167         if(ei.isAbstract()) {
   168             // TODO: see the "Abstract elements and mighty IXmlElement" e-mail
   169             // that I sent to jaxb-tech
   170             TODO.checkSpec();
   171         }
   173         {// collision check
   174             CElementInfo existing = elementFactoryNames.put(ei.getSqueezedName(),ei);
   175             if( existing!=null ) {
   176                 outline.getErrorReceiver().error(existing.getLocator(),
   177                     Messages.OBJECT_FACTORY_CONFLICT.format(ei.getSqueezedName()));
   178                 outline.getErrorReceiver().error(ei.getLocator(),
   179                     Messages.OBJECT_FACTORY_CONFLICT_RELATED.format());
   180                 return;
   181             }
   182         }
   184         // no arg constructor
   185         // [RESULT] if the element doesn't have its own class, something like:
   186         //
   187         //        @XmlElementMapping(uri = "", name = "foo")
   188         //        public JAXBElement<Foo> createFoo( Foo value ) {
   189         //            return new JAXBElement<Foo>(
   190         //                new QName("","foo"),(Class)FooImpl.class,scope,(FooImpl)value);
   191         //        }
   192         //        NOTE: when we generate value classes Foo==FooImpl
   193         //
   194         // [RESULT] otherwise
   195         //
   196         //        @XmlElementMapping(uri = "", name = "foo")
   197         //        public Foo createFoo( FooType value ) {
   198         //            return new Foo((FooTypeImpl)value);
   199         //        }
   200         //        NOTE: when we generate value classes FooType==FooTypeImpl
   201         //
   202         // to deal with
   203         //  new JAXBElement<List<String>>( ..., List.class, ... );
   204         // we sometimes have to produce (Class)List.class instead of just List.class
   206         m = objectFactory.method( JMod.PUBLIC, exposedElementType, "create" + ei.getSqueezedName() );
   207         JVar $value = m.param(exposedType,"value");
   209         JExpression declaredType;
   210         if(implType.boxify().isParameterized() || !exposedType.equals(implType))
   211             declaredType = JExpr.cast(classRef,implType.boxify().dotclass());
   212         else
   213             declaredType = implType.boxify().dotclass();
   214         JExpression scopeClass = scope==null?JExpr._null():scope.dotclass();
   216         // build up the return extpression
   217         JInvocation exp = JExpr._new(exposedElementType);
   218         if(!ei.hasClass()) {
   219             exp.arg(getQNameInvocation(ei));
   220             exp.arg(declaredType);
   221             exp.arg(scopeClass);
   222         }
   223         if(implType==exposedType)
   224             exp.arg($value);
   225         else
   226             exp.arg(JExpr.cast(implType,$value));
   228         m.body()._return( exp );
   230         m.javadoc()
   231             .append("Create an instance of ")
   232             .append(exposedElementType)
   233             .append("}");
   235         XmlElementDeclWriter xemw = m.annotate2(XmlElementDeclWriter.class);
   236         xemw.namespace(namespaceURI).name(localPart);
   237         if(scope!=null)
   238             xemw.scope(scope);
   240         if(ei.getSubstitutionHead()!=null) {
   241             QName n = ei.getSubstitutionHead().getElementName();
   242             xemw.substitutionHeadNamespace(n.getNamespaceURI());
   243             xemw.substitutionHeadName(n.getLocalPart());
   244         }
   246         if(ei.getDefaultValue()!=null)
   247             xemw.defaultValue(ei.getDefaultValue());
   249         if(ei.getProperty().inlineBinaryData())
   250             m.annotate(XmlInlineBinaryData.class);
   252                     // if the element is adapter, put that annotation on the factory method
   253         outline.generateAdapterIfNecessary(ei.getProperty(),m);
   254     }
   256     /**
   257      * return a JFieldVar that represents the QName field for the given information.
   258      *
   259      * if it doesn't exist, create a static field in the class and store a new JFieldVar.
   260      */
   261     private JExpression getQNameInvocation(CElementInfo ei) {
   262         QName name = ei.getElementName();
   263         if(qnameMap.containsKey(name)) {
   264             return qnameMap.get(name);
   265         }
   267         if(qnameMap.size()>1024)
   268             // stop gap measure to avoid 'code too large' error in javac.
   269             return createQName(name);
   271         // [RESULT]
   272         // private static final QName _XYZ_NAME = new QName("uri", "local");
   273         JFieldVar qnameField = objectFactory.field(
   274             JMod.PRIVATE | JMod.STATIC | JMod.FINAL,
   275             QName.class,
   276             '_' + ei.getSqueezedName() + "_QNAME", createQName(name));
   278         qnameMap.put(name, qnameField);
   280         return qnameField;
   281     }
   283     /**
   284      * Generates an expression that evaluates to "new QName(...)"
   285      */
   286     private JInvocation createQName(QName name) {
   287         return JExpr._new(codeModel.ref(QName.class)).arg(name.getNamespaceURI()).arg(name.getLocalPart());
   288     }
   290     protected final void populate( ClassOutlineImpl cc, JClass sigType ) {
   291         // add static factory method for this class to JAXBContext.
   292         //
   293         // generate methods like:
   294         //     public static final SIGTYPE createFoo() {
   295         //         return new FooImpl();
   296         //     }
   298         if(!cc.target.isAbstract()) {
   299             JMethod m = objectFactory.method(
   300                 JMod.PUBLIC, sigType, "create" + cc.target.getSqueezedName() );
   301             m.body()._return( JExpr._new(cc.implRef) );
   303             // add some jdoc to avoid javadoc warnings in jdk1.4
   304             m.javadoc()
   305                 .append("Create an instance of ")
   306                 .append(cc.ref);
   307         }
   310         // add static factory methods for all the other constructors.
   311         Collection<? extends Constructor> consl = cc.target.getConstructors();
   312         if(consl.size()!=0) {
   313             // if we are going to add constructors with parameters,
   314             // first we need to have a default constructor.
   315             cc.implClass.constructor(JMod.PUBLIC);
   316         }
   318         {// collision check
   319             String name = cc.target.getSqueezedName();
   320             ClassOutlineImpl existing = valueFactoryNames.put(name,cc);
   321             if( existing!=null ) {
   322                 outline.getErrorReceiver().error(existing.target.getLocator(),
   323                     Messages.OBJECT_FACTORY_CONFLICT.format(name));
   324                 outline.getErrorReceiver().error(cc.target.getLocator(),
   325                     Messages.OBJECT_FACTORY_CONFLICT_RELATED.format());
   326                 return;
   327             }
   328         }
   330         for( Constructor cons : consl ) {
   331             // method on ObjectFactory
   332             // [RESULT]
   333             // Foo createFoo( T1 a, T2 b, T3 c, ... ) throws JAXBException {
   334             //    return new FooImpl(a,b,c,...);
   335             // }
   336             JMethod m = objectFactory.method( JMod.PUBLIC,
   337                 cc.ref, "create" + cc.target.getSqueezedName() );
   338             JInvocation inv = JExpr._new(cc.implRef);
   339             m.body()._return(inv);
   341             // let's not throw this exception.
   342             // m._throws(codeModel.ref(JAXBException.class));
   344             // add some jdoc to avoid javadoc warnings in jdk1.4
   345             m.javadoc()
   346                 .append( "Create an instance of " )
   347                 .append( cc.ref )
   348                 .addThrows(JAXBException.class).append("if an error occurs");
   350             // constructor
   351             // [RESULT]
   352             // FooImpl( T1 a, T2 b, T3 c, ... ) {
   353             // }
   354             JMethod c = cc.implClass.constructor(JMod.PUBLIC);
   356             for( String fieldName : cons.fields ) {
   357                 CPropertyInfo field = cc.target.getProperty(fieldName);
   358                 if(field==null) {
   359                     outline.getErrorReceiver().error(cc.target.getLocator(),
   360                         Messages.ILLEGAL_CONSTRUCTOR_PARAM.format(fieldName));
   361                     continue;
   362                 }
   364                 fieldName = camelize(fieldName);
   366                 FieldOutline fo = outline.getField(field);
   367                 FieldAccessor accessor = fo.create(JExpr._this());
   369                 // declare a parameter on this factory method and set
   370                 // it to the field
   371                 inv.arg(m.param( fo.getRawType(), fieldName ));
   373                 JVar $var = c.param( fo.getRawType(), fieldName );
   374                 accessor.fromRawValue(c.body(),'_'+fieldName,$var);
   375             }
   376         }
   377     }
   380     /** Change the first character to the lower case. */
   381     private static String camelize( String s ) {
   382         return Character.toLowerCase(s.charAt(0)) + s.substring(1);
   383     }
   384 }

mercurial