diff options
author | kmoore | 2010-11-11 23:33:35 +0000 |
---|---|---|
committer | kmoore | 2010-11-11 23:33:35 +0000 |
commit | bb86ecc161fdcf23f5db16b8049edec016062ce6 (patch) | |
tree | fdade77ed88eddcc8dbe3041e5ee79995111f65e | |
parent | 1d3054671a85738fd8a8bdfa717b0caf609b339c (diff) | |
download | webtools.dali-bb86ecc161fdcf23f5db16b8049edec016062ce6.tar.gz webtools.dali-bb86ecc161fdcf23f5db16b8049edec016062ce6.tar.xz webtools.dali-bb86ecc161fdcf23f5db16b8049edec016062ce6.zip |
Created an AnnotationContainer abstract class for nestable annotations. Similar to the CollectionContainer in AbstractJaxbNode
3 files changed, 327 insertions, 79 deletions
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceAnnotation.java index 66c25f25d4..bb0f2eac53 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceAnnotation.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceAnnotation.java @@ -9,9 +9,18 @@ ******************************************************************************/ package org.eclipse.jpt.jaxb.core.internal.resource.java.source; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jpt.core.internal.utility.jdt.ASTNodeTextRange; import org.eclipse.jpt.core.internal.utility.jdt.ElementAnnotationAdapter; import org.eclipse.jpt.core.utility.TextRange; @@ -21,6 +30,11 @@ import org.eclipse.jpt.core.utility.jdt.DeclarationAnnotationAdapter; import org.eclipse.jpt.core.utility.jdt.DeclarationAnnotationElementAdapter; import org.eclipse.jpt.jaxb.core.resource.java.Annotation; import org.eclipse.jpt.jaxb.core.resource.java.JavaResourceNode; +import org.eclipse.jpt.jaxb.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.utility.internal.CollectionTools; +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.utility.internal.iterables.LiveCloneListIterable; /** * some common state and behavior for Java source annotations; @@ -143,4 +157,292 @@ public abstract class SourceAnnotation<A extends AnnotatedElement> return (astNode == null) ? null : new ASTNodeTextRange(astNode); } + + + /** + * A container for nested annotations. The owner of the AnnotationContainer + * needs to call initialize(CompilationUnit) on it. + * @param <T> the type of the resource nestable annotations + */ + abstract class AnnotationContainer<T extends NestableAnnotation> + { + private final Vector<T> nestedAnnotations = new Vector<T>(); + + protected AnnotationContainer() { + super(); + } + + /** + * Return the annotations property name for firing property change notification + */ + protected abstract String getAnnotationsPropertyName(); + + /** + * Return the element name of the nested annotations + */ + protected abstract String getElementName(); + + /** + * Return the nested annotation name + */ + protected abstract String getNestedAnnotationName(); + + /** + * Return a new nested annotation at the given index + */ + protected abstract T buildNestedAnnotation(int index); + + public void initialize(CompilationUnit astRoot) { + // ignore the nested AST annotations themselves + // (maybe someday we can use them during initialization...) + int size = this.getNestedAstAnnotations(astRoot).size(); + for (int i = 0; i < size; i++) { + T nestedAnnotation = this.buildNestedAnnotation(i); + this.nestedAnnotations.add(i, nestedAnnotation); + nestedAnnotation.initialize(astRoot); + } + } + + /** + * Synchronize the resource model annotations with those in the specified AST. + * Trigger the appropriate change notification. + */ + public void synchronize(CompilationUnit astRoot) { + ArrayList<org.eclipse.jdt.core.dom.Annotation> astAnnotations = this.getNestedAstAnnotations(astRoot); + Iterator<org.eclipse.jdt.core.dom.Annotation> astAnnotationStream = astAnnotations.iterator(); + + for (T nestedAnnotation : this.getNestedAnnotations()) { + if (astAnnotationStream.hasNext()) { + // matching AST annotation is present - synchronize the nested annotation + astAnnotationStream.next(); // maybe someday we can pass this to the update + nestedAnnotation.synchronizeWith(astRoot); + } else { + // no more AST annotations - remove the remaining nested annotations and exit + this.syncRemoveNestedAnnotations(astAnnotations.size()); + return; + } + } + + // add nested annotations for any remaining AST annotations + while (astAnnotationStream.hasNext()) { + this.syncAddNestedAnnotation(astAnnotationStream.next()); + } + } + + public ListIterable<T> getNestedAnnotations() { + return new LiveCloneListIterable<T>(this.nestedAnnotations); + } + + public int getNestedAnnotationsSize() { + return this.nestedAnnotations.size(); + } + + public T nestedAnnotationAt(int index) { + return this.nestedAnnotations.get(index); + } + + public T addNestedAnnotation(int index) { + // add a new annotation to the end of the list... + int sourceIndex = this.getNestedAnnotationsSize(); + T nestedAnnotation = this.buildNestedAnnotation(sourceIndex); + this.nestedAnnotations.add(sourceIndex, nestedAnnotation); + nestedAnnotation.newAnnotation(); + // ...then move it to the specified index + this.moveNestedAnnotation(index, sourceIndex); + return nestedAnnotation; + } + + public T moveNestedAnnotation(int targetIndex, int sourceIndex) { + if (targetIndex != sourceIndex) { + return this.moveNestedAnnotation_(targetIndex, sourceIndex); + } + return null; + } + + public T removeNestedAnnotation(int index) { + T nestedAnnotation = this.nestedAnnotations.remove(index); + nestedAnnotation.removeAnnotation(); + this.syncAstAnnotationsAfterRemove(index); + return nestedAnnotation; + } + + private T moveNestedAnnotation_(int targetIndex, int sourceIndex) { + T nestedAnnotation = CollectionTools.move(this.nestedAnnotations, targetIndex, sourceIndex).get(targetIndex); + this.syncAstAnnotationsAfterMove(targetIndex, sourceIndex, nestedAnnotation); + return nestedAnnotation; + } + + /** + * Return a list of the nested AST annotations. + */ + private ArrayList<org.eclipse.jdt.core.dom.Annotation> getNestedAstAnnotations(CompilationUnit astRoot) { + ArrayList<org.eclipse.jdt.core.dom.Annotation> result = new ArrayList<org.eclipse.jdt.core.dom.Annotation>(); + org.eclipse.jdt.core.dom.Annotation astContainerAnnotation = this.getAstAnnotation(astRoot); + if (astContainerAnnotation == null || astContainerAnnotation.isMarkerAnnotation()) { + // no nested annotations + } + else if (astContainerAnnotation.isSingleMemberAnnotation()) { + if (this.getElementName().equals("value")) { //$NON-NLS-1$ + Expression ex = ((SingleMemberAnnotation) astContainerAnnotation).getValue(); + this.addAstAnnotationsTo(ex, result); + } else { + // no nested annotations + } + } + else if (astContainerAnnotation.isNormalAnnotation()) { + MemberValuePair pair = this.getMemberValuePair((NormalAnnotation) astContainerAnnotation); + if (pair == null) { + // no nested annotations + } else { + this.addAstAnnotationsTo(pair.getValue(), result); + } + } + return result; + } + + /** + * Add whatever annotations are represented by the specified expression to + * the specified list. Do not add null to the list for any non-annotation expression. + */ + private void addAstAnnotationsTo(Expression expression, ArrayList<org.eclipse.jdt.core.dom.Annotation> astAnnotations) { + if (expression == null) { + //do not add null to the list, not sure how we would get here... + } + else if (expression.getNodeType() == ASTNode.ARRAY_INITIALIZER) { + this.addAstAnnotationsTo((ArrayInitializer) expression, astAnnotations); + } + else { + org.eclipse.jdt.core.dom.Annotation astAnnotation = this.getAstAnnotation_(expression); + if (astAnnotation != null) { + astAnnotations.add(astAnnotation); + } + } + } + + private void addAstAnnotationsTo(ArrayInitializer arrayInitializer, ArrayList<org.eclipse.jdt.core.dom.Annotation> astAnnotations) { + List<Expression> expressions = this.expressions(arrayInitializer); + for (Expression expression : expressions) { + org.eclipse.jdt.core.dom.Annotation astAnnotation = getAstAnnotation(expression); + if (astAnnotation != null) { + astAnnotations.add(astAnnotation); + } + } + } + // minimize scope of suppressed warnings + @SuppressWarnings("unchecked") + private List<Expression> expressions(ArrayInitializer arrayInitializer) { + return arrayInitializer.expressions(); + } + + private org.eclipse.jdt.core.dom.Annotation getAstAnnotation(CompilationUnit astRoot) { + return SourceAnnotation.this.getAstAnnotation(astRoot); + } + + /** + * If the specified expression is an annotation with the specified name, return it; + * otherwise return null. + */ + private org.eclipse.jdt.core.dom.Annotation getAstAnnotation(Expression expression) { + // not sure how the expression could be null... + return (expression == null) ? null : getAstAnnotation_(expression); + } + + /** + * pre-condition: expression is not null + */ + private org.eclipse.jdt.core.dom.Annotation getAstAnnotation_(Expression expression) { + switch (expression.getNodeType()) { + case ASTNode.NORMAL_ANNOTATION: + case ASTNode.SINGLE_MEMBER_ANNOTATION: + case ASTNode.MARKER_ANNOTATION: + org.eclipse.jdt.core.dom.Annotation astAnnotation = (org.eclipse.jdt.core.dom.Annotation) expression; + if (this.getQualifiedName(astAnnotation).equals(this.getNestedAnnotationName())) { + return astAnnotation; + } + return null; + default: + return null; + } + } + + private String getQualifiedName(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + ITypeBinding typeBinding = astAnnotation.resolveTypeBinding(); + if (typeBinding != null) { + String resolvedName = typeBinding.getQualifiedName(); + if (resolvedName != null) { + return resolvedName; + } + } + return astAnnotation.getTypeName().getFullyQualifiedName(); + } + + private MemberValuePair getMemberValuePair(NormalAnnotation annotation) { + List<MemberValuePair> pairs = this.values(annotation); + for (MemberValuePair pair : pairs) { + if (pair.getName().getFullyQualifiedName().equals(this.getElementName())) { + return pair; + } + } + return null; + } + + @SuppressWarnings("unchecked") + protected List<MemberValuePair> values(NormalAnnotation na) { + return na.values(); + } + + /** + * An annotation was moved within the specified annotation container from + * the specified source index to the specified target index. + * Synchronize the AST annotations with the resource model annotation container, + * starting with the lower index to prevent overlap. + */ + private void syncAstAnnotationsAfterMove(int targetIndex, int sourceIndex, T nestedAnnotation) { + // move the Java annotation to the end of the list... + nestedAnnotation.moveAnnotation(this.getNestedAnnotationsSize()); + // ...then shift the other AST annotations over one slot... + if (sourceIndex < targetIndex) { + for (int i = sourceIndex; i < targetIndex; i++) { + this.nestedAnnotations.get(i).moveAnnotation(i); + } + } else { + for (int i = sourceIndex; i > targetIndex; i-- ) { + this.nestedAnnotations.get(i).moveAnnotation(i); + } + } + // ...then move the AST annotation to the now empty slot at the target index + nestedAnnotation.moveAnnotation(targetIndex); + } + + /** + * An annotation was removed from the specified annotation container at the + * specified index. + * Synchronize the AST annotations with the resource model annotation container, + * starting at the specified index to prevent overlap. + */ + private void syncAstAnnotationsAfterRemove(int index) { + for (int i = index; i < this.getNestedAnnotationsSize(); i++) { + // the indices are the same because the model annotations are + // already in the proper locations - it's the AST annotations that + // need to be moved to the matching location + this.nestedAnnotations.get(i).moveAnnotation(i); + } + } + + private void syncAddNestedAnnotation(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + int index = this.getNestedAnnotationsSize(); + T nestedAnnotation = this.addNestedAnnotation(index); + nestedAnnotation.initialize((CompilationUnit) astAnnotation.getRoot()); + SourceAnnotation.this.fireItemAdded(this.getAnnotationsPropertyName(), index, nestedAnnotation); + } + + private void syncRemoveNestedAnnotations(int index) { + SourceAnnotation.this.removeItemsFromList(index, this.nestedAnnotations, this.getAnnotationsPropertyName()); + } + + @Override + public String toString() { + return StringTools.buildToStringFor(this); + } + } } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceXmlSchemaAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceXmlSchemaAnnotation.java index b3016a8365..f5c8853a53 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceXmlSchemaAnnotation.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/resource/java/source/SourceXmlSchemaAnnotation.java @@ -9,7 +9,6 @@ *******************************************************************************/ package org.eclipse.jpt.jaxb.core.internal.resource.java.source; -import java.util.Vector; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.core.internal.utility.jdt.AnnotatedElementAnnotationElementAdapter; import org.eclipse.jpt.core.internal.utility.jdt.ConversionDeclarationAnnotationElementAdapter; @@ -22,16 +21,12 @@ import org.eclipse.jpt.core.utility.jdt.AnnotationElementAdapter; import org.eclipse.jpt.core.utility.jdt.DeclarationAnnotationAdapter; import org.eclipse.jpt.core.utility.jdt.DeclarationAnnotationElementAdapter; import org.eclipse.jpt.core.utility.jdt.IndexedDeclarationAnnotationAdapter; -import org.eclipse.jpt.jaxb.core.resource.java.AnnotationContainer; import org.eclipse.jpt.jaxb.core.resource.java.JAXB; import org.eclipse.jpt.jaxb.core.resource.java.JavaResourcePackage; import org.eclipse.jpt.jaxb.core.resource.java.XmlNsAnnotation; import org.eclipse.jpt.jaxb.core.resource.java.XmlNsForm; import org.eclipse.jpt.jaxb.core.resource.java.XmlSchemaAnnotation; -import org.eclipse.jpt.utility.internal.CollectionTools; -import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.iterables.ListIterable; -import org.eclipse.jpt.utility.internal.iterables.LiveCloneListIterable; public class SourceXmlSchemaAnnotation @@ -61,7 +56,6 @@ public class SourceXmlSchemaAnnotation private final AnnotationElementAdapter<String> namespaceAdapter; private String namespace; - private final Vector<XmlNsAnnotation> xmlns = new Vector<XmlNsAnnotation>(); private final XmlnsAnnotationContainer xmlnsContainer = new XmlnsAnnotationContainer(); @@ -114,7 +108,7 @@ public class SourceXmlSchemaAnnotation this.elementFormDefault = buildElementFormDefault(astRoot); this.location = buildLocation(astRoot); this.namespace = buildNamespace(astRoot); - AnnotationContainerTools.initialize(this.xmlnsContainer, astRoot); + this.xmlnsContainer.initialize(astRoot); } public void synchronizeWith(CompilationUnit astRoot) { @@ -122,7 +116,7 @@ public class SourceXmlSchemaAnnotation syncElementFormDefault(buildElementFormDefault(astRoot)); syncLocation(buildLocation(astRoot)); syncNamespace(buildNamespace(astRoot)); - AnnotationContainerTools.synchronize(this.xmlnsContainer, astRoot); + this.xmlnsContainer.synchronize(astRoot); } @Override @@ -246,25 +240,19 @@ public class SourceXmlSchemaAnnotation // **************** xmlns ************************************************* public ListIterable<XmlNsAnnotation> getXmlns() { - return new LiveCloneListIterable<XmlNsAnnotation>(this.xmlns); + return this.xmlnsContainer.getNestedAnnotations(); } public int getXmlnsSize() { - return this.xmlns.size(); + return this.xmlnsContainer.getNestedAnnotationsSize(); } public XmlNsAnnotation xmlnsAt(int index) { - return this.xmlns.get(index); + return this.xmlnsContainer.nestedAnnotationAt(index); } public XmlNsAnnotation addXmlns(int index) { - return (XmlNsAnnotation) AnnotationContainerTools.addNestedAnnotation(index, this.xmlnsContainer); - } - - protected XmlNsAnnotation addXmlns_(int index) { - XmlNsAnnotation xmlns = buildXmlns(index); - this.xmlns.add(index, xmlns); - return xmlns; + return this.xmlnsContainer.addNestedAnnotation(index); } private XmlNsAnnotation buildXmlns(int index) { @@ -277,82 +265,35 @@ public class SourceXmlSchemaAnnotation this.daa, JAXB.XML_SCHEMA__XMLNS, index, JAXB.XML_NS, false); } - protected void syncAddXmlns(org.eclipse.jdt.core.dom.Annotation astAnnotation) { - int index = this.xmlns.size(); - XmlNsAnnotation xmlns = addXmlns(index); - xmlns.initialize((CompilationUnit) astAnnotation.getRoot()); - this.fireItemAdded(XMLNS_LIST, index, xmlns); - } - public void moveXmlns(int targetIndex, int sourceIndex) { - AnnotationContainerTools.moveNestedAnnotation(targetIndex, sourceIndex, this.xmlnsContainer); - } - - protected XmlNsAnnotation moveXmlns_(int targetIndex, int sourceIndex) { - return CollectionTools.move(this.xmlns, targetIndex, sourceIndex).get(targetIndex); + this.xmlnsContainer.moveNestedAnnotation(targetIndex, sourceIndex); } public void removeXmlns(int index) { - AnnotationContainerTools.removeNestedAnnotation(index, this.xmlnsContainer); - } - - protected XmlNsAnnotation removeXmlns_(int index) { - return this.xmlns.remove(index); - } - - protected void syncRemoveXmlns(int index) { - this.removeItemsFromList(index, this.xmlns, XMLNS_LIST); + this.xmlnsContainer.removeNestedAnnotation(index); } /** * adapt the AnnotationContainer interface to the xml schema's xmlns */ - class XmlnsAnnotationContainer - implements AnnotationContainer<XmlNsAnnotation> + class XmlnsAnnotationContainer + extends AnnotationContainer<XmlNsAnnotation> { - public org.eclipse.jdt.core.dom.Annotation getAstAnnotation(CompilationUnit astRoot) { - return SourceXmlSchemaAnnotation.this.getAstAnnotation(astRoot); + @Override + protected String getAnnotationsPropertyName() { + return XMLNS_LIST; } - - public String getElementName() { + @Override + protected String getElementName() { return JAXB.XML_SCHEMA__XMLNS; } - - public String getNestedAnnotationName() { + @Override + protected String getNestedAnnotationName() { return JAXB.XML_NS; } - - public ListIterable<XmlNsAnnotation> getNestedAnnotations() { - return SourceXmlSchemaAnnotation.this.getXmlns(); - } - - public int getNestedAnnotationsSize() { - return SourceXmlSchemaAnnotation.this.getXmlnsSize(); - } - - public XmlNsAnnotation addNestedAnnotation(int index) { - return SourceXmlSchemaAnnotation.this.addXmlns_(index); - } - - public void syncAddNestedAnnotation(org.eclipse.jdt.core.dom.Annotation astAnnotation) { - SourceXmlSchemaAnnotation.this.syncAddXmlns(astAnnotation); - } - - public XmlNsAnnotation moveNestedAnnotation(int targetIndex, int sourceIndex) { - return SourceXmlSchemaAnnotation.this.moveXmlns_(targetIndex, sourceIndex); - } - - public XmlNsAnnotation removeNestedAnnotation(int index) { - return SourceXmlSchemaAnnotation.this.removeXmlns_(index); - } - - public void syncRemoveNestedAnnotations(int index) { - SourceXmlSchemaAnnotation.this.syncRemoveXmlns(index); - } - @Override - public String toString() { - return StringTools.buildToStringFor(this); - } + protected XmlNsAnnotation buildNestedAnnotation(int index) { + return SourceXmlSchemaAnnotation.this.buildXmlns(index); + } } } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/resource/java/JavaResourceAnnotatedElement.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/resource/java/JavaResourceAnnotatedElement.java index 61d0d22b07..6bc1566d34 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/resource/java/JavaResourceAnnotatedElement.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/resource/java/JavaResourceAnnotatedElement.java @@ -35,6 +35,11 @@ public interface JavaResourceAnnotatedElement String ANNOTATIONS_COLLECTION = "annotations"; //$NON-NLS-1$ /** + * String associated with changes to the "containerAannotations" collection + */ + String CONTAINER_ANNOTATIONS_COLLECTION = "containreAnnotations"; //$NON-NLS-1$ + + /** * Return the member's annotations in the order that they appear. * Do not return duplicate annotations as this error is handled by the Java * compiler. |