1 /* 2 * Copyright (c) 1997, 2012, 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 */ 25 26 package com.sun.codemodel.internal; 27 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.Collections; 31 import java.util.Iterator; 32 import java.util.List; 33 34 /** 35 * Represents a Java reference type, such as a class, an interface, 36 * an enum, an array type, a parameterized type. 37 * 38 * <p> 39 * To be exact, this object represents an "use" of a reference type, 40 * not necessarily a declaration of it, which is modeled as {@link JDefinedClass}. 41 */ 42 public abstract class JClass extends JType 43 { 44 protected JClass( JCodeModel _owner ) { 45 this._owner = _owner; 46 } 47 48 /** 49 * Gets the name of this class. 50 * 51 * @return 52 * name of this class, without any qualification. 53 * For example, this method returns "String" for 54 * {@code java.lang.String}. 55 */ 56 abstract public String name(); 57 58 /** 59 * Gets the package to which this class belongs. 60 * TODO: shall we move move this down? 61 */ 62 abstract public JPackage _package(); 63 64 /** 65 * Returns the class in which this class is nested, or {@code null} if 66 * this is a top-level class. 67 */ 68 public JClass outer() { 69 return null; 70 } 71 72 private final JCodeModel _owner; 73 /** Gets the JCodeModel object to which this object belongs. */ 74 public final JCodeModel owner() { return _owner; } 75 76 /** 77 * Gets the super class of this class. 78 * 79 * @return 80 * Returns the JClass representing the superclass of the 81 * entity (class or interface) represented by this {@link JClass}. 82 * Even if no super class is given explicitly or this {@link JClass} 83 * is not a class, this method still returns 84 * {@link JClass} for {@link Object}. 85 * If this JClass represents {@link Object}, return null. 86 */ 87 abstract public JClass _extends(); 88 89 /** 90 * Iterates all super interfaces directly implemented by 91 * this class/interface. 92 * 93 * @return 94 * A non-null valid iterator that iterates all 95 * {@link JClass} objects that represents those interfaces 96 * implemented by this object. 97 */ 98 abstract public Iterator<JClass> _implements(); 99 100 /** 101 * Iterates all the type parameters of this class/interface. 102 * 103 * <p> 104 * For example, if this {@link JClass} represents 105 * {@code Set<T>}, this method returns an array 106 * that contains single {@link JTypeVar} for 'T'. 107 */ 108 public JTypeVar[] typeParams() { 109 return EMPTY_ARRAY; 110 } 111 112 /** 113 * Sometimes useful reusable empty array. 114 */ 115 protected static final JTypeVar[] EMPTY_ARRAY = new JTypeVar[0]; 116 117 /** 118 * Checks if this object represents an interface. 119 */ 120 abstract public boolean isInterface(); 121 122 /** 123 * Checks if this class is an abstract class. 124 */ 125 abstract public boolean isAbstract(); 126 127 /** 128 * If this class represents one of the wrapper classes 129 * defined in the java.lang package, return the corresponding 130 * primitive type. Otherwise null. 131 */ 132 public JPrimitiveType getPrimitiveType() { return null; } 133 134 /** 135 * @deprecated calling this method from {@link JClass} 136 * would be meaningless, since it's always guaranteed to 137 * return {@code this}. 138 */ 139 public JClass boxify() { return this; } 140 141 public JType unboxify() { 142 JPrimitiveType pt = getPrimitiveType(); 143 return pt==null ? (JType)this : pt; 144 } 145 146 public JClass erasure() { 147 return this; 148 } 149 150 /** 151 * Checks the relationship between two classes. 152 * <p> 153 * This method works in the same way as {@link Class#isAssignableFrom(Class)} 154 * works. For example, baseClass.isAssignableFrom(derivedClass)==true. 155 */ 156 public final boolean isAssignableFrom( JClass derived ) { 157 // to avoid the confusion, always use "this" explicitly in this method. 158 159 // null can be assigned to any type. 160 if( derived instanceof JNullType ) return true; 161 162 if( this==derived ) return true; 163 164 // the only class that is assignable from an interface is 165 // java.lang.Object 166 if( this==_package().owner().ref(Object.class) ) return true; 167 168 JClass b = derived._extends(); 169 if( b!=null && this.isAssignableFrom(b) ) 170 return true; 171 172 if( this.isInterface() ) { 173 Iterator<JClass> itfs = derived._implements(); 174 while( itfs.hasNext() ) 175 if( this.isAssignableFrom(itfs.next()) ) 176 return true; 177 } 178 179 return false; 180 } 181 182 /** 183 * Gets the parameterization of the given base type. 184 * 185 * <p> 186 * For example, given the following 187 * <pre>{@code 188 * interface Foo<T> extends List<List<T>> {} 189 * interface Bar extends Foo<String> {} 190 * }</pre> 191 * This method works like this: 192 * <pre>{@code 193 * getBaseClass( Bar, List ) = List<List<String> 194 * getBaseClass( Bar, Foo ) = Foo<String> 195 * getBaseClass( Foo<? extends Number>, Collection ) = Collection<List<? extends Number>> 196 * getBaseClass( ArrayList<? extends BigInteger>, List ) = List<? extends BigInteger> 197 * }</pre> 198 * 199 * @param baseType 200 * The class whose parameterization we are interested in. 201 * @return 202 * The use of {@code baseType} in {@code this} type. 203 * or null if the type is not assignable to the base type. 204 */ 205 public final JClass getBaseClass( JClass baseType ) { 206 207 if( this.erasure().equals(baseType) ) 208 return this; 209 210 JClass b = _extends(); 211 if( b!=null ) { 212 JClass bc = b.getBaseClass(baseType); 213 if(bc!=null) 214 return bc; 215 } 216 217 Iterator<JClass> itfs = _implements(); 218 while( itfs.hasNext() ) { 219 JClass bc = itfs.next().getBaseClass(baseType); 220 if(bc!=null) 221 return bc; 222 } 223 224 return null; 225 } 226 227 public final JClass getBaseClass( Class<?> baseType ) { 228 return getBaseClass(owner().ref(baseType)); 229 } 230 231 232 private JClass arrayClass; 233 public JClass array() { 234 if(arrayClass==null) 235 arrayClass = new JArrayClass(owner(),this); 236 return arrayClass; 237 } 238 239 /** 240 * "Narrows" a generic class to a concrete class by specifying 241 * a type argument. 242 * 243 * <p> 244 * {@code .narrow(X)} builds {@code Set<X>} from {@code Set}. 245 */ 246 public JClass narrow( Class<?> clazz ) { 247 return narrow(owner().ref(clazz)); 248 } 249 250 public JClass narrow( Class<?>... clazz ) { 251 JClass[] r = new JClass[clazz.length]; 252 for( int i=0; i<clazz.length; i++ ) 253 r[i] = owner().ref(clazz[i]); 254 return narrow(r); 255 } 256 257 /** 258 * "Narrows" a generic class to a concrete class by specifying 259 * a type argument. 260 * 261 * <p> 262 * {@code .narrow(X)} builds {@code Set<X>} from {@code Set}. 263 */ 264 public JClass narrow( JClass clazz ) { 265 return new JNarrowedClass(this,clazz); 266 } 267 268 public JClass narrow( JType type ) { 269 return narrow(type.boxify()); 270 } 271 272 public JClass narrow( JClass... clazz ) { 273 return new JNarrowedClass(this,Arrays.asList(clazz.clone())); 274 } 275 276 public JClass narrow( List<? extends JClass> clazz ) { 277 return new JNarrowedClass(this,new ArrayList<JClass>(clazz)); 278 } 279 280 /** 281 * If this class is parameterized, return the type parameter of the given index. 282 */ 283 public List<JClass> getTypeParameters() { 284 return Collections.emptyList(); 285 } 286 287 /** 288 * Returns true if this class is a parameterized class. 289 */ 290 public final boolean isParameterized() { 291 return erasure()!=this; 292 } 293 294 /** 295 * Create "? extends T" from T. 296 * 297 * @return never null 298 */ 299 public final JClass wildcard() { 300 return new JTypeWildcard(this); 301 } 302 303 /** 304 * Substitutes the type variables with their actual arguments. 305 * 306 * <p> 307 * For example, when this class is Map<String,Map<V>>, 308 * (where V then doing 309 * substituteParams( V, Integer ) returns a {@link JClass} 310 * for {@code Map<String,Map<Integer>>}. 311 * 312 * <p> 313 * This method needs to work recursively. 314 */ 315 protected abstract JClass substituteParams( JTypeVar[] variables, List<JClass> bindings ); 316 317 public String toString() { 318 return this.getClass().getName() + '(' + name() + ')'; 319 } 320 321 322 public final JExpression dotclass() { 323 return JExpr.dotclass(this); 324 } 325 326 /** Generates a static method invocation. */ 327 public final JInvocation staticInvoke(JMethod method) { 328 return new JInvocation(this,method); 329 } 330 331 /** Generates a static method invocation. */ 332 public final JInvocation staticInvoke(String method) { 333 return new JInvocation(this,method); 334 } 335 336 /** Static field reference. */ 337 public final JFieldRef staticRef(String field) { 338 return new JFieldRef(this, field); 339 } 340 341 /** Static field reference. */ 342 public final JFieldRef staticRef(JVar field) { 343 return new JFieldRef(this, field); 344 } 345 346 public void generate(JFormatter f) { 347 f.t(this); 348 } 349 350 /** 351 * Prints the class name in javadoc @link format. 352 */ 353 void printLink(JFormatter f) { 354 f.p("{@link ").g(this).p('}'); 355 } 356 }