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  */
  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</code>.
  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 <tt>null</tt> 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&lt;T></code>, 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 <tt>this</tt>.
 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><xmp>
 188      * interface Foo<T> extends List<List<T>> {}
 189      * interface Bar extends Foo<String> {}
 190      * </xmp></pre>
 191      * This method works like this:
 192      * <pre><xmp>
 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      * </xmp></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)</code> builds <code>Set&lt;X></code> from <code>Set</code>.
 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)</code> builds <code>Set&lt;X></code> from <code>Set</code>.
 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&lt;String,Map&lt;V>>,
 308      * (where V then doing
 309      * substituteParams( V, Integer ) returns a {@link JClass}
 310      * for <code>Map&lt;String,Map&lt;Integer>></code>.
 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 }