src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/TypeUtil.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, 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;
    28 import java.util.ArrayList;
    29 import java.util.Collection;
    30 import java.util.Comparator;
    31 import java.util.Iterator;
    32 import java.util.List;
    33 import java.util.Set;
    34 import java.util.TreeSet;
    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.JType;
    40 import com.sun.tools.internal.xjc.ErrorReceiver;
    42 import org.xml.sax.Locator;
    43 import org.xml.sax.SAXParseException;
    45 /**
    46  * Type-related utility methods.
    47  *
    48  * @author
    49  *    <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
    50  */
    51 public class TypeUtil {
    54     /**
    55      * Computes the common base type of two types.
    56      *
    57      * @param types
    58      *      set of {@link JType} objects.
    59      */
    60     public static JType getCommonBaseType( JCodeModel codeModel, Collection<? extends JType> types ) {
    61         return getCommonBaseType( codeModel, types.toArray(new JType[types.size()]) );
    62     }
    64     /**
    65      * Computes the common base type of types.
    66      *
    67      * TODO: this is a very interesting problem. Since one type has possibly
    68      * multiple base types, it's not an easy problem.
    69      * The current implementation is very naive.
    70      *
    71      * To make the result deterministic across differente JVMs, we have to
    72      * use a Set whose ordering is deterministic.
    73      */
    74     public static JType getCommonBaseType(JCodeModel codeModel, JType... t) {
    75         // first, eliminate duplicates.
    76         Set<JType> uniqueTypes = new TreeSet<JType>(typeComparator);
    77         for (JType type : t)
    78             uniqueTypes.add(type);
    80         // if this yields only one type. return now.
    81         // this is the only case where we can return a primitive type
    82         // from this method
    83         if (uniqueTypes.size() == 1)
    84             return uniqueTypes.iterator().next();
    86         // assertion failed. nullType can be used only under a very special circumstance
    87         assert !uniqueTypes.isEmpty();
    89         // the null type doesn't need to be taken into account.
    90         uniqueTypes.remove(codeModel.NULL);
    92         // box all the types and compute the intersection of all types
    93         Set<JClass> s = null;
    95         for (JType type : uniqueTypes) {
    96             JClass cls = type.boxify();
    98             if (s == null)
    99                 s = getAssignableTypes(cls);
   100             else
   101                 s.retainAll(getAssignableTypes(cls));
   102         }
   104         // any JClass can be casted to Object, so make sure it's always there
   105         s.add( codeModel.ref(Object.class));
   107         // refine 's' by removing "lower" types.
   108         // for example, if we have both java.lang.Object and
   109         // java.io.InputStream, then we don't want to use java.lang.Object.
   111         JClass[] raw = s.toArray(new JClass[s.size()]);
   112         s.clear();
   114         for (int i = 0; i < raw.length; i++) { // for each raw[i]
   115             int j;
   116             for (j = 0; j < raw.length; j++) { // see if raw[j] "includes" raw[i]
   117                 if (i == j)
   118                     continue;
   120                 if (raw[i].isAssignableFrom(raw[j]))
   121                     break; // raw[j] is derived from raw[i], hence j includes i.
   122             }
   124             if (j == raw.length)
   125                 // no other type inclueds raw[i]. remember this value.
   126                 s.add(raw[i]);
   127         }
   129         assert !s.isEmpty(); // since at least java.lang.Object has to be there
   131         // we now pick the candidate for the return type
   132         JClass result = pickOne(s);
   134         // finally, sometimes this method is used to compute the base type of types like
   135         // JAXBElement<A>, JAXBElement<B>, and JAXBElement<C>.
   136         // for those inputs, at this point result=JAXBElement.
   137         //
   138         // here, we'll try to figure out the parameterization
   139         // so that we can return JAXBElement<? extends D> instead of just "JAXBElement".
   140         if(result.isParameterized())
   141             return result;
   143         // for each uniqueType we store the list of base type parameterization
   144         List<List<JClass>> parameters = new ArrayList<List<JClass>>(uniqueTypes.size());
   145         int paramLen = -1;
   147         for (JType type : uniqueTypes) {
   148             JClass cls = type.boxify();
   149             JClass bp = cls.getBaseClass(result);
   150             // if there's no parameterization in the base type,
   151             // we won't do any better than <?>. Thus no point in trying to figure out the parameterization.
   152             // just return the base type.
   153             if(bp.equals(result))
   154                 return result;
   156             assert bp.isParameterized();
   157             List<JClass> tp = bp.getTypeParameters();
   158             parameters.add(tp);
   160             assert paramLen==-1 || paramLen==tp.size();
   161                 // since 'bp' always is a parameterized version of 'result', it should always
   162                 // have the same number of parameters.
   163             paramLen = tp.size();
   164         }
   166         List<JClass> paramResult = new ArrayList<JClass>();
   167         List<JClass> argList = new ArrayList<JClass>(parameters.size());
   168         // for each type parameter compute the common base type
   169         for( int i=0; i<paramLen; i++ ) {
   170             argList.clear();
   171             for (List<JClass> list : parameters)
   172                 argList.add(list.get(i));
   174             // compute the lower bound.
   175             JClass bound = (JClass)getCommonBaseType(codeModel,argList);
   176             boolean allSame = true;
   177             for (JClass a : argList)
   178                 allSame &= a.equals(bound);
   179             if(!allSame)
   180                 bound = bound.wildcard();
   182             paramResult.add(bound);
   183         }
   185         return result.narrow(paramResult);
   186     }
   188     private static JClass pickOne(Set<JClass> s) {
   189         // we may have more than one candidates at this point.
   190         // any user-defined generated types should have
   191         // precedence over system-defined existing types.
   192         //
   193         // so try to return such a type if any.
   194         for (JClass c : s)
   195             if (c instanceof JDefinedClass)
   196                 return c;
   198         // we can do more if we like. for example,
   199         // we can avoid types in the RI runtime.
   200         // but for now, just return the first one.
   201         return s.iterator().next();
   202     }
   204     private static Set<JClass> getAssignableTypes( JClass t ) {
   205         Set<JClass> r = new TreeSet<JClass>(typeComparator);
   206         getAssignableTypes(t,r);
   207         return r;
   208     }
   210     /**
   211      * Returns the set of all classes/interfaces that a given type
   212      * implements/extends, including itself.
   213      *
   214      * For example, if you pass java.io.FilterInputStream, then the returned
   215      * set will contain java.lang.Object, java.lang.InputStream, and
   216      * java.lang.FilterInputStream.
   217      */
   218     private static void getAssignableTypes( JClass t, Set<JClass> s ) {
   219         if(!s.add(t))
   220             return;
   222         // add its raw type
   223         s.add(t.erasure());
   225         // if this type is added for the first time,
   226         // recursively process the super class.
   227         JClass _super = t._extends();
   228         if(_super!=null)
   229             getAssignableTypes(_super,s);
   231         // recursively process all implemented interfaces
   232         Iterator<JClass> itr = t._implements();
   233         while(itr.hasNext())
   234             getAssignableTypes(itr.next(),s);
   235     }
   237     /**
   238      * Obtains a {@link JType} object for the string representation
   239      * of a type.
   240      */
   241     public static JType getType( JCodeModel codeModel,
   242         String typeName, ErrorReceiver errorHandler, Locator errorSource ) {
   244         try {
   245             return codeModel.parseType(typeName);
   246         } catch( ClassNotFoundException ee ) {
   248             // make it a warning
   249             errorHandler.warning( new SAXParseException(
   250                 Messages.ERR_CLASS_NOT_FOUND.format(typeName)
   251                 ,errorSource));
   253             // recover by assuming that it's a class that derives from Object
   254             return codeModel.directClass(typeName);
   255         }
   256     }
   258     /**
   259      * Compares {@link JType} objects by their names.
   260      */
   261     private static final Comparator<JType> typeComparator = new Comparator<JType>() {
   262         public int compare(JType t1, JType t2) {
   263             return t1.fullName().compareTo(t2.fullName());
   264         }
   265     };
   266 }

mercurial