001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020:
021: package com.sun.codemodel;
022:
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.Collections;
026: import java.util.Iterator;
027: import java.util.List;
028:
029: /**
030: * Represents a Java reference type, such as a class, an interface,
031: * an enum, an array type, a parameterized type.
032: *
033: * <p>
034: * To be exact, this object represents an "use" of a reference type,
035: * not necessarily a declaration of it, which is modeled as {@link JDefinedClass}.
036: */
037: public abstract class JClass extends JType {
038: protected JClass(JCodeModel _owner) {
039: this ._owner = _owner;
040: }
041:
042: /**
043: * Gets the name of this class.
044: *
045: * @return
046: * name of this class, without any qualification.
047: * For example, this method returns "String" for
048: * <code>java.lang.String</code>.
049: */
050: abstract public String name();
051:
052: /**
053: * Gets the package to which this class belongs.
054: * TODO: shall we move move this down?
055: */
056: abstract public JPackage _package();
057:
058: /**
059: * Returns the class in which this class is nested, or <tt>null</tt> if
060: * this is a top-level class.
061: */
062: public JClass outer() {
063: return null;
064: }
065:
066: private final JCodeModel _owner;
067:
068: /** Gets the JCodeModel object to which this object belongs. */
069: public final JCodeModel owner() {
070: return _owner;
071: }
072:
073: /**
074: * Gets the super class of this class.
075: *
076: * @return
077: * Returns the JClass representing the superclass of the
078: * entity (class or interface) represented by this {@link JClass}.
079: * Even if no super class is given explicitly or this {@link JClass}
080: * is not a class, this method still returns
081: * {@link JClass} for {@link Object}.
082: * If this JClass represents {@link Object}, return null.
083: */
084: abstract public JClass _extends();
085:
086: /**
087: * Iterates all super interfaces directly implemented by
088: * this class/interface.
089: *
090: * @return
091: * A non-null valid iterator that iterates all
092: * {@link JClass} objects that represents those interfaces
093: * implemented by this object.
094: */
095: abstract public Iterator<JClass> _implements ();
096:
097: /**
098: * Iterates all the type parameters of this class/interface.
099: *
100: * <p>
101: * For example, if this {@link JClass} represents
102: * <code>Set<T></code>, this method returns an array
103: * that contains single {@link JTypeVar} for 'T'.
104: */
105: public JTypeVar[] typeParams() {
106: return EMPTY_ARRAY;
107: }
108:
109: /**
110: * Sometimes useful reusable empty array.
111: */
112: protected static final JTypeVar[] EMPTY_ARRAY = new JTypeVar[0];
113:
114: /**
115: * Checks if this object represents an interface.
116: */
117: abstract public boolean isInterface();
118:
119: /**
120: * Checks if this class is an abstract class.
121: */
122: abstract public boolean isAbstract();
123:
124: /**
125: * If this class represents one of the wrapper classes
126: * defined in the java.lang package, return the corresponding
127: * primitive type. Otherwise null.
128: */
129: public JPrimitiveType getPrimitiveType() {
130: return null;
131: }
132:
133: /**
134: * @deprecated calling this method from {@link JClass}
135: * would be meaningless, since it's always guaranteed to
136: * return <tt>this</tt>.
137: */
138: public JClass boxify() {
139: return this ;
140: }
141:
142: public JType unboxify() {
143: JPrimitiveType pt = getPrimitiveType();
144: return pt == null ? (JType) this : pt;
145: }
146:
147: public JClass erasure() {
148: return this ;
149: }
150:
151: /**
152: * Checks the relationship between two classes.
153: * <p>
154: * This method works in the same way as {@link Class#isAssignableFrom(Class)}
155: * works. For example, baseClass.isAssignableFrom(derivedClass)==true.
156: */
157: public final boolean isAssignableFrom(JClass derived) {
158: // to avoid the confusion, always use "this" explicitly in this method.
159:
160: // null can be assigned to any type.
161: if (derived instanceof JNullType)
162: return true;
163:
164: if (this == derived)
165: return true;
166:
167: // the only class that is assignable from an interface is
168: // java.lang.Object
169: if (this == _package().owner().ref(Object.class))
170: return true;
171:
172: JClass b = derived._extends();
173: if (b != null && this .isAssignableFrom(b))
174: return true;
175:
176: if (this .isInterface()) {
177: Iterator itfs = derived._implements ();
178: while (itfs.hasNext())
179: if (this .isAssignableFrom((JClass) itfs.next()))
180: return true;
181: }
182:
183: return false;
184: }
185:
186: /**
187: * Gets the parameterization of the given base type.
188: *
189: * <p>
190: * For example, given the following
191: * <pre><xmp>
192: * interface Foo<T> extends List<List<T>> {}
193: * interface Bar extends Foo<String> {}
194: * </xmp></pre>
195: * This method works like this:
196: * <pre><xmp>
197: * getBaseClass( Bar, List ) = List<List<String>
198: * getBaseClass( Bar, Foo ) = Foo<String>
199: * getBaseClass( Foo<? extends Number>, Collection ) = Collection<List<? extends Number>>
200: * getBaseClass( ArrayList<? extends BigInteger>, List ) = List<? extends BigInteger>
201: * </xmp></pre>
202: *
203: * @param baseType
204: * The class whose parameterization we are interested in.
205: * @return
206: * The use of {@code baseType} in {@code this} type.
207: * or null if the type is not assignable to the base type.
208: */
209: public final JClass getBaseClass(JClass baseType) {
210:
211: if (this .erasure().equals(baseType))
212: return this ;
213:
214: JClass b = _extends();
215: if (b != null) {
216: JClass bc = b.getBaseClass(baseType);
217: if (bc != null)
218: return bc;
219: }
220:
221: Iterator<JClass> itfs = _implements ();
222: while (itfs.hasNext()) {
223: JClass bc = itfs.next().getBaseClass(baseType);
224: if (bc != null)
225: return bc;
226: }
227:
228: return null;
229: }
230:
231: public final JClass getBaseClass(Class baseType) {
232: return getBaseClass(owner().ref(baseType));
233: }
234:
235: private JClass arrayClass;
236:
237: public JClass array() {
238: if (arrayClass == null)
239: arrayClass = new JArrayClass(owner(), this );
240: return arrayClass;
241: }
242:
243: /**
244: * "Narrows" a generic class to a concrete class by specifying
245: * a type argument.
246: *
247: * <p>
248: * <code>.narrow(X)</code> builds <code>Set<X></code> from <code>Set</code>.
249: */
250: public JClass narrow(Class clazz) {
251: return narrow(owner().ref(clazz));
252: }
253:
254: public JClass narrow(Class... clazz) {
255: JClass[] r = new JClass[clazz.length];
256: for (int i = 0; i < clazz.length; i++)
257: r[i] = owner().ref(clazz[i]);
258: return narrow(r);
259: }
260:
261: /**
262: * "Narrows" a generic class to a concrete class by specifying
263: * a type argument.
264: *
265: * <p>
266: * <code>.narrow(X)</code> builds <code>Set<X></code> from <code>Set</code>.
267: */
268: public JClass narrow(JClass clazz) {
269: return new JNarrowedClass(this , clazz);
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(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>></code>.
311: *
312: * <p>
313: * This method needs to work recursively.
314: */
315: protected abstract JClass substituteParams(JTypeVar[] variables,
316: List<JClass> bindings);
317:
318: public String toString() {
319: return this .getClass().getName() + '(' + name() + ')';
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: }
|