KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > java > source > gen > TutorialTest


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-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.api.java.source.gen;
20
21 import com.sun.source.tree.*;
22 import com.sun.source.util.SourcePositions;
23 import java.io.BufferedReader JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FileReader JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.PrintStream JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.List JavaDoc;
32 import javax.lang.model.element.Modifier;
33 import javax.lang.model.element.TypeElement;
34 import javax.lang.model.type.TypeKind;
35 import org.netbeans.api.java.source.CancellableTask;
36 import org.netbeans.api.java.source.JavaSource;
37 import org.netbeans.api.java.source.TestUtilities;
38 import org.netbeans.api.java.source.TreeMaker;
39 import org.netbeans.api.java.source.TreeUtilities;
40 import static org.netbeans.api.java.source.JavaSource.*;
41 import org.netbeans.api.java.source.WorkingCopy;
42 import org.netbeans.junit.NbTestSuite;
43 import org.openide.filesystems.FileStateInvalidException;
44 import org.openide.filesystems.FileUtil;
45
46 /**
47  * This test contains examples described in HOWTO - modify the source code.
48  *
49  * (Test will always pass, as it does not check the results. It is used
50  * just for explanation.)
51  *
52  * @author Pavel Flaska
53  */

54
55 public class TutorialTest extends GeneratorTest {
56     
57     /** Creates a new instance of TutorialTest */
58     public TutorialTest(String JavaDoc name) {
59         super(name);
60     }
61     
62     public static NbTestSuite suite() {
63         NbTestSuite suite = new NbTestSuite();
64         suite.addTestSuite(TutorialTest.class);
65 // suite.addTest(new TutorialTest("testFirstModification"));
66
// suite.addTest(new TutorialTest("testAddMethod"));
67
// suite.addTest(new TutorialTest("testAddAnnotation"));
68
// suite.addTest(new TutorialTest("testForErno"));
69
// suite.addTest(new TutorialTest("testMethodInvocation"));
70
// suite.addTest(new TutorialTest("testNullLiteral"));
71
return suite;
72     }
73     
74     // Modifications demo:
75
// adds "implements Externalizable" and its import to the source.
76
public void testFirstModification() throws FileStateInvalidException,IOException JavaDoc {
77         // First of all, we have to look for JavaSource we want to work with...
78
// There are more ways to do it. For our demostration, we use
79
// straightforward solution, often used in tests. We omit details how
80
// to obtain correct file object and java source and we expect
81
// successful behaviour of called methods.
82
File JavaDoc tutorialFile = getFile(getSourceDir(), "/org/netbeans/test/codegen/Tutorial1.java");
83         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(tutorialFile));
84         
85         CancellableTask task = new CancellableTask<WorkingCopy>() {
86
87             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
88                 // working copy is used for modify source. When all is
89
// done, call commit() method on it to propagate changes
90
// to original source.
91
workingCopy.toPhase(Phase.RESOLVED);
92                 
93                 // CompilationUnitTree represents one java source file,
94
// exactly as defined in JLS, §7.3 Compilation Units.
95
CompilationUnitTree cut = workingCopy.getCompilationUnit();
96                 
97                 // Get the tree maker. This is the core class used for
98
// many modifications. It allows to add new members to class,
99
// modify statements. You should be able to do anything
100
// you need with your source.
101
TreeMaker make = workingCopy.getTreeMaker();
102                 // Go through all the (§7.6) Top Level Type Declarations and
103
// add the Externalizable interface to their declaration.
104
for (Tree typeDecl : cut.getTypeDecls()) {
105                     // ensure that it is correct type declaration, i.e. class
106
if (Tree.Kind.CLASS == typeDecl.getKind()) {
107                         ClassTree clazz = (ClassTree) typeDecl;
108                         // Now, there are several way how to create interface
109
// identifier which we wants to add to the class declaration.
110

111                         // Simpliest, but not sufficient solution: Add the
112
// plain identifier. It generates source as you can
113
// see below, but when import is not available,
114
// identifier is not resolved and class will not
115
// compile.
116
// public class Tutorial1 {
117
// public class Tutorial1 implements Externalizable {
118
ExpressionTree implementsClause = make.Identifier("Externalizable");
119                         
120
121                         // We can solve described problem with specifying
122
// fully-qualified name. We can create again identifier
123
// tree. (Bear in mind, that you will never get such
124
// an identifier from the compiler staff - this identifier
125
// will be represented as chain of MemberSelectTree
126
// of "io" and "Externalizable" and IdentifierTree "java".
127
// Currently, it is compilable and correct, but one can
128
// consider to do it much more precisely. See below.
129
// public class Tutorial1 {
130
// public class Tutorial1 implements java.io.Externalizable {
131
implementsClause = make.Identifier("java.io.Externalizable");
132                         
133                         // Last one and probably the most often used solution.
134
// Use the resolved type, provide the fully-qualified name
135
// for this resolution. You should check, that element is
136
// available. Then, make QualIdent tree, which will be
137
// recognized during source code modification and engine
138
// will decide (in accordance with options) how to correctly
139
// generate. Often, import for your class will be added
140
// and simple name will be used in implments clause.
141
// public class Tutorial1 {
142
//
143
// import java.io.Externalizable;
144
// public class Tutorial1 implements Externalizable {
145
TypeElement element = workingCopy.getElements().getTypeElement("java.io.Externalizable");
146                         implementsClause = make.QualIdent(element);
147                         
148                         // At this time, we want to add the created tree to correct
149
// place. We will use method addClassImplementsClause().
150
// Many of features uses these method, let's clarify
151
// names of the method:
152
// (add|insert|remove) prepend identified operation.
153
// (identifier) identifies tree which will be modified,
154
// in our case it is ClassTree. The rest identifies the
155
// list which will be updated.
156
// See TreeMaker javadoc for details.
157
ClassTree modifiedClazz = make.addClassImplementsClause(clazz, implementsClause);
158                         // As nodes in tree are immutable, all method return
159
// the same class type as provided in first paramter.
160
// If the method takes ClassTree parameter, it will
161
// return another class tree, which contains provided
162
// modification.
163

164                         // At the and, when you makes all the necessary changes,
165
// do not forget to replace original node with the new
166
// one.
167

168                         // TODO: changes can be chained, demonstrate!
169
workingCopy.rewrite(clazz, modifiedClazz);
170                     }
171                 }
172             }
173
174             public void cancel() {
175             }
176         };
177
178         // Now, we can start to process the changes. Because we want to modify
179
// source, we have to use runModificationTask (see its javadoc).
180
// At the end, we have to commit changes to propagate all the work
181
// to the source file... This can fail, so ensure you correctly
182
// handling exceptions. For testing reasons it is unimportant.
183
tutorialSource.runModificationTask(task).commit();
184         
185         // print the result to the System.err to see the changes in console.
186
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(tutorialFile));
187         PrintStream JavaDoc out = System.out;
188         String JavaDoc str;
189         while ((str = in.readLine()) != null) {
190             out.println(str);
191         }
192         in.close();
193     }
194
195     // creates and adds method to the source-code
196
public void testAddMethod() throws FileStateInvalidException, IOException JavaDoc {
197         File JavaDoc tutorialFile = getFile(getSourceDir(), "/org/netbeans/test/codegen/Tutorial1.java");
198         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(tutorialFile));
199         
200         CancellableTask task = new CancellableTask<WorkingCopy>() {
201
202             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
203                 workingCopy.toPhase(Phase.RESOLVED);
204                 CompilationUnitTree cut = workingCopy.getCompilationUnit();
205                 
206                 TreeMaker make = workingCopy.getTreeMaker();
207                 for (Tree typeDecl : cut.getTypeDecls()) {
208                     // ensure that it is correct type declaration, i.e. class
209
if (Tree.Kind.CLASS == typeDecl.getKind()) {
210                         ClassTree clazz = (ClassTree) typeDecl;
211                         
212                         // Create the method. This is done again through the
213
// TreeMaker as in the previous method. Here is the
214
// code how will method look like:
215
//
216
// public void writeExternal(final ObjectOutput arg0) throws IOException {
217
// throw new UnsupportedOperationException("Not supported yet.");
218
// }
219

220                         // create method modifier: public and no annotation
221
ModifiersTree methodModifiers = make.Modifiers(
222                             Collections.<Modifier>singleton(Modifier.PUBLIC),
223                             Collections.<AnnotationTree>emptyList()
224                         );
225                         
226                         // create parameter:
227
// final ObjectOutput arg0
228
VariableTree parameter = make.Variable(
229                                 make.Modifiers(
230                                     Collections.<Modifier>singleton(Modifier.FINAL),
231                                     Collections.<AnnotationTree>emptyList()
232                                 ),
233                                 "arg0", // name
234
make.Identifier("Object"), // parameter type
235
null // initializer - does not make sense in parameters.
236
);
237                         
238                         // prepare simple name to throws clause:
239
// 'throws IOException' and its import will be added
240
TypeElement element = workingCopy.getElements().getTypeElement("java.io.IOException");
241                         ExpressionTree throwsClause = make.QualIdent(element);
242                         
243                         // create method. There are two basic options:
244
// 1)
245
// make.Method() with 'BlockTree body' parameter -
246
// body has to be created, here in example code
247
// empty body block commented out
248
// 2)
249
// make.Method() with 'String body' parameter -
250
// body is added as a text. Used in our example.
251
MethodTree newMethod = make.Method(
252                             methodModifiers, // public
253
"writeExternal", // writeExternal
254
make.PrimitiveType(TypeKind.VOID), // return type "void"
255
Collections.<TypeParameterTree>emptyList(), // type parameters - none
256
Collections.<VariableTree>singletonList(parameter), // final ObjectOutput arg0
257
Collections.<ExpressionTree>singletonList(throwsClause), // throws
258
"{ throw new UnsupportedOperationException(\"Not supported yet.\") }", // body text
259
// make.Block(Collections.<StatementTree>emptyList(), false), // empty statement block
260
null // default value - not applicable here, used by annotations
261
);
262
263                         // and in the same way as interface was added to implements clause,
264
// add feature to the class:
265
ClassTree modifiedClazz = make.addClassMember(clazz, newMethod);
266                         workingCopy.rewrite(clazz, modifiedClazz);
267                     }
268                 }
269             }
270
271             public void cancel() {
272             }
273         };
274
275         tutorialSource.runModificationTask(task).commit();
276         
277         // print the result to the System.err to see the changes in console.
278
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(tutorialFile));
279         PrintStream JavaDoc out = System.out;
280         String JavaDoc str;
281         while ((str = in.readLine()) != null) {
282             out.println(str);
283         }
284         in.close();
285     }
286     
287     // creates and adds annotation to class modifiers
288
public void testAddAnnotation() throws FileStateInvalidException, IOException JavaDoc {
289         File JavaDoc tutorialFile = getFile(getSourceDir(), "/org/netbeans/test/codegen/Tutorial1.java");
290         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(tutorialFile));
291         
292         CancellableTask task = new CancellableTask<WorkingCopy>() {
293
294             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
295                 workingCopy.toPhase(Phase.RESOLVED);
296                 CompilationUnitTree cut = workingCopy.getCompilationUnit();
297                 
298                 TreeMaker make = workingCopy.getTreeMaker();
299                 for (Tree typeDecl : cut.getTypeDecls()) {
300                     // ensure that it is correct type declaration, i.e. class
301
if (Tree.Kind.CLASS == typeDecl.getKind()) {
302                         ClassTree clazz = (ClassTree) typeDecl;
303                         
304                         // create the copy of the annotation list:
305
List JavaDoc<? extends AnnotationTree> oldAnnList = clazz.getModifiers().getAnnotations();
306                         List JavaDoc<AnnotationTree> modifiedAnnList = new ArrayList JavaDoc<AnnotationTree>(oldAnnList);
307                         
308                         // create the new annotation and add it to the end
309
// of the list:
310
// Note:
311
// use make.QualIdent(e) for correct import/FQN handling.
312
AnnotationTree newAnnotation = make.Annotation(
313                                 make.Identifier("Override"),
314                                 Collections.<ExpressionTree>emptyList()
315                         );
316                         modifiedAnnList.add(newAnnotation);
317                         
318                         // create new class modifiers, flags aren't changed,
319
// annotation is added to the end of annotation list.
320
ModifiersTree classModifiers = make.Modifiers(
321                             clazz.getModifiers().getFlags(),
322                             modifiedAnnList
323                         );
324                         // rewrite the original modifiers with the new one:
325
workingCopy.rewrite(clazz.getModifiers(), classModifiers);
326                     }
327                 }
328             }
329
330             public void cancel() {
331             }
332         };
333
334         tutorialSource.runModificationTask(task).commit();
335         
336         // print the result to the System.err to see the changes in console.
337
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(tutorialFile));
338         PrintStream JavaDoc out = System.out;
339         String JavaDoc str;
340         while ((str = in.readLine()) != null) {
341             out.println(str);
342         }
343         in.close();
344     }
345     
346     // obtain, modify and replace the method body as a text
347
public void testForJean() throws FileStateInvalidException, IOException JavaDoc {
348         File JavaDoc tutorialFile = getFile(getSourceDir(), "/org/netbeans/test/codegen/Tutorial2.java");
349         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(tutorialFile));
350         
351         CancellableTask task = new CancellableTask<WorkingCopy>() {
352
353             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
354                 workingCopy.toPhase(Phase.RESOLVED);
355                 CompilationUnitTree cut = workingCopy.getCompilationUnit();
356                 
357                 TreeMaker make = workingCopy.getTreeMaker();
358                 // we know there is exactly one class, named Tutorial2.
359
// (ommiting test for kind corectness!)
360
ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
361                 // get the method, there is a default constructor and
362
// exactly one method, named demoMethod().
363
MethodTree method = (MethodTree) clazz.getMembers().get(1);
364                 BlockTree body = method.getBody();
365                 
366                 // get SourcePositions instance for your working copy and
367
// fetch out start and end position.
368
SourcePositions sp = workingCopy.getTrees().getSourcePositions();
369                 int start = (int) sp.getStartPosition(cut, body);
370                 int end = (int) sp.getEndPosition(cut, body);
371                 // get body text from source text
372
String JavaDoc bodyText = workingCopy.getText().substring(start, end);
373                 MethodTree modified = make.Method(
374                         method.getModifiers(), // copy original values
375
method.getName(),
376                         method.getReturnType(),
377                         method.getTypeParameters(),
378                         method.getParameters(),
379                         method.getThrows(),
380                         bodyText.replace("{0}", "-tag-replace-"), // replace body with the new text
381
null // not applicable here
382
);
383                 // rewrite the original modifiers with the new one:
384
workingCopy.rewrite(method, modified);
385             }
386
387             public void cancel() {
388             }
389         };
390
391         tutorialSource.runModificationTask(task).commit();
392         
393         // print the result to the System.err to see the changes in console.
394
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(tutorialFile));
395         PrintStream JavaDoc out = System.out;
396         String JavaDoc str;
397         while ((str = in.readLine()) != null) {
398             out.println(str);
399         }
400         in.close();
401     }
402     
403     // obtain, modify and replace the method body as a text
404
public void testForErno() throws FileStateInvalidException, IOException JavaDoc {
405         File JavaDoc tutorialFile = getFile(getSourceDir(), "/org/netbeans/test/codegen/Tutorial2.java");
406         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(tutorialFile));
407         
408         CancellableTask task = new CancellableTask<WorkingCopy>() {
409
410             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
411                 workingCopy.toPhase(Phase.RESOLVED);
412                 CompilationUnitTree cut = workingCopy.getCompilationUnit();
413                 
414                 TreeMaker make = workingCopy.getTreeMaker();
415                 // we know there is exactly one class, named Tutorial2.
416
// (ommiting test for kind corectness!)
417
ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
418                 // get the method, there is a default constructor and
419
// exactly one method, named demoMethod().
420
VariableTree var = make.Variable(make.Modifiers(
421                         Collections.<Modifier>emptySet(), Collections.<AnnotationTree>emptyList()),
422                         "myField",
423                         make.Identifier("MyClass"),
424                         make.MethodInvocation(
425                             Collections.<ExpressionTree>emptyList(),
426                             make.MemberSelect(make.Identifier("Something"), "getMyClass"),
427                             Collections.<ExpressionTree>emptyList()
428                         )
429                 );
430                 // rewrite the original modifiers with the new one:
431
ClassTree copy = make.addClassMember(clazz, var);
432                  workingCopy.rewrite(clazz, copy);
433             }
434
435             public void cancel() {
436             }
437         };
438
439         tutorialSource.runModificationTask(task).commit();
440         
441         // print the result to the System.err to see the changes in console.
442
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(tutorialFile));
443         PrintStream JavaDoc out = System.out;
444         String JavaDoc str;
445         while ((str = in.readLine()) != null) {
446             out.println(str);
447         }
448         in.close();
449     }
450     
451     // obtain, modify and replace the method body as a text
452
public void testMethodInvocation() throws Exception JavaDoc {
453         testFile = new File JavaDoc(getWorkDir(), "Test.java");
454         TestUtilities.copyStringToFile(testFile,
455             "package hierbas.del.litoral;\n\n" +
456             "import java.io.*;\n\n" +
457             "public class Test {\n" +
458             " public void taragui() {\n" +
459             " }\n" +
460             "}\n"
461             );
462         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(testFile));
463         
464         CancellableTask task = new CancellableTask<WorkingCopy>() {
465
466             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
467                 workingCopy.toPhase(Phase.RESOLVED);
468                 TreeMaker make = workingCopy.getTreeMaker();
469                 
470                 // make the outer invocation, i.e. "clone()"
471
MethodInvocationTree cloneInvocation = make.MethodInvocation(
472                         Collections.<ExpressionTree>emptyList(),
473                         make.Identifier("clone"),
474                         Collections.<ExpressionTree>emptyList()
475                 );
476                 
477                 // encapsulate 'toString' identifier to outer invocation
478
MemberSelectTree toStringSelIdent = make.MemberSelect(cloneInvocation, "toString");
479                 // make 'toString()' invocation
480
MethodInvocationTree toStringInvocation = make.MethodInvocation(
481                         Collections.<ExpressionTree>emptyList(),
482                         toStringSelIdent,
483                         Collections.<ExpressionTree>emptyList()
484                 );
485                 // make statement from created expression
486
ExpressionStatementTree statement = make.ExpressionStatement(toStringInvocation);
487                 
488                 // finally, find the correct body and rewrite it.
489
ClassTree clazz = (ClassTree) workingCopy.getCompilationUnit().getTypeDecls().get(0);
490                 MethodTree method = (MethodTree) clazz.getMembers().get(1);
491                 BlockTree copy = make.addBlockStatement(method.getBody(), statement);
492                 workingCopy.rewrite(method.getBody(), copy);
493             }
494             
495             public void cancel() {
496             }
497         };
498
499         tutorialSource.runModificationTask(task).commit();
500         
501         // print the result to the System.err to see the changes in console.
502
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(testFile));
503         PrintStream JavaDoc out = System.out;
504         String JavaDoc str;
505         while ((str = in.readLine()) != null) {
506             out.println(str);
507         }
508         in.close();
509     }
510
511     // obtain, modify and replace the method body as a text
512
public void testNullLiteral() throws Exception JavaDoc {
513         testFile = new File JavaDoc(getWorkDir(), "Test.java");
514         TestUtilities.copyStringToFile(testFile,
515             "package hierbas.del.litoral;\n\n" +
516             "import java.io.*;\n\n" +
517             "public class Test {\n" +
518             " public void taragui() {\n" +
519             " }\n" +
520             "}\n"
521             );
522         JavaSource tutorialSource = JavaSource.forFileObject(FileUtil.toFileObject(testFile));
523 // final String statementText = "new Runnable() { };";
524
// final String statementText = "System.err.println(\"Not interested in.\");";
525
final String JavaDoc statementText = "System.err.println(null);";
526         
527         CancellableTask task = new CancellableTask<WorkingCopy>() {
528
529             public void run(WorkingCopy workingCopy) throws java.io.IOException JavaDoc {
530                 workingCopy.toPhase(Phase.RESOLVED);
531                 TreeMaker make = workingCopy.getTreeMaker();
532                 
533                 SourcePositions[] positions = new SourcePositions[1];
534                 final TreeUtilities treeUtils = workingCopy.getTreeUtilities();
535                 StatementTree body = treeUtils.parseStatement(statementText, positions);
536                 System.err.println(TreeMakerDemo.reverse(body));
537             }
538             
539             public void cancel() {
540             }
541         };
542
543         tutorialSource.runModificationTask(task).commit();
544         
545         // print the result to the System.err to see the changes in console.
546
BufferedReader JavaDoc in = new BufferedReader JavaDoc(new FileReader JavaDoc(testFile));
547         PrintStream JavaDoc out = System.out;
548         String JavaDoc str;
549         while ((str = in.readLine()) != null) {
550             out.println(str);
551         }
552         in.close();
553     }
554     
555     // not important for tutorial reasons.
556
// please ignore.
557
String JavaDoc getSourcePckg() {
558         return "org/netbeans/test/codegen/";
559     }
560
561     String JavaDoc getGoldenPckg() {
562         return "org/netbeans/jmi/javamodel/codegen/ConstructorTest/ConstructorTest/";
563     }
564
565 }
566
Popular Tags