View Javadoc
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 }