| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
| <head> |
| <meta name="copyright" content= |
| "Copyright (c) IBM Corporation and others 2000, 2011. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." /> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
| <meta http-equiv="Content-Style-Type" content="text/css" /> |
| <link rel="STYLESHEET" href="../book.css" charset="ISO-8859-1" type="text/css" /> |
| <title>Manipulating Java code</title> |
| <link rel="stylesheet" type="text/css" href="../book.css" /> |
| |
| </head> |
| <body> |
| <h2>Manipulating Java code</h2> |
| <p>Your plug-in can use the JDT API to create classes or interfaces, add methods to existing types, |
| or alter the methods for types.</p> |
| |
| <p>The simplest way to alter Java objects is to use the Java element API. More general techniques |
| can be used to work with the raw source code for a Java element.</p> |
| <h3>Code modification using Java elements</h3> |
| <h4>Generating a compilation unit</h4> |
| <p>The easiest way to programmatically generate a compilation unit is to use <b><a href= |
| "../reference/api/org/eclipse/jdt/core/IPackageFragment.html#createCompilationUnit(java.lang.String,%20java.lang.String,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| IPackageFragment.createCompilationUnit</a></b>. You specify the name and contents of the |
| compilation unit. The compilation unit is created inside the package and the new <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html">ICompilationUnit</a></b> is |
| returned.</p> |
| <p>A compilation unit can be created generically by creating a file resource whose extension is |
| "<b>.java"</b> in the appropriate folder that corresponds to the package directory. Using the |
| generic resource API is a back door to the Java tooling, so the Java model is not updated until the |
| generic resource change listeners are notified and the JDT listeners update the Java model with the |
| new compilation unit.</p> |
| |
| <h4>Modifying a compilation unit</h4> |
| <p>Most simple modifications of Java source can be done using the Java element API.</p> |
| <p>For example, you can query a type from a compilation unit. Once you have the <a href= |
| "../reference/api/org/eclipse/jdt/core/IType.html"><b>IType</b></a>, you can use protocols such as |
| <a href= |
| "../reference/api/org/eclipse/jdt/core/IType.html#createField(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>createField</b></a>, <a href= |
| "../reference/api/org/eclipse/jdt/core/IType.html#createInitializer(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>createInitializer</b></a>, <a href= |
| "../reference/api/org/eclipse/jdt/core/IType.html#createMethod(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>createMethod</b></a>, or <a href= |
| "../reference/api/org/eclipse/jdt/core/IType.html#createType(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| |
| <b>createType</b></a> to add source code members to the type. The source code and information about |
| the location of the member is supplied in these methods.</p> |
| <p>The <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ISourceManipulation.html">ISourceManipulation</a></b> |
| interface defines common source manipulations for Java elements. This includes methods for |
| renaming, moving, copying, or deleting a type's member.</p> |
| <h4>Working copies</h4> |
| <p>Code can be modified by manipulating the compilation unit (and thus the underlying <a href= |
| "../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IFile.html"><b>IFile</b></a> |
| is modified) or one can modify an in-memory copy of the compilation unit called a working copy.</p> |
| <p>A working copy is obtained from a compilation unit using the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#getWorkingCopy(org.eclipse.core.runtime.IProgressMonitor)"> |
| |
| getWorkingCopy</a></b> method. (Note that the compilation unit does not need to exist in the Java |
| model in order for a working copy to be created.) Whoever creates such a working copy is |
| responsible for discarding it when not needed any longer using the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#discardWorkingCopy()">discardWorkingCopy</a></b> |
| method.</p> |
| <p>Working copies modify an in-memory buffer. The <b>getWorkingCopy()</b> method creates a default |
| buffer, but clients can provide their own buffer implementation using the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ITypeRoot.html#getWorkingCopy(org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| getWorkingCopy(WorkingCopyOwner, IProgressMonitor)</a></b> method. Clients can manipulate the text |
| of this buffer directly. If they do so, they must synchronize the working copy with the buffer from |
| time to time using either the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| |
| reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</a></b> method.</p> |
| <p>Finally a working copy can be saved to disk (replacing the original compilation unit) using the |
| <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#commitWorkingCopy(boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| commitWorkingCopy</a></b> method. </p> |
| <p>For example the following code snippet creates a working copy on a compilation unit using a |
| custom working copy owner. The snippet modifies the buffer, reconciles the changes, commits the |
| changes to disk and finally discards the working copy.</p> |
| <pre class="color1"> |
| // Get original compilation unit |
| ICompilationUnit originalUnit = ...; |
| |
| // Get working copy owner |
| WorkingCopyOwner owner = ...; |
| |
| // Create working copy |
| ICompilationUnit workingCopy = originalUnit.getWorkingCopy(owner, null); |
| |
| // Modify buffer and reconcile |
| IBuffer buffer = ((IOpenable)workingCopy).getBuffer(); |
| buffer.append("class X {}"); |
| workingCopy.reconcile(ICompilationUnit.NO_AST, false, null, null); |
| |
| // Commit changes |
| workingCopy.commitWorkingCopy(false, null); |
| |
| // Destroy working copy |
| workingCopy.discardWorkingCopy(); |
| </pre> |
| <p>The compilation unit's buffer can also be modified using the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#applyTextEdit(org.eclipse.text.edits.TextEdit,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| ICompilationUnit.applyTextEdit</a></b> method.</p> |
| <pre class="color1"> |
| // Get original compilation unit |
| ICompilationUnit originalUnit = ...; |
| |
| // Get working copy owner |
| WorkingCopyOwner owner = ...; |
| |
| // Create working copy |
| ICompilationUnit workingCopy = originalUnit.getWorkingCopy(owner, null); |
| |
| // Get text edits |
| TextEdit edit = ...; |
| |
| // Modify buffer and reconcile |
| workingCopy.applyTextEdit(edit, null); |
| workingCopy.reconcile(ICompilationUnit.NO_AST, false, null, null); |
| |
| // Commit changes |
| workingCopy.commitWorkingCopy(false, null); |
| |
| // Destroy working copy |
| workingCopy.discardWorkingCopy(); |
| </pre> |
| <p>Working copies can also be shared by several clients using a working copy owner. A working copy |
| can be later retrieved using the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#findWorkingCopy(org.eclipse.jdt.core.WorkingCopyOwner)"> |
| findWorkingCopy</a></b> method. A shared working copy is thus keyed on the original compilation |
| unit and on a working copy owner.</p> |
| |
| <p>The following shows how client 1 creates a shared working copy, client 2 retrieves this working |
| copy, client 1 discards the working copy, and client 2 trying to retrieve the shared working copy |
| notices it does not exist any longer:</p> |
| <pre class="color1"> |
| // Client 1 & 2: Get original compilation unit |
| ICompilationUnit originalUnit = ...; |
| |
| // Client 1 & 2: Get working copy owner |
| WorkingCopyOwner owner = ...; |
| |
| // Client 1: Create shared working copy |
| ICompilationUnit workingCopyForClient1 = originalUnit.getWorkingCopy(owner, null); |
| |
| // Client 2: Retrieve shared working copy |
| ICompilationUnit workingCopyForClient2 = originalUnit.findWorkingCopy(owner); |
| |
| // This is the same working copy |
| assert workingCopyForClient1 == workingCopyForClient2; |
| |
| // Client 1: Discard shared working copy |
| workingCopyForClient1.discardWorkingCopy(); |
| |
| // Client 2: Attempt to retrieve shared working copy and find out it's null |
| workingCopyForClient2 = originalUnit.findWorkingCopy(owner); |
| assert workingCopyForClient2 == null; |
| </pre> |
| <h3>Code modification using the DOM/AST API</h3> |
| There are three ways to create a <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html">CompilationUnit</a></b>. The first |
| one is to use <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b>. The second is to use |
| |
| <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| ICompilationUnit#reconcile(...)</a></b>. The third is to start from scratch using the factory |
| methods on <b><a href="../reference/api/org/eclipse/jdt/core/dom/AST.html">AST</a></b> (Abstract |
| Syntax Tree). |
| <h4>Creating an AST from existing source code</h4> |
| An instance of <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b> must be created with |
| <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#newParser(int)">ASTParser.newParser(int)</a></b>.<br /> |
| |
| <br /> |
| |
| The source code is given to the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b> with one of the |
| following methods: |
| <ul> |
| <li><b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(char[])">setSource(char[])</a></b>: |
| to create the AST from source code</li> |
| <li><b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(org.eclipse.jdt.core.IClassFile)"> |
| setSource(IClassFile)</a></b>: to create the AST from a classfile</li> |
| <li><b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(org.eclipse.jdt.core.ICompilationUnit)"> |
| setSource(ICompilationUnit)</a></b>: to create the AST from a compilation unit</li> |
| </ul> |
| |
| Then the AST is created by calling <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#createAST(org.eclipse.core.runtime.IProgressMonitor)"> |
| createAST(IProgressMonitor)</a></b>.<br /> |
| <br /> |
| The result is an AST with correct source positions for each node. The resolution of bindings has to |
| be requested before the creation of the tree with <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setResolveBindings(boolean)">setResolveBindings(boolean)</a></b>. |
| Resolving the bindings is a costly operation and should be done only when necessary. As soon as the |
| tree has been modified, all positions and bindings are lost.<br /> |
| Note that some bindings recovery can also be done during this resolution with <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setBindingsRecovery(boolean)">setBindingsRecovery(boolean)</a></b>. |
| Using this recovery, some bindings - <i>typically missing types</i> - will no longer be |
| <code>null</code>, hence improving the resilience of any clients using the AST tree. |
| |
| <h4>Creating an AST by reconciling a working copy</h4> |
| If a working copy is not consistent (has been modified) then an AST can be created by calling the |
| method <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</a></b>. To request AST creation, call |
| the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| reconcile(...)</a></b> method with <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/AST.html#JLS3">AST.JLS3</a></b> as first |
| parameter.<br /> |
| <br /> |
| Its bindings are computed only if the problem requestor is active, or if the problem detection is |
| forced. Resolving the bindings is a costly operation and should be done only when necessary. As |
| soon as the tree has been modified, all positions and bindings are lost.<br /> |
| |
| Note that some bindings recovery can also be done during this resolution with by using the method |
| <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20int,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| reconcile(int, int, WorkingCopyOwner, IProgressMonitor)</a></b> with the flag <b><a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#ENABLE_BINDINGS_RECOVERY">ENABLE_BINDINGS_RECOVERY</a></b> |
| set on the second parameter. Using this recovery, some bindings - <i>typically missing types</i> - |
| will no longer be <code>null</code>, hence improving the resilience of any clients using the AST |
| tree. |
| <h4>From scratch</h4> |
| <p>It is possible to create a <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html">CompilationUnit</a></b> from |
| scratch using the factory methods on <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/AST.html">AST</a></b>. These method names start with |
| |
| <b>new...</b>. The following is an example that creates a <b>HelloWorld</b> class.</p> |
| <p>The first snippet is the generated output:</p> |
| <pre class="color1"> |
| package example; |
| import java.util.*; |
| public class HelloWorld { |
| public static void main(String[] args) { |
| System.out.println("Hello" + " world"); |
| } |
| } |
| </pre> |
| <p>The following snippet is the corresponding code that generates the output.</p> |
| <pre class="color1"> |
| |
| AST ast = AST.newAST(AST.JLS3); |
| CompilationUnit unit = ast.newCompilationUnit(); |
| PackageDeclaration packageDeclaration = ast.newPackageDeclaration(); |
| packageDeclaration.setName(ast.newSimpleName("example")); |
| unit.setPackage(packageDeclaration); |
| ImportDeclaration importDeclaration = ast.newImportDeclaration(); |
| QualifiedName name = |
| ast.newQualifiedName( |
| ast.newSimpleName("java"), |
| ast.newSimpleName("util")); |
| importDeclaration.setName(name); |
| importDeclaration.setOnDemand(true); |
| unit.imports().add(importDeclaration); |
| TypeDeclaration type = ast.newTypeDeclaration(); |
| type.setInterface(false); |
| type.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD)); |
| type.setName(ast.newSimpleName("HelloWorld")); |
| MethodDeclaration methodDeclaration = ast.newMethodDeclaration(); |
| methodDeclaration.setConstructor(false); |
| List modifiers = methodDeclaration.modifiers(); |
| modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD)); |
| modifiers.add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD)); |
| methodDeclaration.setName(ast.newSimpleName("main")); |
| methodDeclaration.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID)); |
| SingleVariableDeclaration variableDeclaration = ast.newSingleVariableDeclaration(); |
| variableDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName("String")))); |
| variableDeclaration.setName(ast.newSimpleName("args")); |
| methodDeclaration.parameters().add(variableDeclaration); |
| org.eclipse.jdt.core.dom.Block block = ast.newBlock(); |
| MethodInvocation methodInvocation = ast.newMethodInvocation(); |
| name = |
| ast.newQualifiedName( |
| ast.newSimpleName("System"), |
| ast.newSimpleName("out")); |
| methodInvocation.setExpression(name); |
| methodInvocation.setName(ast.newSimpleName("println")); |
| InfixExpression infixExpression = ast.newInfixExpression(); |
| infixExpression.setOperator(InfixExpression.Operator.PLUS); |
| StringLiteral literal = ast.newStringLiteral(); |
| literal.setLiteralValue("Hello"); |
| infixExpression.setLeftOperand(literal); |
| literal = ast.newStringLiteral(); |
| literal.setLiteralValue(" world"); |
| infixExpression.setRightOperand(literal); |
| methodInvocation.arguments().add(infixExpression); |
| ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation); |
| block.statements().add(expressionStatement); |
| methodDeclaration.setBody(block); |
| type.bodyDeclarations().add(methodDeclaration); |
| unit.types().add(type); |
| </pre> |
| <h4>Retrieving extra positions</h4> |
| <p>The DOM/AST node contains only a pair of positions (the starting position and the length of the |
| node). This is not always sufficient. In order to retrieve intermediate positions, the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/compiler/IScanner.html">IScanner</a></b> API should be used. |
| For example, we have an <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/InstanceofExpression.html">InstanceofExpression</a></b> |
| for which we want to know the positions of the <i>instanceof</i> operator. We could write the |
| following method to achieve this:</p> |
| |
| <pre class="color1"> |
| |
| private int[] getOperatorPosition(Expression expression, char[] source) { |
| if (expression instanceof InstanceofExpression) { |
| IScanner scanner = ToolFactory.createScanner(false, false, false, false); |
| scanner.setSource(source); |
| int start = expression.getStartPosition(); |
| int end = start + expression.getLength(); |
| scanner.resetTo(start, end); |
| int token; |
| try { |
| while ((token = scanner.getNextToken()) != ITerminalSymbols.TokenNameEOF) { |
| switch(token) { |
| case ITerminalSymbols.TokenNameinstanceof: |
| return new int[] {scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition()}; |
| } |
| } |
| } catch (InvalidInputException e) { |
| } |
| } |
| return null; |
| } |
| </pre> |
| <p>The <b><a href="../reference/api/org/eclipse/jdt/core/compiler/IScanner.html">IScanner</a></b> |
| is used to divide the input source into tokens. Each token has a specific value that is defined in |
| the <b><a href= |
| "../reference/api/org/eclipse/jdt/core/compiler/ITerminalSymbols.html">ITerminalSymbols</a></b> |
| interface. It is fairly simple to iterate and retrieve the right token. We also recommend that you |
| use the scanner if you want to find the position of the <i>super</i> keyword in a <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/SuperMethodInvocation.html">SuperMethodInvocation</a></b>.</p> |
| |
| <h4>Source code modifications</h4> |
| <p>Some source code modifications are not provided via the Java element API. A more general way to |
| edit source code (such as changing the source code for existing elements) is accomplished using the |
| compilation unit's raw source code and the rewrite API of the DOM/AST.</p> |
| <p>To perform DOM/AST rewriting, there are two sets of API: the descriptive rewriting and the |
| modifying rewriting.</p> |
| <p>The descriptive API does not modify the AST but use <b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.html">ASTRewrite</a></b> API to |
| generate the descriptions of modifications. The AST rewriter collects descriptions of modifications |
| to nodes and translates these descriptions into text edits that can then be applied to the original |
| source.</p> |
| <pre class="color1"> |
| |
| // creation of a Document |
| ICompilationUnit cu = ... ; // content is "public class X {\n}" |
| String source = cu.getSource(); |
| Document document= new Document(source); |
| |
| // creation of DOM/AST from a ICompilationUnit |
| ASTParser parser = ASTParser.newParser(AST.JLS3); |
| parser.setSource(cu); |
| CompilationUnit astRoot = (CompilationUnit) parser.createAST(null); |
| |
| // creation of ASTRewrite |
| ASTRewrite rewrite = ASTRewrite.create(astRoot.getAST()); |
| |
| // description of the change |
| SimpleName oldName = ((TypeDeclaration)astRoot.types().get(0)).getName(); |
| SimpleName newName = astRoot.getAST().newSimpleName("Y"); |
| rewrite.replace(oldName, newName, null); |
| |
| // computation of the text edits |
| TextEdit edits = rewrite.rewriteAST(document, cu.getJavaProject().getOptions(true)); |
| |
| // computation of the new source code |
| edits.apply(document); |
| String newSource = document.get(); |
| |
| // update of the compilation unit |
| cu.getBuffer().setContents(newSource); |
| </pre> |
| <p>The modifying API allows to modify directly the AST:</p> |
| |
| <ul> |
| <li>Request the recording of modifications (<b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html#recordModifications()">CompilationUnit.recordModifications()</a></b>).</li> |
| <li>Perform the modifications on the AST Nodes.</li> |
| <li>And when the modifications are finished, generate text edits that can then be applied to the |
| original source (<b><a href= |
| "../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html#rewrite(org.eclipse.jface.text.IDocument,%20java.util.Map)">CompilationUnit.rewrite(...)</a></b>).</li> |
| </ul> |
| <pre class="color1"> |
| // creation of a Document |
| ICompilationUnit cu = ... ; // content is "public class X {\n}" |
| String source = cu.getSource(); |
| Document document= new Document(source); |
| |
| // creation of DOM/AST from a ICompilationUnit |
| ASTParser parser = ASTParser.newParser(AST.JLS3); |
| parser.setSource(cu); |
| CompilationUnit astRoot = (CompilationUnit) parser.createAST(null); |
| |
| // start record of the modifications |
| astRoot.recordModifications(); |
| |
| // modify the AST |
| TypeDeclaration typeDeclaration = (TypeDeclaration)astRoot.types().get(0); |
| SimpleName newName = astRoot.getAST().newSimpleName("Y"); |
| typeDeclaration.setName(newName); |
| |
| // computation of the text edits |
| TextEdit edits = astRoot.rewrite(document, cu.getJavaProject().getOptions(true)); |
| |
| // computation of the new source code |
| edits.apply(document); |
| String newSource = document.get(); |
| |
| // update of the compilation unit |
| cu.getBuffer().setContents(newSource); |
| </pre> |
| <h3><a name="javadeltas" id="javadeltas">Responding to changes in Java elements</a></h3> |
| <p>If your plug-in needs to know about changes to Java elements after the fact, you can register a |
| Java <a href= |
| "../reference/api/org/eclipse/jdt/core/IElementChangedListener.html"><b>IElementChangedListener</b></a> |
| with <a href="../reference/api/org/eclipse/jdt/core/JavaCore.html"><b>JavaCore</b></a>.</p> |
| <pre class="color1"> |
| |
| JavaCore.addElementChangedListener(new MyJavaElementChangeReporter()); |
| </pre> |
| <p>You can be more specific and specify the type of events you're interested in using <a href= |
| "../reference/api/org/eclipse/jdt/core/JavaCore.html#addElementChangedListener(org.eclipse.jdt.core.IElementChangedListener,%20int)"> |
| |
| <b>addElementChangedListener(IElementChangedListener, int)</b></a>.</p> |
| <p>For example, if you're only interested in listening for events during a reconcile operation:</p> |
| <pre class="color1"> |
| |
| JavaCore.addElementChangedListener(new MyJavaElementChangeReporter(), ElementChangedEvent.POST_RECONCILE); |
| </pre> |
| <p>There are two kinds of events that are supported by <b>JavaCore</b>:</p> |
| <ul> |
| <li><a href= |
| "../reference/api/org/eclipse/jdt/core/ElementChangedEvent.html#POST_CHANGE"><b>POST_CHANGE</b></a>: |
| Listeners of this event kind will get notified during the corresponding <a href= |
| "../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IResourceChangeEvent.html#POST_CHANGE"> |
| |
| <b>POST_CHANGE</b></a> resource change notification.</li> |
| <li><a href= |
| "../reference/api/org/eclipse/jdt/core/ElementChangedEvent.html#POST_RECONCILE"><b>POST_RECONCILE</b></a>: |
| Listeners of this event kind will get notified at the end of a reconcile operation on a working |
| copy (see <a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>ICompilationUnit.reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</b></a>).</li> |
| </ul> |
| <p>Java element change listeners are similar conceptually to resource change listeners (described |
| in <a href="../../org.eclipse.platform.doc.isv/guide/resAdv_events.htm" class="XRef">tracking |
| resource changes</a>). The following snippet implements a Java element change reporter that prints |
| the element deltas to the system console.</p> |
| <pre class="color1"> |
| |
| public class MyJavaElementChangeReporter implements IElementChangedListener { |
| public void elementChanged(ElementChangedEvent event) { |
| IJavaElementDelta delta= event.getDelta(); |
| if (delta != null) { |
| System.out.println("delta received: "); |
| System.out.print(delta); |
| } |
| } |
| } |
| </pre> |
| <p>The <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html"><b>IJavaElementDelta</b></a> |
| includes the <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getElement()">element</a> that was |
| changed and <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getFlags()">flags</a> describing the |
| kind of change that occurred. Most of the time the delta tree is rooted at the Java Model level. |
| Clients must then navigate this delta using <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAffectedChildren()"><b>getAffectedChildren</b></a> |
| to find out what projects have changed.</p> |
| |
| <p>The following example method traverses a delta and prints the elements that have been added, |
| removed and changed:</p> |
| <pre class="color1"> |
| |
| void traverseAndPrint(IJavaElementDelta delta) { |
| switch (delta.getKind()) { |
| case IJavaElementDelta.ADDED: |
| System.out.println(delta.getElement() + " was added"); |
| break; |
| case IJavaElementDelta.REMOVED: |
| System.out.println(delta.getElement() + " was removed"); |
| break; |
| case IJavaElementDelta.CHANGED: |
| System.out.println(delta.getElement() + " was changed"); |
| if ((delta.getFlags() & IJavaElementDelta.F_CHILDREN) != 0) { |
| System.out.println("The change was in its children"); |
| } |
| if ((delta.getFlags() & IJavaElementDelta.F_CONTENT) != 0) { |
| System.out.println("The change was in its content"); |
| } |
| /* Others flags can also be checked */ |
| break; |
| } |
| IJavaElementDelta[] children = delta.getAffectedChildren(); |
| for (int i = 0; i < children.length; i++) { |
| traverseAndPrint(children[i]); |
| } |
| } |
| </pre> |
| <p>Since <a href="../reference/api/org/eclipse/jdt/core/IAnnotation.html"><b>IAnnotation</b></a>s |
| are not children of any Java element, annotation deltas are obtained using <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAnnotationDeltas()"><b>getAnnotationDeltas()</b></a>.</p> |
| |
| <p>Several kinds of operations can trigger a Java element change notification. Here are some |
| examples:</p> |
| <ul> |
| <li>Creating a resource, e.g. <a href= |
| "../reference/api/org/eclipse/jdt/core/IPackageFragment.html#createCompilationUnit(java.lang.String,%20java.lang.String,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>IPackageFragment.createCompilationUnit</b></a> (the delta indicates the <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#ADDED">addition</a> of the |
| compilation unit)</li> |
| <li>Modifying a resource, e.g. <a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#createType(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>ICompilationUnit.createType</b></a> (the delta indicates that the compilation unit has <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#CHANGED">changed</a> and that a type |
| was <a href="../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAddedChildren()">added |
| as a child</a> of this compilation unit)</li> |
| |
| <li>Modifying a project's classpath, e.g. <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaProject.html#setRawClasspath(org.eclipse.jdt.core.IClasspathEntry[],%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>IJavaProject.setRawClasspath</b></a> (the delta indicates that package fragment roots have been |
| <a href="../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_ADDED_TO_CLASSPATH">added |
| to the classpath</a>, <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_REMOVED_FROM_CLASSPATH">removed |
| from the classpath</a>, or <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_CLASSPATH_REORDER">reordered on the |
| classpath</a>)</li> |
| <li>Modifying a classpath variable value, e.g. <a href= |
| "../reference/api/org/eclipse/jdt/core/JavaCore.html#setClasspathVariable(java.lang.String,%20org.eclipse.core.runtime.IPath,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>JavaCore.setClasspathVariable</b></a> (the delta also indicates that package fragment roots have |
| been affected)</li> |
| |
| <li>Reconciling a working copy with its buffer, e.g. <a href= |
| "../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)"> |
| <b>ICompilationUnit.reconcile</b></a></li> |
| <li>Modifying an <a href= |
| "../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IFile.html"><b>IFile</b></a> |
| that ends with ".java" and that is on the project's classpath, e.g. using <b>IFile.setContents</b> |
| (the delta indicates that a compilation unit was changed, but <a href= |
| "../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_FINE_GRAINED">no finer-grained |
| information</a> is provided as this was not done through a Java Model operation)</li> |
| </ul> |
| <p>Similar to <a href= |
| "../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IResourceDelta.html"><b> |
| |
| IResourceDelta</b></a> the Java element deltas can be batched using an <a href= |
| "../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IWorkspaceRunnable.html"> |
| <b>IWorkspaceRunnable</b></a>. The deltas resulting from several Java Model operations that are run |
| inside a <b>IWorkspaceRunnable</b> are merged and reported at once. </p> |
| <p><a href="../reference/api/org/eclipse/jdt/core/JavaCore.html"><b>JavaCore</b></a>provides a |
| <b>run</b> method for batching Java element changes.</p> |
| <p>For example, the following code fragment will trigger 2 Java element change events:</p> |
| |
| <pre class="color1"> |
| |
| // Get package |
| IPackageFragment pkg = ...; |
| |
| // Create 2 compilation units |
| ICompilationUnit unitA = pkg.createCompilationUnit("A.java", "public class A {}", false, null); |
| ICompilationUnit unitB = pkg.createCompilationUnit("B.java", "public class B {}", false, null); |
| </pre> |
| <p>Whereas the following code fragment will trigger 1 Java element change event:</p> |
| <pre class="color1"> |
| |
| // Get package |
| final IPackageFragment pkg = ...; |
| |
| // Create 2 compilation units |
| JavaCore.run( |
| new IWorkspaceRunnable() { |
| public void run(IProgressMonitor monitor) throws CoreException { |
| ICompilationUnit unitA = pkg.createCompilationUnit("A.java", "public class A {}", false, null); |
| ICompilationUnit unitB = pkg.createCompilationUnit("B.java", "public class B {}", false, null); |
| } |
| }, |
| null); |
| </pre> |
| </body> |
| </html> |