1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/TypeUtil.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,266 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.internal.xjc.reader; 1.30 + 1.31 +import java.util.ArrayList; 1.32 +import java.util.Collection; 1.33 +import java.util.Comparator; 1.34 +import java.util.Iterator; 1.35 +import java.util.List; 1.36 +import java.util.Set; 1.37 +import java.util.TreeSet; 1.38 + 1.39 +import com.sun.codemodel.internal.JClass; 1.40 +import com.sun.codemodel.internal.JCodeModel; 1.41 +import com.sun.codemodel.internal.JDefinedClass; 1.42 +import com.sun.codemodel.internal.JType; 1.43 +import com.sun.tools.internal.xjc.ErrorReceiver; 1.44 + 1.45 +import org.xml.sax.Locator; 1.46 +import org.xml.sax.SAXParseException; 1.47 + 1.48 +/** 1.49 + * Type-related utility methods. 1.50 + * 1.51 + * @author 1.52 + * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> 1.53 + */ 1.54 +public class TypeUtil { 1.55 + 1.56 + 1.57 + /** 1.58 + * Computes the common base type of two types. 1.59 + * 1.60 + * @param types 1.61 + * set of {@link JType} objects. 1.62 + */ 1.63 + public static JType getCommonBaseType( JCodeModel codeModel, Collection<? extends JType> types ) { 1.64 + return getCommonBaseType( codeModel, types.toArray(new JType[types.size()]) ); 1.65 + } 1.66 + 1.67 + /** 1.68 + * Computes the common base type of types. 1.69 + * 1.70 + * TODO: this is a very interesting problem. Since one type has possibly 1.71 + * multiple base types, it's not an easy problem. 1.72 + * The current implementation is very naive. 1.73 + * 1.74 + * To make the result deterministic across differente JVMs, we have to 1.75 + * use a Set whose ordering is deterministic. 1.76 + */ 1.77 + public static JType getCommonBaseType(JCodeModel codeModel, JType... t) { 1.78 + // first, eliminate duplicates. 1.79 + Set<JType> uniqueTypes = new TreeSet<JType>(typeComparator); 1.80 + for (JType type : t) 1.81 + uniqueTypes.add(type); 1.82 + 1.83 + // if this yields only one type. return now. 1.84 + // this is the only case where we can return a primitive type 1.85 + // from this method 1.86 + if (uniqueTypes.size() == 1) 1.87 + return uniqueTypes.iterator().next(); 1.88 + 1.89 + // assertion failed. nullType can be used only under a very special circumstance 1.90 + assert !uniqueTypes.isEmpty(); 1.91 + 1.92 + // the null type doesn't need to be taken into account. 1.93 + uniqueTypes.remove(codeModel.NULL); 1.94 + 1.95 + // box all the types and compute the intersection of all types 1.96 + Set<JClass> s = null; 1.97 + 1.98 + for (JType type : uniqueTypes) { 1.99 + JClass cls = type.boxify(); 1.100 + 1.101 + if (s == null) 1.102 + s = getAssignableTypes(cls); 1.103 + else 1.104 + s.retainAll(getAssignableTypes(cls)); 1.105 + } 1.106 + 1.107 + // any JClass can be casted to Object, so make sure it's always there 1.108 + s.add( codeModel.ref(Object.class)); 1.109 + 1.110 + // refine 's' by removing "lower" types. 1.111 + // for example, if we have both java.lang.Object and 1.112 + // java.io.InputStream, then we don't want to use java.lang.Object. 1.113 + 1.114 + JClass[] raw = s.toArray(new JClass[s.size()]); 1.115 + s.clear(); 1.116 + 1.117 + for (int i = 0; i < raw.length; i++) { // for each raw[i] 1.118 + int j; 1.119 + for (j = 0; j < raw.length; j++) { // see if raw[j] "includes" raw[i] 1.120 + if (i == j) 1.121 + continue; 1.122 + 1.123 + if (raw[i].isAssignableFrom(raw[j])) 1.124 + break; // raw[j] is derived from raw[i], hence j includes i. 1.125 + } 1.126 + 1.127 + if (j == raw.length) 1.128 + // no other type inclueds raw[i]. remember this value. 1.129 + s.add(raw[i]); 1.130 + } 1.131 + 1.132 + assert !s.isEmpty(); // since at least java.lang.Object has to be there 1.133 + 1.134 + // we now pick the candidate for the return type 1.135 + JClass result = pickOne(s); 1.136 + 1.137 + // finally, sometimes this method is used to compute the base type of types like 1.138 + // JAXBElement<A>, JAXBElement<B>, and JAXBElement<C>. 1.139 + // for those inputs, at this point result=JAXBElement. 1.140 + // 1.141 + // here, we'll try to figure out the parameterization 1.142 + // so that we can return JAXBElement<? extends D> instead of just "JAXBElement". 1.143 + if(result.isParameterized()) 1.144 + return result; 1.145 + 1.146 + // for each uniqueType we store the list of base type parameterization 1.147 + List<List<JClass>> parameters = new ArrayList<List<JClass>>(uniqueTypes.size()); 1.148 + int paramLen = -1; 1.149 + 1.150 + for (JType type : uniqueTypes) { 1.151 + JClass cls = type.boxify(); 1.152 + JClass bp = cls.getBaseClass(result); 1.153 + // if there's no parameterization in the base type, 1.154 + // we won't do any better than <?>. Thus no point in trying to figure out the parameterization. 1.155 + // just return the base type. 1.156 + if(bp.equals(result)) 1.157 + return result; 1.158 + 1.159 + assert bp.isParameterized(); 1.160 + List<JClass> tp = bp.getTypeParameters(); 1.161 + parameters.add(tp); 1.162 + 1.163 + assert paramLen==-1 || paramLen==tp.size(); 1.164 + // since 'bp' always is a parameterized version of 'result', it should always 1.165 + // have the same number of parameters. 1.166 + paramLen = tp.size(); 1.167 + } 1.168 + 1.169 + List<JClass> paramResult = new ArrayList<JClass>(); 1.170 + List<JClass> argList = new ArrayList<JClass>(parameters.size()); 1.171 + // for each type parameter compute the common base type 1.172 + for( int i=0; i<paramLen; i++ ) { 1.173 + argList.clear(); 1.174 + for (List<JClass> list : parameters) 1.175 + argList.add(list.get(i)); 1.176 + 1.177 + // compute the lower bound. 1.178 + JClass bound = (JClass)getCommonBaseType(codeModel,argList); 1.179 + boolean allSame = true; 1.180 + for (JClass a : argList) 1.181 + allSame &= a.equals(bound); 1.182 + if(!allSame) 1.183 + bound = bound.wildcard(); 1.184 + 1.185 + paramResult.add(bound); 1.186 + } 1.187 + 1.188 + return result.narrow(paramResult); 1.189 + } 1.190 + 1.191 + private static JClass pickOne(Set<JClass> s) { 1.192 + // we may have more than one candidates at this point. 1.193 + // any user-defined generated types should have 1.194 + // precedence over system-defined existing types. 1.195 + // 1.196 + // so try to return such a type if any. 1.197 + for (JClass c : s) 1.198 + if (c instanceof JDefinedClass) 1.199 + return c; 1.200 + 1.201 + // we can do more if we like. for example, 1.202 + // we can avoid types in the RI runtime. 1.203 + // but for now, just return the first one. 1.204 + return s.iterator().next(); 1.205 + } 1.206 + 1.207 + private static Set<JClass> getAssignableTypes( JClass t ) { 1.208 + Set<JClass> r = new TreeSet<JClass>(typeComparator); 1.209 + getAssignableTypes(t,r); 1.210 + return r; 1.211 + } 1.212 + 1.213 + /** 1.214 + * Returns the set of all classes/interfaces that a given type 1.215 + * implements/extends, including itself. 1.216 + * 1.217 + * For example, if you pass java.io.FilterInputStream, then the returned 1.218 + * set will contain java.lang.Object, java.lang.InputStream, and 1.219 + * java.lang.FilterInputStream. 1.220 + */ 1.221 + private static void getAssignableTypes( JClass t, Set<JClass> s ) { 1.222 + if(!s.add(t)) 1.223 + return; 1.224 + 1.225 + // add its raw type 1.226 + s.add(t.erasure()); 1.227 + 1.228 + // if this type is added for the first time, 1.229 + // recursively process the super class. 1.230 + JClass _super = t._extends(); 1.231 + if(_super!=null) 1.232 + getAssignableTypes(_super,s); 1.233 + 1.234 + // recursively process all implemented interfaces 1.235 + Iterator<JClass> itr = t._implements(); 1.236 + while(itr.hasNext()) 1.237 + getAssignableTypes(itr.next(),s); 1.238 + } 1.239 + 1.240 + /** 1.241 + * Obtains a {@link JType} object for the string representation 1.242 + * of a type. 1.243 + */ 1.244 + public static JType getType( JCodeModel codeModel, 1.245 + String typeName, ErrorReceiver errorHandler, Locator errorSource ) { 1.246 + 1.247 + try { 1.248 + return codeModel.parseType(typeName); 1.249 + } catch( ClassNotFoundException ee ) { 1.250 + 1.251 + // make it a warning 1.252 + errorHandler.warning( new SAXParseException( 1.253 + Messages.ERR_CLASS_NOT_FOUND.format(typeName) 1.254 + ,errorSource)); 1.255 + 1.256 + // recover by assuming that it's a class that derives from Object 1.257 + return codeModel.directClass(typeName); 1.258 + } 1.259 + } 1.260 + 1.261 + /** 1.262 + * Compares {@link JType} objects by their names. 1.263 + */ 1.264 + private static final Comparator<JType> typeComparator = new Comparator<JType>() { 1.265 + public int compare(JType t1, JType t2) { 1.266 + return t1.fullName().compareTo(t2.fullName()); 1.267 + } 1.268 + }; 1.269 +}