src/share/jaxws_classes/com/sun/codemodel/internal/JCodeModel.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, 2010, 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.codemodel.internal;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.io.PrintStream;
    31 import java.lang.reflect.Modifier;
    32 import java.util.ArrayList;
    33 import java.util.Collections;
    34 import java.util.HashMap;
    35 import java.util.Iterator;
    36 import java.util.List;
    37 import java.util.Map;
    39 import com.sun.codemodel.internal.writer.FileCodeWriter;
    40 import com.sun.codemodel.internal.writer.ProgressCodeWriter;
    43 /**
    44  * Root of the code DOM.
    45  *
    46  * <p>
    47  * Here's your typical CodeModel application.
    48  *
    49  * <pre>
    50  * JCodeModel cm = new JCodeModel();
    51  *
    52  * // generate source code by populating the 'cm' tree.
    53  * cm._class(...);
    54  * ...
    55  *
    56  * // write them out
    57  * cm.build(new File("."));
    58  * </pre>
    59  *
    60  * <p>
    61  * Every CodeModel node is always owned by one {@link JCodeModel} object
    62  * at any given time (which can be often accesesd by the <tt>owner()</tt> method.)
    63  *
    64  * As such, when you generate Java code, most of the operation works
    65  * in a top-down fashion. For example, you create a class from {@link JCodeModel},
    66  * which gives you a {@link JDefinedClass}. Then you invoke a method on it
    67  * to generate a new method, which gives you {@link JMethod}, and so on.
    68  *
    69  * There are a few exceptions to this, most notably building {@link JExpression}s,
    70  * but generally you work with CodeModel in a top-down fashion.
    71  *
    72  * Because of this design, most of the CodeModel classes aren't directly instanciable.
    73  *
    74  *
    75  * <h2>Where to go from here?</h2>
    76  * <p>
    77  * Most of the time you'd want to populate new type definitions in a {@link JCodeModel}.
    78  * See {@link #_class(String, ClassType)}.
    79  */
    80 public final class JCodeModel {
    82     /** The packages that this JCodeWriter contains. */
    83     private HashMap<String,JPackage> packages = new HashMap<String,JPackage>();
    85     /** All JReferencedClasses are pooled here. */
    86     private final HashMap<Class<?>,JReferencedClass> refClasses = new HashMap<Class<?>,JReferencedClass>();
    89     /** Obtains a reference to the special "null" type. */
    90     public final JNullType NULL = new JNullType(this);
    91     // primitive types
    92     public final JPrimitiveType VOID    = new JPrimitiveType(this,"void",   Void.class);
    93     public final JPrimitiveType BOOLEAN = new JPrimitiveType(this,"boolean",Boolean.class);
    94     public final JPrimitiveType BYTE    = new JPrimitiveType(this,"byte",   Byte.class);
    95     public final JPrimitiveType SHORT   = new JPrimitiveType(this,"short",  Short.class);
    96     public final JPrimitiveType CHAR    = new JPrimitiveType(this,"char",   Character.class);
    97     public final JPrimitiveType INT     = new JPrimitiveType(this,"int",    Integer.class);
    98     public final JPrimitiveType FLOAT   = new JPrimitiveType(this,"float",  Float.class);
    99     public final JPrimitiveType LONG    = new JPrimitiveType(this,"long",   Long.class);
   100     public final JPrimitiveType DOUBLE  = new JPrimitiveType(this,"double", Double.class);
   102     /**
   103      * If the flag is true, we will consider two classes "Foo" and "foo"
   104      * as a collision.
   105      */
   106     protected static final boolean isCaseSensitiveFileSystem = getFileSystemCaseSensitivity();
   108     private static boolean getFileSystemCaseSensitivity() {
   109         try {
   110             // let the system property override, in case the user really
   111             // wants to override.
   112             if( System.getProperty("com.sun.codemodel.internal.FileSystemCaseSensitive")!=null )
   113                 return true;
   114         } catch( Exception e ) {}
   116         // on Unix, it's case sensitive.
   117         return (File.separatorChar == '/');
   118     }
   121     public JCodeModel() {}
   123     /**
   124      * Add a package to the list of packages to be generated
   125      *
   126      * @param name
   127      *        Name of the package. Use "" to indicate the root package.
   128      *
   129      * @return Newly generated package
   130      */
   131     public JPackage _package(String name) {
   132         JPackage p = packages.get(name);
   133         if (p == null) {
   134             p = new JPackage(name, this);
   135             packages.put(name, p);
   136         }
   137         return p;
   138     }
   140     public final JPackage rootPackage() {
   141         return _package("");
   142     }
   144     /**
   145      * Returns an iterator that walks the packages defined using this code
   146      * writer.
   147      */
   148     public Iterator<JPackage> packages() {
   149         return packages.values().iterator();
   150     }
   152     /**
   153      * Creates a new generated class.
   154      *
   155      * @exception JClassAlreadyExistsException
   156      *      When the specified class/interface was already created.
   157      */
   158     public JDefinedClass _class(String fullyqualifiedName) throws JClassAlreadyExistsException {
   159         return _class(fullyqualifiedName,ClassType.CLASS);
   160     }
   162     /**
   163      * Creates a dummy, unknown {@link JClass} that represents a given name.
   164      *
   165      * <p>
   166      * This method is useful when the code generation needs to include the user-specified
   167      * class that may or may not exist, and only thing known about it is a class name.
   168      */
   169     public JClass directClass(String name) {
   170         return new JDirectClass(this,name);
   171     }
   173     /**
   174      * Creates a new generated class.
   175      *
   176      * @exception JClassAlreadyExistsException
   177      *      When the specified class/interface was already created.
   178      */
   179     public JDefinedClass _class(int mods, String fullyqualifiedName,ClassType t) throws JClassAlreadyExistsException {
   180         int idx = fullyqualifiedName.lastIndexOf('.');
   181         if( idx<0 )     return rootPackage()._class(fullyqualifiedName);
   182         else
   183             return _package(fullyqualifiedName.substring(0,idx))
   184                 ._class(mods, fullyqualifiedName.substring(idx+1), t );
   185     }
   187     /**
   188      * Creates a new generated class.
   189      *
   190      * @exception JClassAlreadyExistsException
   191      *      When the specified class/interface was already created.
   192      */
   193     public JDefinedClass _class(String fullyqualifiedName,ClassType t) throws JClassAlreadyExistsException {
   194         return _class( JMod.PUBLIC, fullyqualifiedName, t );
   195     }
   197     /**
   198      * Gets a reference to the already created generated class.
   199      *
   200      * @return null
   201      *      If the class is not yet created.
   202      * @see JPackage#_getClass(String)
   203      */
   204     public JDefinedClass _getClass(String fullyQualifiedName) {
   205         int idx = fullyQualifiedName.lastIndexOf('.');
   206         if( idx<0 )     return rootPackage()._getClass(fullyQualifiedName);
   207         else
   208             return _package(fullyQualifiedName.substring(0,idx))
   209                 ._getClass( fullyQualifiedName.substring(idx+1) );
   210     }
   212     /**
   213      * Creates a new anonymous class.
   214      *
   215      * @deprecated
   216      *      The naming convention doesn't match the rest of the CodeModel.
   217      *      Use {@link #anonymousClass(JClass)} instead.
   218      */
   219     public JDefinedClass newAnonymousClass(JClass baseType) {
   220         return new JAnonymousClass(baseType);
   221     }
   223     /**
   224      * Creates a new anonymous class.
   225      */
   226     public JDefinedClass anonymousClass(JClass baseType) {
   227         return new JAnonymousClass(baseType);
   228     }
   230     public JDefinedClass anonymousClass(Class<?> baseType) {
   231         return anonymousClass(ref(baseType));
   232     }
   234     /**
   235      * Generates Java source code.
   236      * A convenience method for <code>build(destDir,destDir,System.out)</code>.
   237      *
   238      * @param   destDir
   239      *          source files are generated into this directory.
   240      * @param   status
   241      *      if non-null, progress indication will be sent to this stream.
   242      */
   243     public void build( File destDir, PrintStream status ) throws IOException {
   244         build(destDir,destDir,status);
   245     }
   247     /**
   248      * Generates Java source code.
   249      * A convenience method that calls {@link #build(CodeWriter,CodeWriter)}.
   250      *
   251      * @param   srcDir
   252      *          Java source files are generated into this directory.
   253      * @param   resourceDir
   254      *          Other resource files are generated into this directory.
   255      * @param   status
   256      *      if non-null, progress indication will be sent to this stream.
   257      */
   258     public void build( File srcDir, File resourceDir, PrintStream status ) throws IOException {
   259         CodeWriter src = new FileCodeWriter(srcDir);
   260         CodeWriter res = new FileCodeWriter(resourceDir);
   261         if(status!=null) {
   262             src = new ProgressCodeWriter(src, status );
   263             res = new ProgressCodeWriter(res, status );
   264         }
   265         build(src,res);
   266     }
   268     /**
   269      * A convenience method for <code>build(destDir,System.out)</code>.
   270      */
   271     public void build( File destDir ) throws IOException {
   272         build(destDir,System.out);
   273     }
   275     /**
   276      * A convenience method for <code>build(srcDir,resourceDir,System.out)</code>.
   277      */
   278     public void build( File srcDir, File resourceDir ) throws IOException {
   279         build(srcDir,resourceDir,System.out);
   280     }
   282     /**
   283      * A convenience method for <code>build(out,out)</code>.
   284      */
   285     public void build( CodeWriter out ) throws IOException {
   286         build(out,out);
   287     }
   289     /**
   290      * Generates Java source code.
   291      */
   292     public void build( CodeWriter source, CodeWriter resource ) throws IOException {
   293         JPackage[] pkgs = packages.values().toArray(new JPackage[packages.size()]);
   294         // avoid concurrent modification exception
   295         for( JPackage pkg : pkgs )
   296             pkg.build(source,resource);
   297         source.close();
   298         resource.close();
   299     }
   301     /**
   302      * Returns the number of files to be generated if
   303      * {@link #build} is invoked now.
   304      */
   305     public int countArtifacts() {
   306         int r = 0;
   307         JPackage[] pkgs = packages.values().toArray(new JPackage[packages.size()]);
   308         // avoid concurrent modification exception
   309         for( JPackage pkg : pkgs )
   310             r += pkg.countArtifacts();
   311         return r;
   312     }
   315     /**
   316      * Obtains a reference to an existing class from its Class object.
   317      *
   318      * <p>
   319      * The parameter may not be primitive.
   320      *
   321      * @see #_ref(Class) for the version that handles more cases.
   322      */
   323     public JClass ref(Class<?> clazz) {
   324         JReferencedClass jrc = (JReferencedClass)refClasses.get(clazz);
   325         if (jrc == null) {
   326             if (clazz.isPrimitive())
   327                 throw new IllegalArgumentException(clazz+" is a primitive");
   328             if (clazz.isArray()) {
   329                 return new JArrayClass(this, _ref(clazz.getComponentType()));
   330             } else {
   331                 jrc = new JReferencedClass(clazz);
   332                 refClasses.put(clazz, jrc);
   333             }
   334         }
   335         return jrc;
   336     }
   338     public JType _ref(Class<?> c) {
   339         if(c.isPrimitive())
   340             return JType.parse(this,c.getName());
   341         else
   342             return ref(c);
   343     }
   345     /**
   346      * Obtains a reference to an existing class from its fully-qualified
   347      * class name.
   348      *
   349      * <p>
   350      * First, this method attempts to load the class of the given name.
   351      * If that fails, we assume that the class is derived straight from
   352      * {@link Object}, and return a {@link JClass}.
   353      */
   354     public JClass ref(String fullyQualifiedClassName) {
   355         try {
   356             // try the context class loader first
   357             return ref(SecureLoader.getContextClassLoader().loadClass(fullyQualifiedClassName));
   358         } catch (ClassNotFoundException e) {
   359             // fall through
   360         }
   361         // then the default mechanism.
   362         try {
   363             return ref(Class.forName(fullyQualifiedClassName));
   364         } catch (ClassNotFoundException e1) {
   365             // fall through
   366         }
   368         // assume it's not visible to us.
   369         return new JDirectClass(this,fullyQualifiedClassName);
   370     }
   372     /**
   373      * Cached for {@link #wildcard()}.
   374      */
   375     private JClass wildcard;
   377     /**
   378      * Gets a {@link JClass} representation for "?",
   379      * which is equivalent to "? extends Object".
   380      */
   381     public JClass wildcard() {
   382         if(wildcard==null)
   383             wildcard = ref(Object.class).wildcard();
   384         return wildcard;
   385     }
   387     /**
   388      * Obtains a type object from a type name.
   389      *
   390      * <p>
   391      * This method handles primitive types, arrays, and existing {@link Class}es.
   392      *
   393      * @exception ClassNotFoundException
   394      *      If the specified type is not found.
   395      */
   396     public JType parseType(String name) throws ClassNotFoundException {
   397         // array
   398         if(name.endsWith("[]"))
   399             return parseType(name.substring(0,name.length()-2)).array();
   401         // try primitive type
   402         try {
   403             return JType.parse(this,name);
   404         } catch (IllegalArgumentException e) {
   405             ;
   406         }
   408         // existing class
   409         return new TypeNameParser(name).parseTypeName();
   410     }
   412     private final class TypeNameParser {
   413         private final String s;
   414         private int idx;
   416         public TypeNameParser(String s) {
   417             this.s = s;
   418         }
   420         /**
   421          * Parses a type name token T (which can be potentially of the form Tr&ly;T1,T2,...>,
   422          * or "? extends/super T".)
   423          *
   424          * @return the index of the character next to T.
   425          */
   426         JClass parseTypeName() throws ClassNotFoundException {
   427             int start = idx;
   429             if(s.charAt(idx)=='?') {
   430                 // wildcard
   431                 idx++;
   432                 ws();
   433                 String head = s.substring(idx);
   434                 if(head.startsWith("extends")) {
   435                     idx+=7;
   436                     ws();
   437                     return parseTypeName().wildcard();
   438                 } else
   439                 if(head.startsWith("super")) {
   440                     throw new UnsupportedOperationException("? super T not implemented");
   441                 } else {
   442                     // not supported
   443                     throw new IllegalArgumentException("only extends/super can follow ?, but found "+s.substring(idx));
   444                 }
   445             }
   447             while(idx<s.length()) {
   448                 char ch = s.charAt(idx);
   449                 if(Character.isJavaIdentifierStart(ch)
   450                 || Character.isJavaIdentifierPart(ch)
   451                 || ch=='.')
   452                     idx++;
   453                 else
   454                     break;
   455             }
   457             JClass clazz = ref(s.substring(start,idx));
   459             return parseSuffix(clazz);
   460         }
   462         /**
   463          * Parses additional left-associative suffixes, like type arguments
   464          * and array specifiers.
   465          */
   466         private JClass parseSuffix(JClass clazz) throws ClassNotFoundException {
   467             if(idx==s.length())
   468                 return clazz; // hit EOL
   470             char ch = s.charAt(idx);
   472             if(ch=='<')
   473                 return parseSuffix(parseArguments(clazz));
   475             if(ch=='[') {
   476                 if(s.charAt(idx+1)==']') {
   477                     idx+=2;
   478                     return parseSuffix(clazz.array());
   479                 }
   480                 throw new IllegalArgumentException("Expected ']' but found "+s.substring(idx+1));
   481             }
   483             return clazz;
   484         }
   486         /**
   487          * Skips whitespaces
   488          */
   489         private void ws() {
   490             while(Character.isWhitespace(s.charAt(idx)) && idx<s.length())
   491                 idx++;
   492         }
   494         /**
   495          * Parses '&lt;T1,T2,...,Tn>'
   496          *
   497          * @return the index of the character next to '>'
   498          */
   499         private JClass parseArguments(JClass rawType) throws ClassNotFoundException {
   500             if(s.charAt(idx)!='<')
   501                 throw new IllegalArgumentException();
   502             idx++;
   504             List<JClass> args = new ArrayList<JClass>();
   506             while(true) {
   507                 args.add(parseTypeName());
   508                 if(idx==s.length())
   509                     throw new IllegalArgumentException("Missing '>' in "+s);
   510                 char ch = s.charAt(idx);
   511                 if(ch=='>')
   512                     return rawType.narrow(args.toArray(new JClass[args.size()]));
   514                 if(ch!=',')
   515                     throw new IllegalArgumentException(s);
   516                 idx++;
   517             }
   519         }
   520     }
   522     /**
   523      * References to existing classes.
   524      *
   525      * <p>
   526      * JReferencedClass is kept in a pool so that they are shared.
   527      * There is one pool for each JCodeModel object.
   528      *
   529      * <p>
   530      * It is impossible to cache JReferencedClass globally only because
   531      * there is the _package() method, which obtains the owner JPackage
   532      * object, which is scoped to JCodeModel.
   533      */
   534     private class JReferencedClass extends JClass implements JDeclaration {
   535         private final Class<?> _class;
   537         JReferencedClass(Class<?> _clazz) {
   538             super(JCodeModel.this);
   539             this._class = _clazz;
   540             assert !_class.isArray();
   541         }
   543         public String name() {
   544             return _class.getSimpleName().replace('$','.');
   545         }
   547         public String fullName() {
   548             return _class.getName().replace('$','.');
   549         }
   551         public String binaryName() {
   552             return _class.getName();
   553         }
   555         public JClass outer() {
   556             Class<?> p = _class.getDeclaringClass();
   557             if(p==null)     return null;
   558             return ref(p);
   559         }
   561         public JPackage _package() {
   562             String name = fullName();
   564             // this type is array
   565             if (name.indexOf('[') != -1)
   566                 return JCodeModel.this._package("");
   568             // other normal case
   569             int idx = name.lastIndexOf('.');
   570             if (idx < 0)
   571                 return JCodeModel.this._package("");
   572             else
   573                 return JCodeModel.this._package(name.substring(0, idx));
   574         }
   576         public JClass _extends() {
   577             Class<?> sp = _class.getSuperclass();
   578             if (sp == null) {
   579                 if(isInterface())
   580                     return owner().ref(Object.class);
   581                 return null;
   582             } else
   583                 return ref(sp);
   584         }
   586         public Iterator<JClass> _implements() {
   587             final Class<?>[] interfaces = _class.getInterfaces();
   588             return new Iterator<JClass>() {
   589                 private int idx = 0;
   590                 public boolean hasNext() {
   591                     return idx < interfaces.length;
   592                 }
   593                 public JClass next() {
   594                     return JCodeModel.this.ref(interfaces[idx++]);
   595                 }
   596                 public void remove() {
   597                     throw new UnsupportedOperationException();
   598                 }
   599             };
   600         }
   602         public boolean isInterface() {
   603             return _class.isInterface();
   604         }
   606         public boolean isAbstract() {
   607             return Modifier.isAbstract(_class.getModifiers());
   608         }
   610         public JPrimitiveType getPrimitiveType() {
   611             Class<?> v = boxToPrimitive.get(_class);
   612             if(v!=null)
   613                 return JType.parse(JCodeModel.this,v.getName());
   614             else
   615                 return null;
   616         }
   618         public boolean isArray() {
   619             return false;
   620         }
   622         public void declare(JFormatter f) {
   623         }
   625         public JTypeVar[] typeParams() {
   626             // TODO: does JDK 1.5 reflection provides these information?
   627             return super.typeParams();
   628         }
   630         protected JClass substituteParams(JTypeVar[] variables, List<JClass> bindings) {
   631             // TODO: does JDK 1.5 reflection provides these information?
   632             return this;
   633         }
   634     }
   636     /**
   637      * Conversion from primitive type {@link Class} (such as {@link Integer#TYPE}
   638      * to its boxed type (such as <tt>Integer.class</tt>)
   639      */
   640     public static final Map<Class<?>,Class<?>> primitiveToBox;
   641     /**
   642      * The reverse look up for {@link #primitiveToBox}
   643      */
   644     public static final Map<Class<?>,Class<?>> boxToPrimitive;
   646     static {
   647         Map<Class<?>,Class<?>> m1 = new HashMap<Class<?>,Class<?>>();
   648         Map<Class<?>,Class<?>> m2 = new HashMap<Class<?>,Class<?>>();
   650         m1.put(Boolean.class,Boolean.TYPE);
   651         m1.put(Byte.class,Byte.TYPE);
   652         m1.put(Character.class,Character.TYPE);
   653         m1.put(Double.class,Double.TYPE);
   654         m1.put(Float.class,Float.TYPE);
   655         m1.put(Integer.class,Integer.TYPE);
   656         m1.put(Long.class,Long.TYPE);
   657         m1.put(Short.class,Short.TYPE);
   658         m1.put(Void.class,Void.TYPE);
   660         for (Map.Entry<Class<?>, Class<?>> e : m1.entrySet())
   661             m2.put(e.getValue(),e.getKey());
   663         boxToPrimitive = Collections.unmodifiableMap(m1);
   664         primitiveToBox = Collections.unmodifiableMap(m2);
   666     }
   667 }

mercurial