diff options
author | bvosburgh | 2012-03-01 19:52:55 +0000 |
---|---|---|
committer | bvosburgh | 2012-03-01 19:52:55 +0000 |
commit | 78ee8533a9e89294cfe48d0777ad63d6c2a8e811 (patch) | |
tree | 974954356c8fd030c4b3603bc9dac1399e74078a /common | |
parent | f2a5717516c61abd079d1c8b813e15a92032e59c (diff) | |
download | webtools.dali-78ee8533a9e89294cfe48d0777ad63d6c2a8e811.tar.gz webtools.dali-78ee8533a9e89294cfe48d0777ad63d6c2a8e811.tar.xz webtools.dali-78ee8533a9e89294cfe48d0777ad63d6c2a8e811.zip |
[372431] rework "combination" annotations
Diffstat (limited to 'common')
9 files changed, 784 insertions, 639 deletions
diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotatedElement.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotatedElement.java index 59335c8450..dfb509060d 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotatedElement.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotatedElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Oracle. All rights reserved. + * Copyright (c) 2010, 2012 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. @@ -9,14 +9,14 @@ ******************************************************************************/ package org.eclipse.jpt.common.core.internal.resource.java.binary; -import java.util.HashMap; -import java.util.Map; +import java.util.Hashtable; import java.util.Vector; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMemberValuePair; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.AnnotationProvider; import org.eclipse.jpt.common.core.JptCommonCorePlugin; import org.eclipse.jpt.common.core.resource.java.Annotation; import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement; @@ -24,6 +24,8 @@ import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; import org.eclipse.jpt.common.core.resource.java.NestableAnnotation; import org.eclipse.jpt.common.core.utility.TextRange; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.Transformer; +import org.eclipse.jpt.common.utility.internal.TransformerAdapter; import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; @@ -32,7 +34,7 @@ import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; /** - * binary annotated element + * Java binary annotated element */ abstract class BinaryAnnotatedElement extends BinaryNode @@ -41,25 +43,28 @@ abstract class BinaryAnnotatedElement /** JDT annotated element adapter */ final Adapter adapter; - /** annotations */ - final Vector<Annotation> annotations = new Vector<Annotation>(); - /** - * Annotation containers keyed on nestable annotation name. + * Annotations keyed by annotation name; + * no duplicates (the Java compiler does not allow duplicate annotations). + */ + private final Hashtable<String, Annotation> annotations = new Hashtable<String, Annotation>(); + + /** + * Annotation containers keyed by <em>nestable</em> annotation name. * This is used to store annotations that can be both standalone and nested - * and are moved back and forth between the 2. + * and are moved back and forth between the two. */ - final Map<String, AnnotationContainer> annotationContainers = new HashMap<String, AnnotationContainer>(); + private final Hashtable<String, AnnotationContainer> annotationContainers = new Hashtable<String, AnnotationContainer>(); /** - * these are built as needed + * These are built as needed. */ - private final HashMap<String, Annotation> nullAnnotationsCache = new HashMap<String, Annotation>(); + private final Hashtable<String, Annotation> nullAnnotationsCache = new Hashtable<String, Annotation>(); // ********** construction/initialization ********** - public BinaryAnnotatedElement(JavaResourceNode parent, Adapter adapter) { + BinaryAnnotatedElement(JavaResourceNode parent, Adapter adapter) { super(parent); this.adapter = adapter; this.initializeAnnotations(); @@ -73,49 +78,39 @@ abstract class BinaryAnnotatedElement private void addAnnotation(IAnnotation jdtAnnotation) { String jdtAnnotationName = jdtAnnotation.getElementName(); - if (this.annotationIsValid(jdtAnnotationName)) { - this.annotations.add(this.getAnnotationProvider().buildAnnotation(this, jdtAnnotation)); - } - if (this.annotationIsValidNestable(jdtAnnotationName)) { - AnnotationContainer container = new AnnotationContainer(); - container.initializeFromNestableAnnotation(jdtAnnotation); - this.annotationContainers.put(jdtAnnotationName, container); - } + // check whether the annotation is a valid container annotation first + // because container validations are also valid annotations + // TODO remove container annotations from list of annotations??? if (this.annotationIsValidContainer(jdtAnnotationName)) { - String nestableAnnotationName = this.getNestableAnnotationName(jdtAnnotationName); + String nestableAnnotationName = this.getAnnotationProvider().getNestableAnnotationName(jdtAnnotationName); AnnotationContainer container = new AnnotationContainer(); container.initializeFromContainerAnnotation(jdtAnnotation); this.annotationContainers.put(nestableAnnotationName, container); } + else if (this.annotationIsValid(jdtAnnotationName)) { + this.annotations.put(jdtAnnotationName, this.buildAnnotation(jdtAnnotation)); + } + else if (this.annotationIsValidNestable(jdtAnnotationName)) { + // if we already have an annotation container (because there was a container annotation) + // ignore the standalone nestable annotation + if (this.annotationContainers.get(jdtAnnotationName) == null) { + AnnotationContainer container = new AnnotationContainer(); + container.initializeFromStandaloneAnnotation(jdtAnnotation); + this.annotationContainers.put(jdtAnnotationName, container); + } + } } private boolean annotationIsValid(String annotationName) { - return CollectionTools.contains(this.getValidAnnotationNames(), annotationName); + return CollectionTools.contains(this.getAnnotationProvider().getAnnotationNames(), annotationName); } private boolean annotationIsValidContainer(String annotationName) { - return CollectionTools.contains(this.getValidContainerAnnotationNames(), annotationName); + return CollectionTools.contains(this.getAnnotationProvider().getContainerAnnotationNames(), annotationName); } private boolean annotationIsValidNestable(String annotationName) { - return CollectionTools.contains(this.getValidNestableAnnotationNames(), annotationName); - } - - Iterable<String> getValidAnnotationNames() { - return this.getAnnotationProvider().getAnnotationNames(); - } - - Iterable<String> getValidContainerAnnotationNames() { - return this.getAnnotationProvider().getContainerAnnotationNames(); - } - - Iterable<String> getValidNestableAnnotationNames() { - return this.getAnnotationProvider().getNestableAnnotationNames(); - } - - - private String getNestableAnnotationName(String containerAnnotationName) { - return getAnnotationProvider().getNestableAnnotationName(containerAnnotationName); + return CollectionTools.contains(this.getAnnotationProvider().getNestableAnnotationNames(), annotationName); } @@ -131,33 +126,20 @@ abstract class BinaryAnnotatedElement private void updateAnnotations() { throw new UnsupportedOperationException(); } - - + + // ********** annotations ********** public Iterable<Annotation> getAnnotations() { - return new LiveCloneIterable<Annotation>(this.annotations); + return new LiveCloneIterable<Annotation>(this.annotations.values()); } public int getAnnotationsSize() { return this.annotations.size(); } - protected Iterable<NestableAnnotation> getNestableAnnotations() { - return new CompositeIterable<NestableAnnotation>(this.getNestableAnnotationLists()); - } - - private Iterable<Iterable<NestableAnnotation>> getNestableAnnotationLists() { - return new TransformationIterable<AnnotationContainer, Iterable<NestableAnnotation>>(this.annotationContainers.values()) { - @Override - protected Iterable<NestableAnnotation> transform(AnnotationContainer container) { - return container.getNestedAnnotations(); - } - }; - } - public Annotation getAnnotation(String annotationName) { - return this.selectAnnotationNamed(this.getAnnotations(), annotationName); + return this.annotations.get(annotationName); } public Annotation getNonNullAnnotation(String annotationName) { @@ -165,65 +147,106 @@ abstract class BinaryAnnotatedElement return (annotation != null) ? annotation : this.getNullAnnotation(annotationName); } - private synchronized Annotation getNullAnnotation(String annotationName) { - Annotation annotation = this.nullAnnotationsCache.get(annotationName); - if (annotation == null) { - annotation = this.buildNullAnnotation(annotationName); - this.nullAnnotationsCache.put(annotationName, annotation); + private Annotation getNullAnnotation(String annotationName) { + synchronized (this.nullAnnotationsCache) { + Annotation annotation = this.nullAnnotationsCache.get(annotationName); + if (annotation == null) { + annotation = this.buildNullAnnotation(annotationName); + this.nullAnnotationsCache.put(annotationName, annotation); + } + return annotation; } - return annotation; } private Annotation buildNullAnnotation(String annotationName) { - return getAnnotationProvider().buildNullAnnotation(this, annotationName); + return this.getAnnotationProvider().buildNullAnnotation(this, annotationName); + } + + /* CU private */ Annotation buildAnnotation(IAnnotation jdtAnnotation) { + return this.getAnnotationProvider().buildAnnotation(this, jdtAnnotation); + } + + + // ********** combination annotations ********** + + private Iterable<NestableAnnotation> getNestableAnnotations() { + return new CompositeIterable<NestableAnnotation>(this.getNestableAnnotationLists()); } - // ********** nestable annotations ********** + private Iterable<Iterable<NestableAnnotation>> getNestableAnnotationLists() { + return new TransformationIterable<AnnotationContainer, Iterable<NestableAnnotation>>(this.getAnnotationContainers(), ANNOTATION_CONTAINER_NESTED_ANNOTATIONS_TRANSFORMER); + } + + private static final Transformer<AnnotationContainer, Iterable<NestableAnnotation>> ANNOTATION_CONTAINER_NESTED_ANNOTATIONS_TRANSFORMER = new AnnotationContainerNestedAnnotationsTransformer(); + static final class AnnotationContainerNestedAnnotationsTransformer + extends TransformerAdapter<AnnotationContainer, Iterable<NestableAnnotation>> + { + @Override + public Iterable<NestableAnnotation> transform(AnnotationContainer container) { + return container.getNestedAnnotations(); + } + } + + private Iterable<AnnotationContainer> getAnnotationContainers() { + return new LiveCloneIterable<AnnotationContainer>(this.annotationContainers.values()); + } public ListIterable<NestableAnnotation> getAnnotations(String nestableAnnotationName) { AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container != null ? container.getNestedAnnotations() : EmptyListIterable.<NestableAnnotation> instance(); + return (container != null) ? container.getNestedAnnotations() : EmptyListIterable.<NestableAnnotation> instance(); } public int getAnnotationsSize(String nestableAnnotationName) { AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container == null ? 0 : container.getNestedAnnotationsSize(); + return (container == null) ? 0 : container.getNestedAnnotationsSize(); } public NestableAnnotation getAnnotation(int index, String nestableAnnotationName) { AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container == null ? null : container.nestedAnnotationAt(index); + return (container == null) ? null : container.getNestedAnnotation(index); + } + + private Iterable<Annotation> getContainerOrStandaloneNestableAnnotations() { + return new TransformationIterable<AnnotationContainer, Annotation>(this.getAnnotationContainers(), TOP_LEVEL_ANNOTATION_CONTAINER_TRANSFORMER); } - // ***** queries ***** - - public Iterable<Annotation> getAllAnnotations() { + private static final Transformer<AnnotationContainer, Annotation> TOP_LEVEL_ANNOTATION_CONTAINER_TRANSFORMER = new TopLevelAnnotationContainerTransformer(); + /* CU private */ static final class TopLevelAnnotationContainerTransformer + extends TransformerAdapter<AnnotationContainer, Annotation> + { + @Override + public Annotation transform(AnnotationContainer container) { + Annotation containerAnnotation = container.getContainerAnnotation(); + return (containerAnnotation != null) ? containerAnnotation : container.getNestedAnnotation(0); + } + } + + /* CU private */ NestableAnnotation buildAnnotation(IAnnotation jdtAnnotation, int index) { + return this.getAnnotationProvider().buildAnnotation(this, jdtAnnotation, index); + } + + + // ***** all annotations ***** + + @SuppressWarnings("unchecked") + public Iterable<Annotation> getTopLevelAnnotations() { return new CompositeIterable<Annotation>( - getAnnotations(), - getContainerOrNestableAnnotations()); - } - - protected Iterable<Annotation> getContainerOrNestableAnnotations() { - return new TransformationIterable<AnnotationContainer, Annotation>(this.annotationContainers.values()) { - @Override - protected Annotation transform(AnnotationContainer o) { - return (o.getContainerAnnotation() != null) ? o.getContainerAnnotation() : CollectionTools.get(o.getNestedAnnotations(), 0); - } - }; + this.getAnnotations(), + this.getContainerOrStandaloneNestableAnnotations() + ); } - + public boolean isAnnotated() { - return ! (this.annotations.isEmpty() && this.annotationContainers.isEmpty()); + return ! this.isUnannotated(); } - public boolean isAnnotatedWith(Iterable<String> annotationNames) { - for (Annotation annotation : this.getAnnotations()) { - if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { - return true; - } - } - for (Annotation annotation : this.getNestableAnnotations()) { + private boolean isUnannotated() { + return this.annotations.isEmpty() && this.annotationContainers.isEmpty(); + } + + public boolean isAnnotatedWithAnyOf(Iterable<String> annotationNames) { + for (Annotation annotation : this.getSignificantAnnotations()) { if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { return true; } @@ -231,20 +254,24 @@ abstract class BinaryAnnotatedElement return false; } + /** + * Return the "significant" annotations; + * i.e. ignore the container annotations (they have no semantics). + */ + @SuppressWarnings("unchecked") + private Iterable<Annotation> getSignificantAnnotations() { + return new CompositeIterable<Annotation>( + this.getAnnotations(), + this.getNestableAnnotations() + ); + } - // ********** misc ********** - IJavaElement getAnnotatedElement() { - return this.adapter.getElement(); - } + // ********** misc ********** - private Annotation selectAnnotationNamed(Iterable<Annotation> annotationList, String annotationName) { - for (Annotation annotation : annotationList) { - if (annotation.getAnnotationName().equals(annotationName)) { - return annotation; - } - } - return null; + @Override + protected AnnotationProvider getAnnotationProvider() { + return super.getAnnotationProvider(); } private IAnnotation[] getJdtAnnotations() { @@ -303,74 +330,61 @@ abstract class BinaryAnnotatedElement throw new UnsupportedOperationException(); } - private static final IMemberValuePair[] EMPTY_MEMBER_VALUE_PAIR_ARRAY = new IMemberValuePair[0]; - - - class AnnotationContainer { - + /* CU private */ static final IMemberValuePair[] EMPTY_MEMBER_VALUE_PAIR_ARRAY = new IMemberValuePair[0]; + /* CU private */ static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + + + // ********** annotation container ********** + + /* CU private */ class AnnotationContainer { + private Annotation containerAnnotation; - + private final Vector<NestableAnnotation> nestedAnnotations = new Vector<NestableAnnotation>(); - - protected AnnotationContainer() { + + AnnotationContainer() { super(); - } - - - // ***** init from container ***** - - protected void initializeFromContainerAnnotation(IAnnotation jdtContainerAnnotation) { - this.containerAnnotation = - BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( - BinaryAnnotatedElement.this, jdtContainerAnnotation); - initializeNestedAnnotations(jdtContainerAnnotation); } - - protected void initializeNestedAnnotations(IAnnotation jdtContainerAnnotation) { - int index = 0; - for (IMemberValuePair valuePair : this.getJdtMemberValuePairs(jdtContainerAnnotation)) { - IAnnotation jdtNestedAnnotation = (IAnnotation) valuePair.getValue(); - this.nestedAnnotations.add( - BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( - BinaryAnnotatedElement.this, jdtNestedAnnotation, index++)); - } + + void initializeFromContainerAnnotation(IAnnotation jdtContainerAnnotation) { + this.initializeNestedAnnotations(jdtContainerAnnotation); + this.containerAnnotation = BinaryAnnotatedElement.this.buildAnnotation(jdtContainerAnnotation); } - - private IMemberValuePair[] getJdtMemberValuePairs(IAnnotation jdtContainerAnnotation) { - try { - return jdtContainerAnnotation.getMemberValuePairs(); - } - catch (JavaModelException ex) { - JptCommonCorePlugin.log(ex); - return EMPTY_MEMBER_VALUE_PAIR_ARRAY; + + void initializeNestedAnnotations(IAnnotation jdtContainerAnnotation) { + Object[] jdtNestedAnnotations = this.getJdtNestedAnnotations(jdtContainerAnnotation); + int len = jdtNestedAnnotations.length; + for (int i = 0; i < len; i++) { + IAnnotation jdtNestedAnnotation = (IAnnotation) jdtNestedAnnotations[i]; + this.addAnnotation(jdtNestedAnnotation, i); } } - - - // ***** init from nestable ***** - - protected void initializeFromNestableAnnotation(IAnnotation jdtNestableAnnotation) { - this.nestedAnnotations.add( - BinaryAnnotatedElement.this.getAnnotationProvider().buildAnnotation( - BinaryAnnotatedElement.this, jdtNestableAnnotation, 0)); + + private Object[] getJdtNestedAnnotations(IAnnotation jdtContainerAnnotation) { + return BinaryAnnotatedElement.this.getJdtMemberValues(jdtContainerAnnotation, "value"); //$NON-NLS-1$ + } + + void initializeFromStandaloneAnnotation(IAnnotation jdtNestableAnnotation) { + this.addAnnotation(jdtNestableAnnotation, 0); + } + + private void addAnnotation(IAnnotation jdtNestableAnnotation, int index) { + this.nestedAnnotations.add(BinaryAnnotatedElement.this.buildAnnotation(jdtNestableAnnotation, index)); } - - - // ***** queries ***** - - protected Annotation getContainerAnnotation() { + + Annotation getContainerAnnotation() { return this.containerAnnotation; } - - protected ListIterable<NestableAnnotation> getNestedAnnotations() { + + ListIterable<NestableAnnotation> getNestedAnnotations() { return new LiveCloneListIterable<NestableAnnotation>(this.nestedAnnotations); } - - protected int getNestedAnnotationsSize() { + + int getNestedAnnotationsSize() { return this.nestedAnnotations.size(); } - - protected NestableAnnotation nestedAnnotationAt(int index) { + + NestableAnnotation getNestedAnnotation(int index) { return this.nestedAnnotations.get(index); } } diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotation.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotation.java index 63af604399..813453ccab 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotation.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryAnnotation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * Copyright (c) 2009, 2012 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. @@ -10,10 +10,7 @@ package org.eclipse.jpt.common.core.internal.resource.java.binary; import org.eclipse.jdt.core.IAnnotation; -import org.eclipse.jdt.core.IMemberValuePair; -import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jpt.common.core.JptCommonCorePlugin; import org.eclipse.jpt.common.core.resource.java.Annotation; import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; @@ -37,41 +34,16 @@ public abstract class BinaryAnnotation * Return the values of the JDT annotation's member with the specified name. */ protected Object[] getJdtMemberValues(String memberName) { - Object[] values = (Object[]) this.getJdtMemberValue(memberName); - return (values != null) ? values : EMPTY_OBJECT_ARRAY; + return this.getJdtMemberValues(this.jdtAnnotation, memberName); } - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** * Return the value of the JDT annotation's member with the specified name. */ protected Object getJdtMemberValue(String memberName) { - IMemberValuePair pair = this.getJdtMemberValuePair(memberName); - return (pair == null) ? null : pair.getValue(); + return this.getJdtMemberValue(this.jdtAnnotation, memberName); } - /** - * Return the JDT annotation's member-value pair with the specified name. - */ - private IMemberValuePair getJdtMemberValuePair(String memberName) { - for (IMemberValuePair pair : this.getJdtMemberValuePairs()) { - if (pair.getMemberName().equals(memberName)) { - return pair; - } - } - return null; - } - - private IMemberValuePair[] getJdtMemberValuePairs() { - try { - return this.jdtAnnotation.getMemberValuePairs(); - } catch (JavaModelException ex) { - JptCommonCorePlugin.log(ex); - return EMPTY_MEMBER_VALUE_PAIR_ARRAY; - } - } - private static final IMemberValuePair[] EMPTY_MEMBER_VALUE_PAIR_ARRAY = new IMemberValuePair[0]; - // ********** Annotation implementation ********** diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryNode.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryNode.java index 5bb0ad0410..76a1eecf52 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryNode.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryNode.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2010 Oracle. All rights reserved. + * Copyright (c) 2009, 2012 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. @@ -10,7 +10,11 @@ package org.eclipse.jpt.common.core.internal.resource.java.binary; import org.eclipse.core.resources.IFile; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IMemberValuePair; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.JptCommonCorePlugin; import org.eclipse.jpt.common.core.internal.resource.java.AbstractJavaResourceNode; import org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit; import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; @@ -24,9 +28,6 @@ import org.eclipse.jpt.common.core.utility.TextRange; public abstract class BinaryNode extends AbstractJavaResourceNode { - - // ********** construction ********** - protected BinaryNode(JavaResourceNode parent) { super(parent); } @@ -59,4 +60,48 @@ public abstract class BinaryNode throw new UnsupportedOperationException(); } + + // ********** member value-pairs ********** + + /** + * Return the <em>values</em> of the specified JDT annotation's member with + * the specified name. + */ + public Object[] getJdtMemberValues(IAnnotation jdtContainerAnnotation, String memberName) { + Object[] values = (Object[]) this.getJdtMemberValue(jdtContainerAnnotation, memberName); + return (values != null) ? values : EMPTY_OBJECT_ARRAY; + } + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + + /** + * Return the value of the specified JDT annotation's member with + * the specified name. + */ + public Object getJdtMemberValue(IAnnotation jdtContainerAnnotation, String memberName) { + IMemberValuePair pair = this.getJdtMemberValuePair(jdtContainerAnnotation, memberName); + return (pair == null) ? null : pair.getValue(); + } + + /** + * Return the specified JDT annotation's member-value pair with + * the specified name. + */ + public IMemberValuePair getJdtMemberValuePair(IAnnotation jdtContainerAnnotation, String memberName) { + for (IMemberValuePair pair : this.getJdtMemberValuePairs(jdtContainerAnnotation)) { + if (pair.getMemberName().equals(memberName)) { + return pair; + } + } + return null; + } + + public IMemberValuePair[] getJdtMemberValuePairs(IAnnotation jdtContainerAnnotation) { + try { + return jdtContainerAnnotation.getMemberValuePairs(); + } catch (JavaModelException ex) { + JptCommonCorePlugin.log(ex); + return EMPTY_MEMBER_VALUE_PAIR_ARRAY; + } + } + private static final IMemberValuePair[] EMPTY_MEMBER_VALUE_PAIR_ARRAY = new IMemberValuePair[0]; } diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotatedElement.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotatedElement.java index ec38a9ee2e..1c6276717d 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotatedElement.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotatedElement.java @@ -1,24 +1,27 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Oracle. All rights reserved. + * Copyright (c) 2010, 2012 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.common.core.internal.resource.java.source; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.Vector; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; @@ -30,6 +33,9 @@ import org.eclipse.jpt.common.core.resource.java.NestableAnnotation; import org.eclipse.jpt.common.core.utility.TextRange; import org.eclipse.jpt.common.core.utility.jdt.AnnotatedElement; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.Transformer; +import org.eclipse.jpt.common.utility.internal.TransformerAdapter; import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; @@ -37,66 +43,82 @@ import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable; import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; /** - * Java source annotated element (annotations) + * Java source annotated element */ -abstract class SourceAnnotatedElement<A extends AnnotatedElement> +abstract class SourceAnnotatedElement<E extends AnnotatedElement> extends SourceNode implements JavaResourceAnnotatedElement { - final A annotatedElement; + final E annotatedElement; /** - * annotations; no duplicates (java compiler has an error for duplicates) + * Annotations keyed by annotation name; + * no duplicates (the Java compiler does not allow duplicate annotations). */ - final Vector<Annotation> annotations = new Vector<Annotation>(); + private final Hashtable<String, Annotation> annotations = new Hashtable<String, Annotation>(); /** - * Annotation containers keyed on nestable annotation name. + * Annotation containers keyed by <em>nestable</em> annotation name. * This is used to store annotations that can be both standalone and nested - * and are moved back and forth between the 2. + * and are moved back and forth between the two. */ - final Map<String, AnnotationContainer> annotationContainers = new HashMap<String, AnnotationContainer>(); + private final Hashtable<String, CombinationAnnotationContainer> annotationContainers = new Hashtable<String, CombinationAnnotationContainer>(); + // ********** construction/initialization ********** - SourceAnnotatedElement(JavaResourceNode parent, A annotatedElement) { + SourceAnnotatedElement(JavaResourceNode parent, E annotatedElement) { super(parent); this.annotatedElement = annotatedElement; } + /** + * Gather up all the significant AST annotations + * and build the corresponding Dali annotations. + */ public void initialize(CompilationUnit astRoot) { ASTNode node = this.annotatedElement.getBodyDeclaration(astRoot); - node.accept(this.buildInitialAnnotationVisitor(node)); - } - - private ASTVisitor buildInitialAnnotationVisitor(ASTNode node) { - return new InitialAnnotationVisitor(node); + AnnotationVisitor visitor = new AnnotationVisitor(node); + node.accept(visitor); + this.initializeAnnotations(visitor.astAnnotations); + // container annotations take precedence over... + this.initializeContainerAnnotations(visitor.astContainerAnnotations); + // ...standalone nestable annotations + this.initializeStandaloneNestableAnnotations(visitor.astStandaloneNestableAnnotations); + } + + private void initializeAnnotations(HashMap<String, org.eclipse.jdt.core.dom.Annotation> astAnnotations) { + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astAnnotations.entrySet()) { + String annotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astAnnotation = entry.getValue(); + Annotation annotation = this.buildAnnotation(annotationName); + annotation.initialize((CompilationUnit) astAnnotation.getRoot()); // TODO pass the AST annotation! + this.annotations.put(annotationName, annotation); + } + } + + private void initializeContainerAnnotations(HashMap<String, org.eclipse.jdt.core.dom.Annotation> astContainerAnnotations) { + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astContainerAnnotations.entrySet()) { + String containerAnnotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astAnnotation = entry.getValue(); + String nestableAnnotationName = this.getNestableAnnotationName(containerAnnotationName); + CombinationAnnotationContainer container = new CombinationAnnotationContainer(nestableAnnotationName, containerAnnotationName); + container.initializeFromContainerAnnotation(astAnnotation); + this.annotationContainers.put(nestableAnnotationName, container); + } } - /** - * called from {@link InitialAnnotationVisitor} - */ - /* private */ void addInitialAnnotation(org.eclipse.jdt.core.dom.Annotation node) { - String jdtAnnotationName = ASTTools.resolveAnnotation(node); - if (jdtAnnotationName != null) { - if(this.annotationIsValidContainer(jdtAnnotationName)) { - String nestableAnnotationName = this.getNestableAnnotationName(jdtAnnotationName); - AnnotationContainer container = new AnnotationContainer(nestableAnnotationName); - container.initialize(node); + private void initializeStandaloneNestableAnnotations(HashMap<String, org.eclipse.jdt.core.dom.Annotation> astStandaloneNestableAnnotations) { + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astStandaloneNestableAnnotations.entrySet()) { + String nestableAnnotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astAnnotation = entry.getValue(); + // if we already have an annotation container (because there was a container annotation) + // ignore the standalone nestable annotation + if (this.annotationContainers.get(nestableAnnotationName) == null) { + CombinationAnnotationContainer container = new CombinationAnnotationContainer(nestableAnnotationName); + container.initializeFromStandaloneAnnotation(astAnnotation); this.annotationContainers.put(nestableAnnotationName, container); } - else if (this.annotationIsValid(jdtAnnotationName)) { - if (this.selectAnnotationNamed(this.annotations, jdtAnnotationName) == null) { // ignore duplicates - Annotation annotation = this.buildAnnotation(jdtAnnotationName); - annotation.initialize((CompilationUnit) node.getRoot()); - this.annotations.add(annotation); - } - } - else if(this.annotationIsValidNestable(jdtAnnotationName)) { - AnnotationContainer container = new AnnotationContainer(jdtAnnotationName); - container.initializeNestableAnnotation(node); - this.annotationContainers.put(jdtAnnotationName, container); - } } } @@ -108,32 +130,20 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> // ********** annotations ********** public Iterable<Annotation> getAnnotations() { - return new LiveCloneIterable<Annotation>(this.annotations); + return new LiveCloneIterable<Annotation>(this.annotations.values()); } public int getAnnotationsSize() { return this.annotations.size(); } - protected Iterable<NestableAnnotation> getNestableAnnotations() { - return new CompositeIterable<NestableAnnotation>(this.getNestableAnnotationLists()); - } - - private Iterable<Iterable<NestableAnnotation>> getNestableAnnotationLists() { - return new TransformationIterable<AnnotationContainer, Iterable<NestableAnnotation>>(this.annotationContainers.values()) { - @Override - protected Iterable<NestableAnnotation> transform(AnnotationContainer container) { - return container.getNestedAnnotations(); - } - }; - } - public Annotation getAnnotation(String annotationName) { + // TODO figure out why we need to search the containers... if (this.annotationIsValidContainer(annotationName)) { - AnnotationContainer container = this.annotationContainers.get(getAnnotationProvider().getNestableAnnotationName(annotationName)); - return container == null ? null : container.getContainerAnnotation(); + CombinationAnnotationContainer container = this.annotationContainers.get(this.getAnnotationProvider().getNestableAnnotationName(annotationName)); + return (container == null) ? null : container.getContainerAnnotation(); } - return this.selectAnnotationNamed(this.getAnnotations(), annotationName); + return this.annotations.get(annotationName); } public Annotation getNonNullAnnotation(String annotationName) { @@ -141,45 +151,88 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> return (annotation != null) ? annotation : this.buildNullAnnotation(annotationName); } + private Annotation buildNullAnnotation(String annotationName) { + return this.getAnnotationProvider().buildNullAnnotation(this, annotationName); + } + + public Annotation addAnnotation(String annotationName) { + Annotation annotation = this.buildAnnotation(annotationName); + this.annotations.put(annotationName, annotation); + annotation.newAnnotation(); + return annotation; + } + + public void removeAnnotation(String annotationName) { + Annotation annotation = this.annotations.remove(annotationName); + if (annotation != null) { + annotation.removeAnnotation(); + } + } + + /* CU private */ boolean annotationIsValid(String annotationName) { + return CollectionTools.contains(this.getAnnotationProvider().getAnnotationNames(), annotationName); + } + + /* CU private */ Annotation buildAnnotation(String annotationName) { + return this.getAnnotationProvider().buildAnnotation(this, this.annotatedElement, annotationName); + } + + + // ********** combination annotations ********** + + private Iterable<NestableAnnotation> getNestableAnnotations() { + return new CompositeIterable<NestableAnnotation>(this.getNestableAnnotationLists()); + } + + private Iterable<Iterable<NestableAnnotation>> getNestableAnnotationLists() { + return new TransformationIterable<CombinationAnnotationContainer_, Iterable<NestableAnnotation>>(this.getAnnotationContainers(), ANNOTATION_CONTAINER_NESTED_ANNOTATIONS_TRANSFORMER); + } + + private static final Transformer<CombinationAnnotationContainer_, Iterable<NestableAnnotation>> ANNOTATION_CONTAINER_NESTED_ANNOTATIONS_TRANSFORMER = new AnnotationContainerNestedAnnotationsTransformer(); + /* CU private */ static final class AnnotationContainerNestedAnnotationsTransformer + extends TransformerAdapter<CombinationAnnotationContainer_, Iterable<NestableAnnotation>> + { + @Override + public Iterable<NestableAnnotation> transform(CombinationAnnotationContainer_ container) { + return container.getNestedAnnotations(); + } + } + + private Iterable<CombinationAnnotationContainer> getAnnotationContainers() { + return new LiveCloneIterable<CombinationAnnotationContainer>(this.annotationContainers.values()); + } + public ListIterable<NestableAnnotation> getAnnotations(String nestableAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container != null ? container.getNestedAnnotations() : EmptyListIterable.<NestableAnnotation> instance(); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + return (container != null) ? container.getNestedAnnotations() : EmptyListIterable.<NestableAnnotation> instance(); } public int getAnnotationsSize(String nestableAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container == null ? 0 : container.getNestedAnnotationsSize(); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + return (container == null) ? 0 : container.getNestedAnnotationsSize(); } public NestableAnnotation getAnnotation(int index, String nestableAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - return container == null ? null : container.nestedAnnotationAt(index); - } - - public Annotation getContainerAnnotation(String containerAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(getAnnotationProvider().getNestableAnnotationName(containerAnnotationName)); - return container == null ? null : container.getContainerAnnotation(); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + return (container == null) ? null : container.getNestedAnnotation(index); } private String getNestableAnnotationName(String containerAnnotationName) { - return getAnnotationProvider().getNestableAnnotationName(containerAnnotationName); + return this.getAnnotationProvider().getNestableAnnotationName(containerAnnotationName); } - private String getNestableElementName(String nestableAnnotationName) { - return getAnnotationProvider().getNestableElementName(nestableAnnotationName); + /* CU private */ String getContainerAnnotationName(String nestableAnnotationName) { + return this.getAnnotationProvider().getContainerAnnotationName(nestableAnnotationName); } - public Annotation addAnnotation(String annotationName) { - Annotation annotation = this.buildAnnotation(annotationName); - this.annotations.add(annotation); - annotation.newAnnotation(); - return annotation; + /* CU private */ String getNestableElementName(String nestableAnnotationName) { + return this.getAnnotationProvider().getNestableElementName(nestableAnnotationName); } public NestableAnnotation addAnnotation(int index, String nestableAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); if (container == null) { - container = new AnnotationContainer(nestableAnnotationName); + container = new CombinationAnnotationContainer(nestableAnnotationName); this.annotationContainers.put(nestableAnnotationName, container); } return container.addNestedAnnotation(index); @@ -189,188 +242,217 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> this.annotationContainers.get(nestableAnnotationName).moveNestedAnnotation(targetIndex, sourceIndex); } - public void removeAnnotation(String annotationName) { - Annotation annotation = this.getAnnotation(annotationName); - if (annotation != null) { - this.removeAnnotation(annotation); - } - } - - private void removeAnnotation(Annotation annotation) { - this.annotations.remove(annotation); - annotation.removeAnnotation(); - } - public void removeAnnotation(int index, String nestableAnnotationName) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); container.removeNestedAnnotation(index); if (container.isEmpty()) { this.annotationContainers.remove(nestableAnnotationName); } } - protected boolean annotationIsValid(String annotationName) { - return CollectionTools.contains(this.getValidAnnotationNames(), annotationName); - } - - protected boolean annotationIsValidContainer(String annotationName) { - return CollectionTools.contains(this.getValidContainerAnnotationNames(), annotationName); - } - - protected boolean annotationIsValidNestable(String annotationName) { - return CollectionTools.contains(this.getValidNestableAnnotationNames(), annotationName); + /* CU private */ boolean annotationIsValidContainer(String annotationName) { + return CollectionTools.contains(this.getAnnotationProvider().getContainerAnnotationNames(), annotationName); } - Iterable<String> getValidAnnotationNames() { - return this.getAnnotationProvider().getAnnotationNames(); + /* CU private */ boolean annotationIsValidNestable(String annotationName) { + return CollectionTools.contains(this.getAnnotationProvider().getNestableAnnotationNames(), annotationName); } - Iterable<String> getValidContainerAnnotationNames() { - return this.getAnnotationProvider().getContainerAnnotationNames(); - } - - Iterable<String> getValidNestableAnnotationNames() { - return this.getAnnotationProvider().getNestableAnnotationNames(); - } - - Annotation buildAnnotation(String annotationName) { - return this.getAnnotationProvider().buildAnnotation(this, this.annotatedElement, annotationName); + /* CU private */ NestableAnnotation buildNestableAnnotation(String annotationName, int index) { + return this.getAnnotationProvider().buildAnnotation(this, this.annotatedElement, annotationName, index); } - Annotation buildNullAnnotation(String annotationName) { - return this.getAnnotationProvider().buildNullAnnotation(this, annotationName); + /* CU private */ void nestedAnnotationAdded(String collectionName, NestableAnnotation addedAnnotation) { + this.fireItemAdded(collectionName, addedAnnotation); } - NestableAnnotation buildNestableAnnotation(String annotationName, int index) { - return this.getAnnotationProvider().buildAnnotation(this, this.annotatedElement, annotationName, index); + /* CU private */ void nestedAnnotationsRemoved(String collectionName, Collection<? extends NestableAnnotation> removedAnnotations) { + this.fireItemsRemoved(collectionName, removedAnnotations); } - private void syncAnnotations(ASTNode node) { - HashSet<Annotation> annotationsToRemove = new HashSet<Annotation>(this.annotations); - HashSet<AnnotationContainer> containersToRemove = new HashSet<AnnotationContainer>(this.annotationContainers.values()); - node.accept(this.buildSynchronizeAnnotationVisitor(node, annotationsToRemove, containersToRemove)); + // ***** all annotations ***** - for (Annotation annotation : annotationsToRemove) { - this.removeItemFromCollection(annotation, this.annotations, ANNOTATIONS_COLLECTION); + Annotation setPrimaryAnnotation(String primaryAnnotationName, Iterable<String> supportingAnnotationNames) { + // clear out extraneous annotations + HashSet<String> annotationNames = new HashSet<String>(); + CollectionTools.addAll(annotationNames, supportingAnnotationNames); + if (primaryAnnotationName != null) { + annotationNames.add(primaryAnnotationName); } + this.retainAnnotations(annotationNames); + this.retainAnnotationContainers(annotationNames); - for (AnnotationContainer annotationContainer : containersToRemove) { - this.annotationContainers.remove(annotationContainer.getNestedAnnotationName()); - fireItemsRemoved(NESTABLE_ANNOTATIONS_COLLECTION, CollectionTools.collection(annotationContainer.getNestedAnnotations())); + // add the primary annotation + if (primaryAnnotationName == null) { + return null; } + Annotation primaryAnnotation = this.getAnnotation(primaryAnnotationName); + if (primaryAnnotation == null) { + primaryAnnotation = this.buildAnnotation(primaryAnnotationName); + this.annotations.put(primaryAnnotationName, primaryAnnotation); + primaryAnnotation.newAnnotation(); + } + return primaryAnnotation; + } - Iterator<String> keys = this.annotationContainers.keySet().iterator(); - - while (keys.hasNext()) { - String annotationName = keys.next(); - if (this.annotationContainers.get(annotationName).getNestedAnnotationsSize() == 0) { - keys.remove(); + private void retainAnnotations(HashSet<String> annotationNames) { + synchronized (this.annotations) { + for (Iterator<Map.Entry<String, Annotation>> stream = this.annotations.entrySet().iterator(); stream.hasNext(); ) { + Map.Entry<String, Annotation> entry = stream.next(); + String annotationName = entry.getKey(); + Annotation annotation = entry.getValue(); + if ( ! annotationNames.contains(annotationName)) { + stream.remove(); + annotation.removeAnnotation(); + } } } } - private ASTVisitor buildSynchronizeAnnotationVisitor(ASTNode node, Set<Annotation> annotationsToRemove, Set<AnnotationContainer> containersToRemove) { - return new SynchronizeAnnotationVisitor(node, annotationsToRemove, containersToRemove); + private void retainAnnotationContainers(HashSet<String> annotationNames) { + synchronized (this.annotationContainers) { + for (Iterator<Map.Entry<String, CombinationAnnotationContainer>> stream = this.annotationContainers.entrySet().iterator(); stream.hasNext(); ) { + Map.Entry<String, CombinationAnnotationContainer> entry = stream.next(); + String nestableAnnotationName = entry.getKey(); + CombinationAnnotationContainer container = entry.getValue(); + Annotation containerAnnotation = container.getContainerAnnotation(); + if (containerAnnotation != null) { + if ( ! annotationNames.contains(container.getContainerAnnotationName())) { + stream.remove(); + containerAnnotation.removeAnnotation(); + } + } else { + // standalone "nestable" annotation + if ( ! annotationNames.contains(nestableAnnotationName)) { + stream.remove(); + container.getNestedAnnotation(0).removeAnnotation(); + } + } + } + } } /** - * called from {@link SynchronizeAnnotationVisitor} + * Gather up all the significant AST annotations + * and add or sync the corresponding Dali annotations. */ - /* private */ void addOrSyncAnnotation(org.eclipse.jdt.core.dom.Annotation node, Set<Annotation> annotationsToRemove, Set<AnnotationContainer> containersToRemove) { - String jdtAnnotationName = ASTTools.resolveAnnotation(node); - if (jdtAnnotationName != null) { - if (this.annotationIsValidContainer(jdtAnnotationName)) { - this.addOrSyncContainerAnnotation_(node, jdtAnnotationName, containersToRemove); - } - else if (this.annotationIsValid(jdtAnnotationName)) { - this.addOrSyncAnnotation_(node, jdtAnnotationName, annotationsToRemove); - } - else if(this.annotationIsValidNestable(jdtAnnotationName)) { - this.addOrSyncNestableAnnotation_(node, jdtAnnotationName, containersToRemove); + private void syncAnnotations(ASTNode node) { + AnnotationVisitor visitor = new AnnotationVisitor(node); + node.accept(visitor); + this.syncAnnotations(visitor.astAnnotations); + this.syncAnnotationContainers(visitor.astContainerAnnotations, visitor.astStandaloneNestableAnnotations); + } + + private void syncAnnotations(HashMap<String, org.eclipse.jdt.core.dom.Annotation> astAnnotations) { + HashMap<String, Annotation> annotationsToRemove = new HashMap<String, Annotation>(this.annotations); + HashMap<String, Annotation> annotationsToAdd = new HashMap<String, Annotation>(); + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astAnnotations.entrySet()) { + String annotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astAnnotation = entry.getValue(); + Annotation annotation = annotationsToRemove.remove(annotationName); + if (annotation == null) { + annotation = this.buildAnnotation(annotationName); + annotation.initialize((CompilationUnit) astAnnotation.getRoot()); // TODO pass the AST annotation! + annotationsToAdd.put(annotationName, annotation); + } else { + annotation.synchronizeWith((CompilationUnit) astAnnotation.getRoot()); // TODO pass the AST annotation! } } - } - /** - * pre-condition: jdtAnnotationName is valid - */ - private void addOrSyncAnnotation_(org.eclipse.jdt.core.dom.Annotation node, String jdtAnnotationName, Set<Annotation> annotationsToRemove) { - Annotation annotation = this.selectAnnotationNamed(annotationsToRemove, jdtAnnotationName); - if (annotation != null) { - annotation.synchronizeWith((CompilationUnit) node.getRoot()); - annotationsToRemove.remove(annotation); - } else { - annotation = this.buildAnnotation(jdtAnnotationName); - annotation.initialize((CompilationUnit) node.getRoot()); - this.addItemToCollection(annotation, this.annotations, ANNOTATIONS_COLLECTION); + for (String annotationName : annotationsToRemove.keySet()) { + this.annotations.remove(annotationName); } + this.fireItemsRemoved(ANNOTATIONS_COLLECTION, annotationsToRemove.values()); + + this.annotations.putAll(annotationsToAdd); + this.fireItemsAdded(ANNOTATIONS_COLLECTION, annotationsToAdd.values()); } - /** - * pre-condition: jdtAnnotationName is valid - */ - private void addOrSyncNestableAnnotation_(org.eclipse.jdt.core.dom.Annotation node, String nestableAnnotationName, Set<AnnotationContainer> containersToRemove) { - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - if (container != null) { - container.synchronizeNestableAnnotation(node); - containersToRemove.remove(container); - } - else { - container = new AnnotationContainer(nestableAnnotationName); - container.initializeNestableAnnotation(node); - this.annotationContainers.put(nestableAnnotationName, container); - this.fireItemAdded(NESTABLE_ANNOTATIONS_COLLECTION, container.nestedAnnotationAt(0)); + private void syncAnnotationContainers(HashMap<String, org.eclipse.jdt.core.dom.Annotation> astContainerAnnotations, HashMap<String, org.eclipse.jdt.core.dom.Annotation> astStandaloneNestableAnnotations) { + HashMap<String, CombinationAnnotationContainer> containersToRemove = new HashMap<String, CombinationAnnotationContainer>(this.annotationContainers); + HashMap<String, CombinationAnnotationContainer> containersToAdd = new HashMap<String, CombinationAnnotationContainer>(); + + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astContainerAnnotations.entrySet()) { + String containerAnnotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astContainerAnnotation = entry.getValue(); + String nestableAnnotationName = this.getNestableAnnotationName(containerAnnotationName); + CombinationAnnotationContainer container = containersToRemove.remove(nestableAnnotationName); + if (container == null) { + container = new CombinationAnnotationContainer(nestableAnnotationName, containerAnnotationName); + container.initializeFromContainerAnnotation(astContainerAnnotation); + containersToAdd.put(nestableAnnotationName, container); + } else { + container.synchronize(astContainerAnnotation); + } + // if it exists, strip out the standalone annotation + // corresponding to the current container annotation + astStandaloneNestableAnnotations.remove(nestableAnnotationName); + } + + for (Map.Entry<String, org.eclipse.jdt.core.dom.Annotation> entry : astStandaloneNestableAnnotations.entrySet()) { + String nestableAnnotationName = entry.getKey(); + org.eclipse.jdt.core.dom.Annotation astNestableAnnotation = entry.getValue(); + CombinationAnnotationContainer container = containersToRemove.remove(nestableAnnotationName); + if (container == null) { + container = new CombinationAnnotationContainer(nestableAnnotationName); + container.initializeFromStandaloneAnnotation(astNestableAnnotation); + containersToAdd.put(nestableAnnotationName, container); + } else { + container.synchronizeNestableAnnotation(astNestableAnnotation); + } } - } - /** - * pre-condition: node is valid container annotation - */ - private void addOrSyncContainerAnnotation_(org.eclipse.jdt.core.dom.Annotation node, String containerAnnotationName, Set<AnnotationContainer> containersToRemove) { - String nestableAnnotationName = this.getNestableAnnotationName(containerAnnotationName); - AnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); - if (container == null) { - container = new AnnotationContainer(nestableAnnotationName); - container.initialize(node); - this.annotationContainers.put(nestableAnnotationName, container); - this.fireItemsAdded(NESTABLE_ANNOTATIONS_COLLECTION, CollectionTools.collection(container.getNestedAnnotations())); + ArrayList<NestableAnnotation> removedNestableAnnotations = new ArrayList<NestableAnnotation>(); + for (String nestableAnnotationName : containersToRemove.keySet()) { + CombinationAnnotationContainer container = this.annotationContainers.remove(nestableAnnotationName); + CollectionTools.addAll(removedNestableAnnotations, container.getNestedAnnotations()); } - else { - container.synchronize(node); - containersToRemove.remove(container); + this.fireItemsRemoved(NESTABLE_ANNOTATIONS_COLLECTION, removedNestableAnnotations); + + ArrayList<NestableAnnotation> addedNestableAnnotations = new ArrayList<NestableAnnotation>(); + for (Map.Entry<String, CombinationAnnotationContainer> entry : containersToAdd.entrySet()) { + String nestableAnnotationName = entry.getKey(); + CombinationAnnotationContainer container = entry.getValue(); + this.annotationContainers.put(nestableAnnotationName, container); + CollectionTools.addAll(addedNestableAnnotations, container.getNestedAnnotations()); } + this.fireItemsAdded(NESTABLE_ANNOTATIONS_COLLECTION, addedNestableAnnotations); } - - // ********** miscellaneous ********** - - public Iterable<Annotation> getAllAnnotations() { + @SuppressWarnings("unchecked") + public Iterable<Annotation> getTopLevelAnnotations() { return new CompositeIterable<Annotation>( - getAnnotations(), - getContainerOrNestableAnnotations()); + this.getAnnotations(), + this.getContainerOrStandaloneNestableAnnotations() + ); } - - protected Iterable<Annotation> getContainerOrNestableAnnotations() { - return new TransformationIterable<AnnotationContainer, Annotation>(this.annotationContainers.values()) { - @Override - protected Annotation transform(AnnotationContainer o) { - return (o.getContainerAnnotation() != null) ? o.getContainerAnnotation() : CollectionTools.get(o.getNestedAnnotations(), 0); - } - }; + + private Iterable<Annotation> getContainerOrStandaloneNestableAnnotations() { + return new TransformationIterable<CombinationAnnotationContainer_, Annotation>(this.getAnnotationContainers(), TOP_LEVEL_ANNOTATION_CONTAINER_TRANSFORMER); } - + + private static final Transformer<CombinationAnnotationContainer_, Annotation> TOP_LEVEL_ANNOTATION_CONTAINER_TRANSFORMER = new TopLevelAnnotationContainerTransformer(); + static final class TopLevelAnnotationContainerTransformer + extends TransformerAdapter<CombinationAnnotationContainer_, Annotation> + { + @Override + public Annotation transform(CombinationAnnotationContainer_ container) { + Annotation containerAnnotation = container.getContainerAnnotation(); + return (containerAnnotation != null) ? containerAnnotation : container.getNestedAnnotation(0); + } + } + public boolean isAnnotated() { - return ! (this.annotations.isEmpty() && this.annotationContainers.isEmpty()); + return ! this.isUnannotated(); } - public boolean isAnnotatedWith(Iterable<String> annotationNames) { - for (Annotation annotation : this.getAnnotations()) { - if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { - return true; - } - } - for (Annotation annotation : this.getNestableAnnotations()) { + public boolean isUnannotated() { + return this.annotations.isEmpty() && this.annotationContainers.isEmpty(); + } + + public boolean isAnnotatedWithAnyOf(Iterable<String> annotationNames) { + for (Annotation annotation : this.getSignificantAnnotations()) { if (CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { return true; } @@ -378,6 +460,21 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> return false; } + /** + * Return the "significant" annotations; + * i.e. ignore the container annotations (they have no semantics). + */ + @SuppressWarnings("unchecked") + private Iterable<Annotation> getSignificantAnnotations() { + return new CompositeIterable<Annotation>( + this.getAnnotations(), + this.getNestableAnnotations() + ); + } + + + // ********** misc ********** + public TextRange getTextRange(CompilationUnit astRoot) { // the AST is null for virtual Java attributes // TODO remove the AST null check once we start storing text ranges @@ -393,22 +490,15 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> } public TextRange getTextRange(String nestableAnnotationName, CompilationUnit astRoot) { - Annotation containerAnnotation = getContainerAnnotation(getAnnotationProvider().getContainerAnnotationName(nestableAnnotationName)); - if (containerAnnotation != null) { - return containerAnnotation.getTextRange(astRoot); + CombinationAnnotationContainer container = this.annotationContainers.get(nestableAnnotationName); + if (container == null) { + return null; } - Annotation nestableAnnotation = getAnnotation(0, nestableAnnotationName); - return nestableAnnotation == null ? null : nestableAnnotation.getTextRange(astRoot); - } - - - private Annotation selectAnnotationNamed(Iterable<Annotation> list, String annotationName) { - for (Annotation annotation : list) { - if (annotation.getAnnotationName().equals(annotationName)) { - return annotation; - } + Annotation annotation = container.getContainerAnnotation(); + if (annotation == null) { + annotation = container.getNestedAnnotation(0); } - return null; + return annotation.getTextRange(astRoot); } private TextRange buildTextRange(ASTNode astNode) { @@ -416,116 +506,172 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> } - // ********** AST visitors ********** + // ********** AST visitor ********** /** - * annotation visitor + * This annotation visitor gathers up all the <em>significant</em> + * (i.e. non-duplicate with a valid name) AST annotations + * container annotations and standalone nestable annotations for its + * {@link #node}. */ - protected static abstract class AnnotationVisitor + /* CU private */ class AnnotationVisitor extends ASTVisitor { - protected final ASTNode node; - + private final ASTNode node; + final HashMap<String, org.eclipse.jdt.core.dom.Annotation> astAnnotations = new HashMap<String, org.eclipse.jdt.core.dom.Annotation>(); + final HashMap<String, org.eclipse.jdt.core.dom.Annotation> astContainerAnnotations = new HashMap<String, org.eclipse.jdt.core.dom.Annotation>(); + final HashMap<String, org.eclipse.jdt.core.dom.Annotation> astStandaloneNestableAnnotations = new HashMap<String, org.eclipse.jdt.core.dom.Annotation>(); - protected AnnotationVisitor(ASTNode node) { + AnnotationVisitor(ASTNode node) { super(); this.node = node; } @Override - public boolean visit(SingleMemberAnnotation node) { - return this.visit_(node); + public boolean visit(SingleMemberAnnotation annotation) { + return this.visit_(annotation); } @Override - public boolean visit(NormalAnnotation node) { - return this.visit_(node); + public boolean visit(NormalAnnotation annotation) { + return this.visit_(annotation); } @Override - public boolean visit(MarkerAnnotation node) { - return this.visit_(node); + public boolean visit(MarkerAnnotation annotation) { + return this.visit_(annotation); } - protected boolean visit_(org.eclipse.jdt.core.dom.Annotation node) { - // ignore annotations for child members, only this member - if (node.getParent() == this.node) { - this.visitChildAnnotation(node); + /** + * Process only the annotations for the {@link #node}; ignore any children. + */ + private boolean visit_(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + if (astAnnotation.getParent() == this.node) { + this.visitChildAnnotation(astAnnotation); } - return false; + return false; // => do *not* visit children } - protected abstract void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node); - } - + /** + * For each annotation name we save only the first one + * and ignore duplicates. + */ + private void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + String astAnnotationName = this.resolveAnnotationName(astAnnotation); + if (astAnnotationName == null) { + return; + } + // check whether the annotation is a valid container annotation first + // because container validations are also valid annotations + // TODO remove container annotations from list of annotations??? + if (SourceAnnotatedElement.this.annotationIsValidContainer(astAnnotationName)) { + if (this.astContainerAnnotations.get(astAnnotationName) == null) { + this.astContainerAnnotations.put(astAnnotationName, astAnnotation); + } + } + else if (SourceAnnotatedElement.this.annotationIsValid(astAnnotationName)) { + if (this.astAnnotations.get(astAnnotationName) == null) { + this.astAnnotations.put(astAnnotationName, astAnnotation); + } + } + else if (SourceAnnotatedElement.this.annotationIsValidNestable(astAnnotationName)) { + if (this.astStandaloneNestableAnnotations.get(astAnnotationName) == null) { + this.astStandaloneNestableAnnotations.put(astAnnotationName, astAnnotation); + } + } + } - /** - * initial annotation visitor - */ - protected class InitialAnnotationVisitor - extends AnnotationVisitor - { - protected InitialAnnotationVisitor(ASTNode node) { - super(node); + /** + * Return the specified annotation's (fully-qualified) class name. + */ + private String resolveAnnotationName(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + IAnnotationBinding annotationBinding = astAnnotation.resolveAnnotationBinding(); + if (annotationBinding == null) { + return null; + } + ITypeBinding annotationTypeBinding = annotationBinding.getAnnotationType(); + return (annotationTypeBinding == null) ? null : annotationTypeBinding.getQualifiedName(); } @Override - protected void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node) { - SourceAnnotatedElement.this.addInitialAnnotation(node); + public String toString() { + return StringTools.buildToStringFor(this, node); } } + // ********** annotation container ********** + /** - * synchronize annotation visitor + * Use this interface to make static references to the annotation container. + * Sort of a hack.... + * @see AnnotationContainerNestedAnnotationsTransformer + * @see TopLevelAnnotationContainerTransformer */ - protected class SynchronizeAnnotationVisitor - extends AnnotationVisitor - { - protected final Set<Annotation> annotationsToRemove; - protected final Set<AnnotationContainer> containersToRemove; - - protected SynchronizeAnnotationVisitor(ASTNode node, Set<Annotation> annotationsToRemove, Set<AnnotationContainer> containersToRemove) { - super(node); - this.annotationsToRemove = annotationsToRemove; - this.containersToRemove = containersToRemove; - } - - @Override - protected void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node) { - SourceAnnotatedElement.this.addOrSyncAnnotation(node, this.annotationsToRemove, this.containersToRemove); - } + private interface CombinationAnnotationContainer_ { + Annotation getContainerAnnotation(); + ListIterable<NestableAnnotation> getNestedAnnotations(); + NestableAnnotation getNestedAnnotation(int index); } - class AnnotationContainer extends SourceNode.AnnotationContainer<NestableAnnotation> + /** + * Annotation container for top-level "combination" annotations that allow + * a single nestable annotation to stand alone, outside of its standard + * container annotation, and represent a single-element array. + */ + /* CU private */ class CombinationAnnotationContainer + extends AnnotationContainer<NestableAnnotation> + implements CombinationAnnotationContainer_ { + /** + * The name of the nestable annotation that be either a top-level + * standalone annotation or nested within the container annotation. + */ private final String nestableAnnotationName; + /** + * The name of the container annotation, used to build the + * {@link #containerAnnotation container annotation} as necessary. + */ + private final String containerAnnotationName; + + /** + * This is <code>null</code> if the container annotation does not exist + * but the standalone nestable annotation does. + */ private Annotation containerAnnotation; - - protected AnnotationContainer(String nestableAnnotationName) { + + + CombinationAnnotationContainer(String nestableAnnotationName) { + this(nestableAnnotationName, SourceAnnotatedElement.this.getContainerAnnotationName(nestableAnnotationName)); + } + + CombinationAnnotationContainer(String nestableAnnotationName, String containerAnnotationName) { super(); + if ((nestableAnnotationName == null) || (containerAnnotationName == null)) { + throw new NullPointerException(); + } this.nestableAnnotationName = nestableAnnotationName; + this.containerAnnotationName = containerAnnotationName; } @Override - public void initialize(org.eclipse.jdt.core.dom.Annotation astContainerAnnotation) { - super.initialize(astContainerAnnotation); - this.containerAnnotation = this.buildContainerAnnotation(ASTTools.resolveAnnotation(astContainerAnnotation)); + public void initializeFromContainerAnnotation(org.eclipse.jdt.core.dom.Annotation astContainerAnnotation) { + super.initializeFromContainerAnnotation(astContainerAnnotation); + this.containerAnnotation = this.buildContainerAnnotation(this.containerAnnotationName); } - protected Annotation buildContainerAnnotation(String name) { - return getAnnotationProvider().buildAnnotation(SourceAnnotatedElement.this, SourceAnnotatedElement.this.annotatedElement, name); + private Annotation buildContainerAnnotation(String name) { + return SourceAnnotatedElement.this.buildAnnotation(name); } - protected Annotation getContainerAnnotation() { + public Annotation getContainerAnnotation() { return this.containerAnnotation; } - @Override - public void synchronize(org.eclipse.jdt.core.dom.Annotation astContainerAnnotation) { - super.synchronize(astContainerAnnotation); + String getContainerAnnotationName() { + return this.containerAnnotationName; } /** @@ -552,46 +698,67 @@ abstract class SourceAnnotatedElement<A extends AnnotatedElement> return SourceAnnotatedElement.this.buildNestableAnnotation(this.nestableAnnotationName, index); } - public void initializeNestableAnnotation(org.eclipse.jdt.core.dom.Annotation standaloneNestableAnnotation) { + void initializeFromStandaloneAnnotation(org.eclipse.jdt.core.dom.Annotation astStandaloneNestableAnnotation) { NestableAnnotation nestedAnnotation = this.buildNestedAnnotation(0); this.nestedAnnotations.add(nestedAnnotation); - nestedAnnotation.initialize((CompilationUnit) standaloneNestableAnnotation.getRoot()); + nestedAnnotation.initialize((CompilationUnit) astStandaloneNestableAnnotation.getRoot()); // TODO pass the AST annotation! } - public void synchronizeNestableAnnotation(org.eclipse.jdt.core.dom.Annotation standaloneNestableAnnotation) { - if (this.getNestedAnnotationsSize() > 1) { - //ignore the new standalone annotation as a container annotation already exists - } - else if (this.getNestedAnnotationsSize() == 1) { - this.containerAnnotation = null; - this.nestedAnnotationAt(0).synchronizeWith((CompilationUnit) standaloneNestableAnnotation.getRoot()); + /** + * If we get here, the container annotation does <em>not</em> exist but + * the standalone nestable annotation does. + */ + void synchronizeNestableAnnotation(org.eclipse.jdt.core.dom.Annotation astStandaloneNestableAnnotation) { + if (this.nestedAnnotations.size() == 0) { + throw new IllegalStateException(); // should not get here... } + + this.containerAnnotation = null; + this.nestedAnnotations.get(0).synchronizeWith((CompilationUnit) astStandaloneNestableAnnotation.getRoot()); // TODO pass the AST annotation! + // remove any remaining nested annotations + this.syncRemoveNestedAnnotations(1); } @Override public NestableAnnotation addNestedAnnotation(int index) { - if (getNestedAnnotationsSize() == 1 && getContainerAnnotation() == null) { - this.containerAnnotation = buildContainerAnnotation(getAnnotationProvider().getContainerAnnotationName(getNestedAnnotationName())); + if ((this.nestedAnnotations.size() == 1) && (this.containerAnnotation == null)) { + this.containerAnnotation = this.buildContainerAnnotation(this.containerAnnotationName); } return super.addNestedAnnotation(index); } @Override public NestableAnnotation removeNestedAnnotation(int index) { - if (getNestedAnnotationsSize() == 2) { + if (this.nestedAnnotations.size() == 2) { this.containerAnnotation = null; } return super.removeNestedAnnotation(index); } + /** + * <strong>NB:</strong> This is a <em>collection</em> name. + * @see #nestedAnnotationAdded(int, NestableAnnotation) + * @see #nestedAnnotationsRemoved(int, List) + */ + @Override + protected String getNestedAnnotationsListName() { + throw new UnsupportedOperationException(); + } + + /** + * <strong>NB:</strong> Convert to a <em>collection</em> change. + */ @Override - protected void fireItemAdded(int index, NestableAnnotation nestedAnnotation) { - SourceAnnotatedElement.this.fireItemAdded(NESTABLE_ANNOTATIONS_COLLECTION, nestedAnnotation); + void nestedAnnotationAdded(int index, NestableAnnotation addedAnnotation) { + SourceAnnotatedElement.this.nestedAnnotationAdded(NESTABLE_ANNOTATIONS_COLLECTION, addedAnnotation); } + /** + * <strong>NB:</strong> Convert to a <em>collection</em> change. + */ @Override - protected void fireItemsRemoved(int index, List<NestableAnnotation> removedItems) { - SourceAnnotatedElement.this.fireItemsRemoved(NESTABLE_ANNOTATIONS_COLLECTION, removedItems); + void nestedAnnotationsRemoved(int index, List<NestableAnnotation> removedAnnotations) { + SourceAnnotatedElement.this.nestedAnnotationsRemoved(NESTABLE_ANNOTATIONS_COLLECTION, removedAnnotations); } } } diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotation.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotation.java index 75f693464d..a7eaef1f9e 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotation.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceAnnotation.java @@ -217,35 +217,4 @@ public abstract class SourceAnnotation private IndexedAnnotationAdapter getIndexedAnnotationAdapter() { return (IndexedAnnotationAdapter) this.annotationAdapter; } - - - // ********** annotation container ********** - - /** - * 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 - */ - public abstract class AnnotationContainer<T extends NestableAnnotation> - extends SourceNode.AnnotationContainer<T> - { - protected AnnotationContainer() { - super(); - } - - /** - * Return the annotations property name for firing property change notification - */ - protected abstract String getAnnotationsPropertyName(); - - @Override - protected void fireItemAdded(int index, T addedItem) { - SourceAnnotation.this.fireItemAdded(this.getAnnotationsPropertyName(), index, addedItem); - } - - @Override - protected void fireItemsRemoved(int index, java.util.List<T> removedItems) { - SourceAnnotation.this.fireItemsRemoved(this.getAnnotationsPropertyName(), index, removedItems); - } - } } diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceMember.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceMember.java index 694c3af5ab..f872eac69c 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceMember.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceMember.java @@ -9,8 +9,6 @@ ******************************************************************************/ package org.eclipse.jpt.common.core.internal.resource.java.source; -import java.util.ArrayList; -import java.util.Iterator; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.Modifier; @@ -18,7 +16,6 @@ import org.eclipse.jpt.common.core.resource.java.Annotation; import org.eclipse.jpt.common.core.resource.java.JavaResourceMember; import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; import org.eclipse.jpt.common.core.utility.jdt.Member; -import org.eclipse.jpt.common.utility.internal.CollectionTools; /** * Java source member (annotations, "persistable") @@ -27,7 +24,6 @@ abstract class SourceMember<M extends Member> extends SourceAnnotatedElement<M> implements JavaResourceMember { - boolean final_; // 'final' is a reserved word boolean transient_; // 'transient' is a reserved word @@ -66,50 +62,6 @@ abstract class SourceMember<M extends Member> this.syncProtected(this.buildProtected(binding)); } - - // ********** annotations ********** - - public Annotation setPrimaryAnnotation(String primaryAnnotationName, Iterable<String> supportingAnnotationNames) { - ArrayList<String> annotationNames = new ArrayList<String>(); - CollectionTools.addAll(annotationNames, supportingAnnotationNames); - if (primaryAnnotationName != null) { - annotationNames.add(primaryAnnotationName); - } - for (Annotation annotation : this.getAnnotations()) { - if ( ! CollectionTools.contains(annotationNames, annotation.getAnnotationName())) { - this.annotations.remove(annotation); - annotation.removeAnnotation(); - } - } - Iterator<AnnotationContainer> containers = this.annotationContainers.values().iterator(); - for (; containers.hasNext();) { - AnnotationContainer container = containers.next(); - if (container.getContainerAnnotation() != null) { - if ( ! CollectionTools.contains(annotationNames, container.getContainerAnnotation().getAnnotationName())) { - containers.remove(); - container.getContainerAnnotation().removeAnnotation(); - } - } - else { - //At this point the only thing remaining would be a standalone "nestable" annotation - String nestedAnnotatioName = container.getNestedAnnotationName(); - if ( ! CollectionTools.contains(annotationNames, nestedAnnotatioName)) { - containers.remove(); - container.getNestedAnnotations().iterator().next().removeAnnotation(); - } - } - } - - Annotation newPrimaryAnnotation = this.getAnnotation(primaryAnnotationName); - if ((primaryAnnotationName != null) && (newPrimaryAnnotation == null)) { - newPrimaryAnnotation = this.buildAnnotation(primaryAnnotationName); - this.annotations.add(newPrimaryAnnotation); - newPrimaryAnnotation.newAnnotation(); - } - return newPrimaryAnnotation; - } - - // ***** final public boolean isFinal() { return this.final_; @@ -191,7 +143,13 @@ abstract class SourceMember<M extends Member> return this.annotatedElement.matches(memberName, occurrence); } + @Override + public Annotation setPrimaryAnnotation(String primaryAnnotationName, Iterable<String> supportingAnnotationNames) { + return super.setPrimaryAnnotation(primaryAnnotationName, supportingAnnotationNames); + } + public void resolveTypes(CompilationUnit astRoot) { + // do nothing? } public boolean isPublicOrProtected() { diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceNode.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceNode.java index 2b2ffbaa38..0b0f31b7e2 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceNode.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/source/SourceNode.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Oracle. All rights reserved. + * Copyright (c) 2010, 2012 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. @@ -21,6 +21,7 @@ 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.common.core.AnnotationProvider; import org.eclipse.jpt.common.core.internal.resource.java.AbstractJavaResourceNode; import org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit; import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; @@ -38,7 +39,7 @@ public abstract class SourceNode extends AbstractJavaResourceNode { - public SourceNode(JavaResourceNode parent) { + protected SourceNode(JavaResourceNode parent) { super(parent); } @@ -50,14 +51,31 @@ public abstract class SourceNode return this.getJavaResourceCompilationUnit().buildASTRoot(); } + protected void nestedAnnotationAdded(String listName, int index, NestableAnnotation addedAnnotation) { + this.fireItemAdded(listName, index, addedAnnotation); + } + + protected void nestedAnnotationsRemoved(String listName, int index, List<? extends NestableAnnotation> removedAnnotations) { + this.fireItemsRemoved(listName, index, removedAnnotations); + } + + @Override + protected AnnotationProvider getAnnotationProvider() { + return super.getAnnotationProvider(); + } + + + // ********** annotation container ********** + /** * A container for nested annotations. The owner of the AnnotationContainer - * needs to call initialize(org.eclipse.jdt.core.dom.Annotation) on it. - * @param <T> the type of the resource nestable annotations + * needs to call + * {@link #initializeFromContainerAnnotation(org.eclipse.jdt.core.dom.Annotation)} + * on it. + * @param <A> the type of the resource nestable annotations */ - abstract class AnnotationContainer<T extends NestableAnnotation> - { - protected final Vector<T> nestedAnnotations = new Vector<T>(); + protected abstract class AnnotationContainer<A extends NestableAnnotation> { + protected final Vector<A> nestedAnnotations = new Vector<A>(); protected AnnotationContainer() { super(); @@ -76,18 +94,14 @@ public abstract class SourceNode /** * Return a new nested annotation at the given index */ - protected abstract T buildNestedAnnotation(int index); - - protected abstract void fireItemAdded(int index, T nestedAnnotation); + protected abstract A buildNestedAnnotation(int index); - protected abstract void fireItemsRemoved(int index, List<T> removedItems); - - public void initialize(org.eclipse.jdt.core.dom.Annotation astContainerAnnotation) { + public void initializeFromContainerAnnotation(org.eclipse.jdt.core.dom.Annotation astContainerAnnotation) { // ignore the nested AST annotations themselves - // (maybe someday we can use them during initialization...) + // TODO (maybe someday we can use them during initialization...) int size = this.getNestedAstAnnotations(astContainerAnnotation).size(); for (int i = 0; i < size; i++) { - T nestedAnnotation = this.buildNestedAnnotation(i); + A nestedAnnotation = this.buildNestedAnnotation(i); this.nestedAnnotations.add(i, nestedAnnotation); nestedAnnotation.initialize((CompilationUnit) astContainerAnnotation.getRoot()); } @@ -101,10 +115,10 @@ public abstract class SourceNode ArrayList<org.eclipse.jdt.core.dom.Annotation> astAnnotations = this.getNestedAstAnnotations(astContainerAnnotation); Iterator<org.eclipse.jdt.core.dom.Annotation> astAnnotationStream = astAnnotations.iterator(); - for (T nestedAnnotation : this.getNestedAnnotations()) { + for (A 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 + astAnnotationStream.next(); // TODO pass this to the update nestedAnnotation.synchronizeWith((CompilationUnit) astContainerAnnotation.getRoot()); } else { // no more AST annotations - remove the remaining nested annotations and exit @@ -119,22 +133,22 @@ public abstract class SourceNode } } - public ListIterable<T> getNestedAnnotations() { - return new LiveCloneListIterable<T>(this.nestedAnnotations); + public ListIterable<A> getNestedAnnotations() { + return new LiveCloneListIterable<A>(this.nestedAnnotations); } public int getNestedAnnotationsSize() { return this.nestedAnnotations.size(); } - public T nestedAnnotationAt(int index) { + public A getNestedAnnotation(int index) { return this.nestedAnnotations.get(index); } - public T addNestedAnnotation(int index) { + public A addNestedAnnotation(int index) { // add a new annotation to the end of the list... - int sourceIndex = this.getNestedAnnotationsSize(); - T nestedAnnotation = this.buildNestedAnnotation(sourceIndex); + int sourceIndex = this.nestedAnnotations.size(); + A nestedAnnotation = this.buildNestedAnnotation(sourceIndex); this.nestedAnnotations.add(sourceIndex, nestedAnnotation); nestedAnnotation.newAnnotation(); nestedAnnotation.initialize(nestedAnnotation.getJavaResourceCompilationUnit().buildASTRoot()); @@ -143,22 +157,22 @@ public abstract class SourceNode return nestedAnnotation; } - public T moveNestedAnnotation(int targetIndex, int sourceIndex) { + public A 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); + public A removeNestedAnnotation(int index) { + A 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); + private A moveNestedAnnotation_(int targetIndex, int sourceIndex) { + A nestedAnnotation = CollectionTools.move(this.nestedAnnotations, targetIndex, sourceIndex).get(targetIndex); this.syncAstAnnotationsAfterMove(targetIndex, sourceIndex, nestedAnnotation); return nestedAnnotation; } @@ -274,7 +288,7 @@ public abstract class SourceNode } @SuppressWarnings("unchecked") - protected List<MemberValuePair> values(NormalAnnotation na) { + private List<MemberValuePair> values(NormalAnnotation na) { return na.values(); } @@ -284,9 +298,9 @@ public abstract class SourceNode * 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) { + private void syncAstAnnotationsAfterMove(int targetIndex, int sourceIndex, A nestedAnnotation) { // move the Java annotation to the end of the list... - nestedAnnotation.moveAnnotation(this.getNestedAnnotationsSize()); + nestedAnnotation.moveAnnotation(this.nestedAnnotations.size()); // ...then shift the other AST annotations over one slot... if (sourceIndex < targetIndex) { for (int i = sourceIndex; i < targetIndex; i++) { @@ -308,7 +322,7 @@ public abstract class SourceNode * starting at the specified index to prevent overlap. */ private void syncAstAnnotationsAfterRemove(int index) { - for (int i = index; i < this.getNestedAnnotationsSize(); i++) { + for (int i = index; i < this.nestedAnnotations.size(); 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 @@ -316,32 +330,50 @@ public abstract class SourceNode } } - protected void syncAddNestedAnnotation(org.eclipse.jdt.core.dom.Annotation astAnnotation) { - int index = this.getNestedAnnotationsSize(); - T nestedAnnotation = this.buildNestedAnnotation(index); + private void syncAddNestedAnnotation(org.eclipse.jdt.core.dom.Annotation astAnnotation) { + int index = this.nestedAnnotations.size(); + A nestedAnnotation = this.buildNestedAnnotation(index); nestedAnnotation.initialize((CompilationUnit) astAnnotation.getRoot()); this.nestedAnnotations.add(index, nestedAnnotation); - this.fireItemAdded(index, nestedAnnotation); + this.nestedAnnotationAdded(index, nestedAnnotation); + } + + void nestedAnnotationAdded(int index, A addedAnnotation) { + SourceNode.this.nestedAnnotationAdded(this.getNestedAnnotationsListName(), index, addedAnnotation); } - protected void syncRemoveNestedAnnotations(int index) { - List<T> subList = this.nestedAnnotations.subList(index, this.getNestedAnnotationsSize()); - List<T> removedItems = new ArrayList<T>(subList); + /** + * Remove the nested annotations from the specified index to the end of + * the list. + */ + void syncRemoveNestedAnnotations(int index) { + List<A> subList = this.nestedAnnotations.subList(index, this.nestedAnnotations.size()); + List<A> removedAnnotations = new ArrayList<A>(subList); subList.clear(); - this.fireItemsRemoved(index, removedItems); + this.nestedAnnotationsRemoved(index, removedAnnotations); + } + + void nestedAnnotationsRemoved(int index, List<A> removedAnnotations) { + SourceNode.this.nestedAnnotationsRemoved(this.getNestedAnnotationsListName(), index, removedAnnotations); } + /** + * Return the nested annotations list name for firing property change + * notification. + */ + protected abstract String getNestedAnnotationsListName(); + public boolean isEmpty() { return this.nestedAnnotations.isEmpty(); } - @Override - public String toString() { - return StringTools.buildToStringFor(this); + AnnotationProvider getAnnotationProvider() { + return SourceNode.this.getAnnotationProvider(); } - public void toString(StringBuilder sb) { - sb.append(this.nestedAnnotations); + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.nestedAnnotations); } } } diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/utility/jdt/ASTTools.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/utility/jdt/ASTTools.java index ccf435662e..3be76642bd 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/utility/jdt/ASTTools.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/utility/jdt/ASTTools.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2011 Oracle. All rights reserved. + * Copyright (c) 2005, 2012 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. @@ -15,11 +15,9 @@ import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.Annotation; 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.IAnnotationBinding; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; @@ -83,19 +81,6 @@ public class ASTTools { } /** - * Return the fully-qualified name of the specified node's annotation - * class. - */ - public static String resolveAnnotation(Annotation node) { - IAnnotationBinding annotationBinding = node.resolveAnnotationBinding(); - if (annotationBinding == null) { - return null; - } - ITypeBinding annotationTypeBinding = annotationBinding.getAnnotationType(); - return (annotationTypeBinding == null) ? null : annotationTypeBinding.getQualifiedName(); - } - - /** * If the specified expression is a type literal, return the type's fully- * qualified name. Return null otherwise. */ diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/resource/java/JavaResourceAnnotatedElement.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/resource/java/JavaResourceAnnotatedElement.java index dbc44f7499..5176d120ef 100644 --- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/resource/java/JavaResourceAnnotatedElement.java +++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/resource/java/JavaResourceAnnotatedElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2011 Oracle. All rights reserved. + * Copyright (c) 2010, 2012 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. @@ -133,11 +133,14 @@ public interface JavaResourceAnnotatedElement // ********** queries ********** /** - * Return all top level annotations. - * If there is a container annotation, return that and not any nestables within it. - * If there is a nestable alone, return that and not the container. + * Return the element's "top level" annotations. + * For "combination" annotations (i.e. a virtual array of annotations that + * can be either a single <em>standalone</em> annotation [representing an + * array of length one] or an array of annotations witin a + * <em>container</em> annotation), only the <em>container</em> annotation is + * included (if it is present) or the single <em>standalone</em> annotation. */ - Iterable<Annotation> getAllAnnotations(); + Iterable<Annotation> getTopLevelAnnotations(); /** * Return whether the underlying JDT member is currently annotated with any recognized @@ -148,7 +151,7 @@ public interface JavaResourceAnnotatedElement /** * Return whether the underlying JDT member is annotated with any of the given annotations. */ - boolean isAnnotatedWith(Iterable<String> annotationNames); + boolean isAnnotatedWithAnyOf(Iterable<String> annotationNames); /** * Return the element kind |