KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > java > source > ElementHandle


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.java.source;
21
22 import com.sun.tools.javac.code.Symtab;
23 import com.sun.tools.javac.jvm.Target;
24 import com.sun.tools.javac.model.JavacElements;
25 import java.util.List JavaDoc;
26 import javax.lang.model.element.Element;
27 import javax.lang.model.element.ElementKind;
28 import javax.lang.model.element.ExecutableElement;
29 import javax.lang.model.element.PackageElement;
30 import javax.lang.model.element.TypeElement;
31 import javax.lang.model.element.TypeParameterElement;
32 import javax.lang.model.element.VariableElement;
33 import org.netbeans.modules.java.source.ElementHandleAccessor;
34 import org.netbeans.modules.java.source.usages.ClassFileUtil;
35
36 /**
37  * Represents a handle for {@link Element} which can be kept and later resolved
38  * by another javac. The javac {@link Element}s are valid only in a single
39  * {@link javax.tools.CompilationTask} or a single run of a
40  * {@link CancellableTask}. A client needing to
41  * keep a reference to an {@link Element} and use it in another {@link CancellableTask}
42  * must serialize it into an {@link ElementHandle}.
43  * Currently not all {@link Element}s can be serialized. See {@link #create} for details.
44  * <div class="nonnormative">
45  * <p>
46  * Typical usage of {@link ElementHandle} is as follows:
47  * </p>
48  * <pre>
49  * final ElementHandle[] elementHandle = new ElementHandle[1];
50  * javaSource.runUserActionTask(new CancellableTask&lt;CompilationController>() {
51  * public void run(CompilationController compilationController) {
52  * compilationController.toPhase(Phase.RESOLVED);
53  * CompilationUnitTree cu = compilationController.getTree();
54  * List&lt;? extends Tree> types = getTypeDecls(cu);
55  * Tree tree = getInterestingElementTree(types);
56  * Element element = compilationController.getElement(tree);
57  * elementHandle[0] = ElementHandle.create(element);
58  * }
59  * }, true);
60  *
61  * otherJavaSource.runUserActionTask(new CancellableTask&lt;CompilationController>() {
62  * public void run(CompilationController compilationController) {
63  * compilationController.toPhase(Phase.RESOLVED);
64  * Element element = elementHandle[0].resolve(compilationController);
65  * // ....
66  * }
67  * }, true);
68  * </pre>
69  * </div>
70  * @author Tomas Zezula
71  */

72 public final class ElementHandle<T extends Element> {
73     
74     static {
75         ElementHandleAccessor.INSTANCE = new ElementHandleAccessorImpl ();
76     }
77     
78     private ElementKind kind;
79     private String JavaDoc[] signatures;
80         
81        
82     private ElementHandle(final ElementKind kind, String JavaDoc[] signatures) {
83         assert kind != null;
84         assert signatures != null;
85         this.kind = kind;
86         this.signatures = signatures;
87     }
88     
89     
90     /**
91      * Resolves an {@link Element} from the {@link ElementHandle}.
92      * @param compilationInfo representing the {@link javax.tools.CompilationTask}
93      * in which the {@link Element} should be resolved.
94      * @return resolved subclass of {@link Element} or null if the elment does not exist on
95      * the classpath/sourcepath of {@link javax.tools.CompilationTask}.
96      */

97     @SuppressWarnings JavaDoc ("unchecked") // NOI18N
98
public T resolve (final CompilationInfo compilationInfo) {
99         assert compilationInfo != null;
100         switch (this.kind) {
101             case PACKAGE:
102                 assert signatures.length == 1;
103                 return (T) compilationInfo.getElements().getPackageElement(signatures[0]);
104             case CLASS:
105             case INTERFACE:
106             case ENUM:
107             case ANNOTATION_TYPE:
108             case OTHER:
109                 assert signatures.length == 1;
110                 return (T) getTypeElementByBinaryName (signatures[0], compilationInfo);
111             case METHOD:
112             case CONSTRUCTOR:
113             case INSTANCE_INIT:
114             case STATIC_INIT:
115             {
116                 assert signatures.length == 3;
117                 final TypeElement type = getTypeElementByBinaryName (signatures[0], compilationInfo);
118                 if (type != null) {
119                    final List JavaDoc<? extends Element> members = type.getEnclosedElements();
120                    for (Element member : members) {
121                        if (this.kind == member.getKind()) {
122                            String JavaDoc[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member);
123                            assert desc.length == 3;
124                            if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) {
125                                return (T) member;
126                            }
127                        }
128                    }
129                 }
130                 break;
131             }
132             case FIELD:
133             case ENUM_CONSTANT:
134             {
135                 assert signatures.length == 3;
136                 final TypeElement type = getTypeElementByBinaryName (signatures[0], compilationInfo);
137                 if (type != null) {
138                     final List JavaDoc<? extends Element> members = type.getEnclosedElements();
139                     for (Element member : members) {
140                         if (this.kind == member.getKind()) {
141                             String JavaDoc[] desc = ClassFileUtil.createFieldDescriptor((VariableElement)member);
142                             assert desc.length == 3;
143                             if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) {
144                                 return (T) member;
145                             }
146                         }
147                     }
148                 }
149                 break;
150             }
151             case TYPE_PARAMETER:
152             {
153                 if (signatures.length == 2) {
154                      TypeElement type = getTypeElementByBinaryName (signatures[0], compilationInfo);
155                      if (type != null) {
156                          List JavaDoc<? extends TypeParameterElement> tpes = type.getTypeParameters();
157                          for (TypeParameterElement tpe : tpes) {
158                              if (tpe.getSimpleName().contentEquals(signatures[1])) {
159                                  return (T)tpe;
160                              }
161                          }
162                      }
163                 }
164                 else if (signatures.length == 4) {
165                     final TypeElement type = getTypeElementByBinaryName (signatures[0], compilationInfo);
166                     if (type != null) {
167                         final List JavaDoc<? extends Element> members = type.getEnclosedElements();
168                         for (Element member : members) {
169                             if (member.getKind() == ElementKind.METHOD || member.getKind() == ElementKind.CONSTRUCTOR) {
170                                 String JavaDoc[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member);
171                                 assert desc.length == 3;
172                                 if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) {
173                                     assert member instanceof ExecutableElement;
174                                     List JavaDoc<? extends TypeParameterElement> tpes =((ExecutableElement)member).getTypeParameters();
175                                     for (TypeParameterElement tpe : tpes) {
176                                         if (tpe.getSimpleName().contentEquals(signatures[3])) {
177                                             return (T) tpe;
178                                         }
179                                     }
180                                 }
181                             }
182                         }
183                     }
184                 }
185                 else {
186                     throw new IllegalStateException JavaDoc ();
187                 }
188                 break;
189             }
190             default:
191                 throw new IllegalStateException JavaDoc ();
192         }
193         return null;
194     }
195     
196     
197     /**
198      * Tests if the handle has the same signature as the parameter.
199      * The handles with the same signatures are resolved into the same
200      * element in the same {@link javax.tools.JavaCompiler} task, but may be resolved into
201      * the different {@link Element}s in the different {@link javax.tools.JavaCompiler} tasks.
202      * @param handle to be checked
203      * @return true if the handles resolve into the same {@link Element}s
204      * in the same {@link javax.tools.JavaCompiler} task.
205      */

206     public boolean signatureEquals (final ElementHandle<? extends Element> handle) {
207          if (this.kind != handle.kind || this.signatures.length != handle.signatures.length) {
208              return false;
209          }
210          for (int i=0; i<signatures.length; i++) {
211              if (!signatures[i].equals(handle.signatures[i])) {
212                  return false;
213              }
214          }
215          return true;
216     }
217     
218     
219     /**
220      * Returns a binary name of the {@link TypeElement} represented by this
221      * {@link ElementHandle}. When the {@link ElementHandle} doesn't represent
222      * a {@link TypeElement} it throws a {@link IllegalStateException}
223      * @return the qualified name
224      * @throws an {@link IllegalStateException} when this {@link ElementHandle}
225      * isn't creatred for the {@link TypeElement}.
226      */

227     public String JavaDoc getBinaryName () throws IllegalStateException JavaDoc {
228         if ((this.kind.isClass() && !isArray(signatures[0])) || this.kind.isInterface()) {
229             return this.signatures[0];
230         }
231         else {
232             throw new IllegalStateException JavaDoc ();
233         }
234     }
235     
236     
237     /**
238      * Returns a qualified name of the {@link TypeElement} represented by this
239      * {@link ElementHandle}. When the {@link ElementHandle} doesn't represent
240      * a {@link TypeElement} it throws a {@link IllegalStateException}
241      * @return the qualified name
242      * @throws an {@link IllegalStateException} when this {@link ElementHandle}
243      * isn't creatred for the {@link TypeElement}.
244      */

245     public String JavaDoc getQualifiedName () throws IllegalStateException JavaDoc {
246         if ((this.kind.isClass() && !isArray(signatures[0])) || this.kind.isInterface()) {
247             return this.signatures[0].replace (Target.DEFAULT.syntheticNameChar(),'.'); //NOI18N
248
}
249         else {
250             throw new IllegalStateException JavaDoc ();
251         }
252     }
253     
254     
255     /**
256      * Tests if the handle has this same signature as the parameter.
257      * The handles has the same signatures if it is resolved into the same
258      * element in the same {@link javax.tools.JavaCompiler} task, but may be resolved into
259      * the different {@link Element} in the different {@link javax.tools.JavaCompiler} task.
260      * @param element to be checked
261      * @return true if this handle resolves into the same {@link Element}
262      * in the same {@link javax.tools.JavaCompiler} task.
263      */

264     public boolean signatureEquals (final T element) {
265         if (!element.getKind().equals(getKind())) {
266             return false;
267         }
268         final ElementHandle<T> handle = create (element);
269         return signatureEquals (handle);
270     }
271     
272     /**
273      * Returns the {@link ElementKind} of this element handle,
274      * it is the kind of the {@link Element} from which the handle
275      * was created.
276      * @return {@link ElementKind}
277      *
278      */

279     public ElementKind getKind () {
280         return this.kind;
281     }
282     
283     
284     /**
285      * Factory method for creating {@link ElementHandle}.
286      * @param element for which the {@link ElementHandle} should be created. Permitted
287      * {@link ElementKind}s
288      * are: {@link ElementKind#PACKAGE}, {@link ElementKind#CLASS},
289      * {@link ElementKind#INTERFACE}, {@link ElementKind#ENUM}, {@link ElementKind#ANNOTATION_TYPE}, {@link ElementKind#METHOD},
290      * {@link ElementKind#CONSTRUCTOR}, {@link ElementKind#INSTANCE_INIT}, {@link ElementKind#STATIC_INIT},
291      * {@link ElementKind#FIELD}, and {@link ElementKind#ENUM_CONSTANT}.
292      * @return a new {@link ElementHandle}
293      * @throws IllegalArgumentException if the element is of an unsupported {@link ElementKind}
294      */

295     public static<T extends Element> ElementHandle<T> create (final T element) throws IllegalArgumentException JavaDoc {
296         assert element != null;
297         ElementKind kind = element.getKind();
298         String JavaDoc[] signatures;
299         switch (kind) {
300             case PACKAGE:
301                 assert element instanceof PackageElement;
302                 signatures = new String JavaDoc[]{((PackageElement)element).getQualifiedName().toString()};
303                 break;
304             case CLASS:
305             case INTERFACE:
306             case ENUM:
307             case ANNOTATION_TYPE:
308                 assert element instanceof TypeElement;
309                 signatures = new String JavaDoc[] {ClassFileUtil.encodeClassNameOrArray((TypeElement)element)};
310                 break;
311             case METHOD:
312             case CONSTRUCTOR:
313             case INSTANCE_INIT:
314             case STATIC_INIT:
315                 assert element instanceof ExecutableElement;
316                 signatures = ClassFileUtil.createExecutableDescriptor((ExecutableElement)element);
317                 break;
318             case FIELD:
319             case ENUM_CONSTANT:
320                 assert element instanceof VariableElement;
321                 signatures = ClassFileUtil.createFieldDescriptor((VariableElement)element);
322                 break;
323             case TYPE_PARAMETER:
324                 assert element instanceof TypeParameterElement;
325                 TypeParameterElement tpe = (TypeParameterElement) element;
326                 Element ge = tpe.getGenericElement();
327                 ElementKind gek = ge.getKind();
328                 if (gek.isClass() || gek.isInterface()) {
329                     assert ge instanceof TypeElement;
330                     signatures = new String JavaDoc[2];
331                     signatures[0] = ClassFileUtil.encodeClassNameOrArray((TypeElement)ge);
332                     signatures[1] = tpe.getSimpleName().toString();
333                 }
334                 else if (gek == ElementKind.METHOD || gek == ElementKind.CONSTRUCTOR) {
335                     assert ge instanceof ExecutableElement;
336                     String JavaDoc[] _sigs = ClassFileUtil.createExecutableDescriptor((ExecutableElement)ge);
337                     signatures = new String JavaDoc[_sigs.length + 1];
338                     System.arraycopy(_sigs, 0, signatures, 0, _sigs.length);
339                     signatures[_sigs.length] = tpe.getSimpleName().toString();
340                 }
341                 else {
342                     throw new IllegalArgumentException JavaDoc(gek.toString());
343                 }
344                 break;
345             default:
346                 throw new IllegalArgumentException JavaDoc(kind.toString());
347         }
348         return new ElementHandle<T> (kind, signatures);
349     }
350     
351     
352     public @Override JavaDoc String JavaDoc toString () {
353         final StringBuilder JavaDoc result = new StringBuilder JavaDoc ();
354         result.append (this.getClass().getSimpleName());
355         result.append ('['); // NOI18N
356
result.append ("kind=" +this.kind.toString()); // NOI18N
357
result.append ("; sigs="); // NOI18N
358
for (String JavaDoc sig : this.signatures) {
359             result.append (sig);
360             result.append (' '); // NOI18N
361
}
362         result.append (']'); // NOI18N
363
return result.toString();
364     }
365     
366     
367     /**@inheritDoc*/
368     @Override JavaDoc
369     public int hashCode () {
370         return signatures.length == 0 || signatures[0] == null ? 0 : signatures[0].hashCode();
371     }
372     
373     /**@inheritDoc*/
374     @Override JavaDoc
375     public boolean equals (Object JavaDoc other) {
376         if (other instanceof ElementHandle) {
377             return signatureEquals((ElementHandle)other);
378         }
379         return false;
380     }
381     
382     
383     /**
384      * Returns the element signature.
385      * Package private, used by ClassIndex.
386      */

387     String JavaDoc[] getSignature () {
388         return this.signatures;
389     }
390         
391     
392     private static class ElementHandleAccessorImpl extends ElementHandleAccessor {
393         
394         public ElementHandle create(ElementKind kind, String JavaDoc... descriptors) {
395             assert kind != null;
396             assert descriptors != null;
397             switch (kind) {
398                 case PACKAGE:
399                     if (descriptors.length != 1) {
400                         throw new IllegalArgumentException JavaDoc ();
401                     }
402                     return new ElementHandle<PackageElement> (kind, descriptors);
403                 case CLASS:
404                 case INTERFACE:
405                 case ENUM:
406                 case ANNOTATION_TYPE:
407                 case OTHER:
408                     if (descriptors.length != 1) {
409                         throw new IllegalArgumentException JavaDoc ();
410                     }
411                     return new ElementHandle<TypeElement> (kind, descriptors);
412                 case METHOD:
413                 case CONSTRUCTOR:
414                 case INSTANCE_INIT:
415                 case STATIC_INIT:
416                     if (descriptors.length != 3) {
417                         throw new IllegalArgumentException JavaDoc ();
418                     }
419                     return new ElementHandle<ExecutableElement> (kind, descriptors);
420                 case FIELD:
421                 case ENUM_CONSTANT:
422                     if (descriptors.length != 3) {
423                         throw new IllegalArgumentException JavaDoc ();
424                     }
425                     return new ElementHandle<VariableElement> (kind, descriptors);
426                 default:
427                     throw new IllegalArgumentException JavaDoc ();
428             }
429         }
430     }
431     
432     private static TypeElement getTypeElementByBinaryName (final String JavaDoc signature, final CompilationInfo ci) {
433         if (isArray(signature)) {
434             return Symtab.instance(ci.getJavacTask().getContext()).arrayClass;
435         }
436         else {
437             assert ci.getElements() instanceof JavacElements;
438             final JavacElements elements = (JavacElements) ci.getElements();
439             return (TypeElement) elements.getTypeElementByBinaryName(signature);
440         }
441     }
442     
443     private static boolean isArray (String JavaDoc signature) {
444         return signature.length() == 1 && signature.charAt(0) == '[';
445     }
446     
447 }
448
Popular Tags