diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jdtutility/Member.java')
-rw-r--r-- | jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jdtutility/Member.java | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jdtutility/Member.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jdtutility/Member.java new file mode 100644 index 0000000000..87fba5c1e4 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jdtutility/Member.java @@ -0,0 +1,394 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.core.internal.jdtutility; + +import org.eclipse.core.filebuffers.FileBuffers; +import org.eclipse.core.filebuffers.ITextFileBuffer; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jpt.core.internal.ITextRange; +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.text.edits.TextEdit; + +/** + * Adapt and extend a JDT member with simplified annotation handling. + */ +public abstract class Member { + + private final IMember jdtMember; + + /** this will be null for a top-level type */ + private final Type declaringType; + + + // ********** constructor ********** + + Member(IMember jdtMember) { + super(); + this.jdtMember = jdtMember; + IType jdtDeclaringType = jdtMember.getDeclaringType(); + this.declaringType = (jdtDeclaringType == null) ? null : new Type(jdtDeclaringType); + } + + + // ********** accessors ********** + + public IMember getJdtMember() { + return this.jdtMember; + } + + public boolean wraps(IMember member) { + return this.jdtMember.exists() + && this.jdtMember.equals(member); + } + + /** + * this will return null for a top-level type + */ + public Type getDeclaringType() { + return this.declaringType; + } + + + // ********** miscellaneous ********** + + public ICompilationUnit compilationUnit() { + return this.jdtMember.getCompilationUnit(); + } + + public String getName() { + return this.jdtMember.getElementName(); + } + + public Type topLevelDeclaringType() { + return this.declaringType.topLevelDeclaringType(); + } + + /** + * note: this creates a *new* AST + */ + public CompilationUnit astRoot() { + return JDTTools.createASTRoot(this.jdtMember); + } + + public ModifiedDeclaration modifiedDeclaration() { + return this.modifiedDeclaration(this.astRoot()); + } + + public ModifiedDeclaration modifiedDeclaration(CompilationUnit astRoot) { + return new ModifiedDeclaration(this.bodyDeclaration(astRoot)); + } + + public BodyDeclaration bodyDeclaration() { + return this.bodyDeclaration(this.astRoot()); + } + + public ITextRange textRange() { + return this.textRange(this.astRoot()); + } + + public ITextRange textRange(CompilationUnit astRoot) { + return this.textRange(this.bodyDeclaration(astRoot)); + } + + ITextRange textRange(BodyDeclaration bodyDeclaration) { + return new ASTNodeTextRange(bodyDeclaration); + } + + /** + * this will throw a NPE for a top-level type + */ + TypeDeclaration declaringTypeDeclaration(CompilationUnit astRoot) { + return this.declaringType.typeDeclaration(astRoot); + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.getName()); + } + + + // ********** abstract methods ********** + + /** + * Return the member's body declaration. + */ + public abstract BodyDeclaration bodyDeclaration(CompilationUnit astRoot); + + + // ********** annotations ********** + + public Annotation annotation(DeclarationAnnotationAdapter adapter, CompilationUnit astRoot) { + return adapter.getAnnotation(this.modifiedDeclaration(astRoot)); + } + + public Annotation annotation(DeclarationAnnotationAdapter adapter) { + return this.annotation(adapter, this.astRoot()); + } + + public boolean containsAnnotation(DeclarationAnnotationAdapter adapter, CompilationUnit astRoot) { + return this.annotation(adapter, astRoot) != null; + } + + public boolean containsAnnotation(DeclarationAnnotationAdapter adapter) { + return this.containsAnnotation(adapter, this.astRoot()); + } + + /** + * Return whether the member contains any one of the specified annotations. + */ + public boolean containsAnyAnnotation(DeclarationAnnotationAdapter[] adapters) { + return this.containsAnyAnnotation(adapters, this.astRoot()); + } + + /** + * Return whether the member contains any one of the specified annotations. + */ + public boolean containsAnyAnnotation(DeclarationAnnotationAdapter[] adapters, CompilationUnit astRoot) { + for (DeclarationAnnotationAdapter adapter : adapters) { + if (this.containsAnnotation(adapter, astRoot)) { + return true; + } + } + return false; + } + + /** + * Return the text range corresponding to the specified annotation. + * If the annotation is missing, return null. + */ + public ITextRange annotationTextRange(DeclarationAnnotationAdapter adapter, CompilationUnit astRoot) { + Annotation annotation = this.annotation(adapter, astRoot); + return (annotation == null) ? null : new ASTNodeTextRange(annotation); + } + + /** + * Return the text range corresponding to the specified annotation. + * If the annotation is missing, return null. + */ + public ITextRange annotationTextRange(DeclarationAnnotationAdapter adapter) { + return this.annotationTextRange(adapter, this.astRoot()); + } + + /** + * Return the AST node corresponding to the specified annotation. + * If the annotation is missing, return its parent node. + */ + public ASTNode annotationASTNode(DeclarationAnnotationAdapter adapter, CompilationUnit astRoot) { + return adapter.astNode(this.modifiedDeclaration(astRoot)); + } + + /** + * Return the AST node corresponding to the specified annotation. + * If the annotation is missing, return its parent node. + */ + public ASTNode annotationASTNode(DeclarationAnnotationAdapter adapter) { + return this.annotationASTNode(adapter, this.astRoot()); + } + + /** + * Add the specified marker annotation to the member. + */ + public void newMarkerAnnotation(final DeclarationAnnotationAdapter adapter) { + this.edit(new Editor() { + public void edit(ModifiedDeclaration declaration) { + adapter.newMarkerAnnotation(declaration); + } + }); + } + + /** + * Add the specified single member annotation to the member. + */ + public void newSingleMemberAnnotation(final DeclarationAnnotationAdapter adapter) { + this.edit(new Editor() { + public void edit(ModifiedDeclaration declaration) { + adapter.newSingleMemberAnnotation(declaration); + } + }); + } + + /** + * Add the specified normal annotation to the member. + */ + public void newNormalAnnotation(final DeclarationAnnotationAdapter adapter) { + this.edit(new Editor() { + public void edit(ModifiedDeclaration declaration) { + adapter.newNormalAnnotation(declaration); + } + }); + } + + /** + * Remove the specified annotation from the member. + */ + public void removeAnnotation(final DeclarationAnnotationAdapter adapter) { + this.edit(new Editor() { + public void edit(ModifiedDeclaration declaration) { + adapter.removeAnnotation(declaration); + } + }); + } + + + // ********** annotation elements ********** + + public Object annotationElementValue(DeclarationAnnotationElementAdapter adapter, CompilationUnit astRoot) { + return adapter.getValue(this.modifiedDeclaration(astRoot)); + } + + public Object annotationElementValue(DeclarationAnnotationElementAdapter adapter) { + return this.annotationElementValue(adapter, this.astRoot()); + } + + public Expression annotationElementExpression(DeclarationAnnotationElementAdapter adapter, CompilationUnit astRoot) { + return adapter.expression(this.modifiedDeclaration(astRoot)); + } + + public Expression annotationElementExpression(DeclarationAnnotationElementAdapter adapter) { + return this.annotationElementExpression(adapter, this.astRoot()); + } + + public boolean containsAnnotationElement(DeclarationAnnotationElementAdapter adapter, CompilationUnit astRoot) { + return this.annotationElementExpression(adapter, astRoot) != null; + } + + public boolean containsAnnotationElement(DeclarationAnnotationElementAdapter adapter) { + return this.containsAnnotationElement(adapter, this.astRoot()); + } + + /** + * Return the text range corresponding to the specified element. + * If the element is missing, return null. + */ + public ITextRange annotationElementTextRange(DeclarationAnnotationElementAdapter adapter, CompilationUnit astRoot) { + Expression expression = this.annotationElementExpression(adapter, astRoot); + return (expression == null) ? null : new ASTNodeTextRange(expression); + } + + /** + * Return the text range corresponding to the specified element. + * If the element is missing, return null. + */ + public ITextRange annotationElementTextRange(DeclarationAnnotationElementAdapter adapter) { + return this.annotationElementTextRange(adapter, this.astRoot()); + } + + /** + * Return the AST node corresponding to the specified element. + * If the element is missing, return its parent node. + */ + public ASTNode annotationElementASTNode(DeclarationAnnotationElementAdapter adapter, CompilationUnit astRoot) { + return adapter.astNode(this.modifiedDeclaration(astRoot)); + } + + /** + * Return the AST node corresponding to the specified element. + * If the element is missing, return its parent node. + */ + public ASTNode annotationElementASTNode(DeclarationAnnotationElementAdapter adapter) { + return this.annotationElementASTNode(adapter, this.astRoot()); + } + + /** + * Set the value of the specified element. + */ + public void setAnnotationElementValue(final DeclarationAnnotationElementAdapter adapter, final Object value) { + this.edit(new Editor() { + public void edit(ModifiedDeclaration declaration) { + adapter.setValue(value, declaration); + } + }); + } + + + // ********** editing ********** + + /** + * Edit the member with the specified editor. + * The editor will be invoked once the member's compilation unit + * is in an editable state. + */ + public void edit(Editor editor) { + try { + this.edit_(editor); + } catch (JavaModelException ex) { + throw new RuntimeException(ex); + } catch (BadLocationException ex) { + throw new RuntimeException(ex); + } + } + + /** + * NB: Be careful changing this method. + * Things to look out for: + * - when editing via the JavaEditor there is no need to create a working copy + * - when editing headlessly, a "working copy" must be created + * (at least as far as I can tell ~kfm) + * - when editing via a plain text editor, make a working copy or else things are screwed + * up the second time you edit through the Persistence Properties View + */ + private void edit_(Editor editor) throws JavaModelException, BadLocationException { + ICompilationUnit compilationUnit = this.compilationUnit(); + if ( ! compilationUnit.isWorkingCopy()) { + compilationUnit.becomeWorkingCopy(null, null); + } + + ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(compilationUnit.getResource().getFullPath()); + boolean textEditorPresent = (buffer != null); + IDocument doc = textEditorPresent ? + buffer.getDocument() + : + new Document(compilationUnit.getBuffer().getContents()); + + CompilationUnit astRoot = this.astRoot(); + astRoot.recordModifications(); + + editor.edit(this.modifiedDeclaration(astRoot)); + + TextEdit edits = astRoot.rewrite(doc, compilationUnit.getJavaProject().getOptions(true)); + AnnotationEditFormatter formatter = new AnnotationEditFormatter(doc); + formatter.apply(edits); + + if ( ! textEditorPresent) { + compilationUnit.getBuffer().setContents(doc.get()); + compilationUnit.commitWorkingCopy(true, null); + compilationUnit.discardWorkingCopy(); + } + } + + + // ********** "editor" interface ********** + + /** + * This interface defines a callback that is invoked when the member's + * compilation unit is in a state to be manipulated. + */ + public interface Editor { + + /** + * Edit the specified declaration. + */ + void edit(ModifiedDeclaration declaration); + + } + +} |