diff options
author | bvosburgh | 2008-05-15 05:29:48 +0000 |
---|---|---|
committer | bvosburgh | 2008-05-15 05:29:48 +0000 |
commit | f0f9657d3b820c12d9658ab360947c939e6c75d9 (patch) | |
tree | 6ad923f9582ab8dec642dd1a00a74065e6dcb52f | |
parent | 2315456dc5dbd5e45bc382488eac041d0afb6d8d (diff) | |
download | webtools.dali-f0f9657d3b820c12d9658ab360947c939e6c75d9.tar.gz webtools.dali-f0f9657d3b820c12d9658ab360947c939e6c75d9.tar.xz webtools.dali-f0f9657d3b820c12d9658ab360947c939e6c75d9.zip |
[225885] fix editing annotations with property access
51 files changed, 3894 insertions, 2014 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFile.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFile.java index 56c5191022..73868f9448 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFile.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFile.java @@ -40,6 +40,23 @@ public interface JpaFile extends JpaNode */ ResourceModel getResourceModel(); + /** + * Forward the Java element changed event to the JPA file's content. + */ + void javaElementChanged(ElementChangedEvent event); + + /** + * Update the JPA resource model from the underlying resource. + */ + void updateFromResource(); + + /** + * The JPA file has been removed from the JPA project. Clean up any + * hooks to external resources etc. + */ + void dispose(); + + // **************** root structure nodes ************************************* /** @@ -53,6 +70,7 @@ public interface JpaFile extends JpaNode Iterator<JpaStructureNode> rootStructureNodes(); int rootStructureNodesSize(); + /** * Set the root context model object represented by this JPA file. * There is the potential for multiple root structure nodes @@ -65,20 +83,10 @@ public interface JpaFile extends JpaNode void addRootStructureNode(Object key, JpaStructureNode rootStructureNode); void removeRootStructureNode(Object key); + /** * Return the structure node best represented by the location in the file. */ JpaStructureNode getStructureNode(int textOffset); - /** - * Forward the Java element changed event to the JPA file's content. - */ - void javaElementChanged(ElementChangedEvent event); - - /** - * The JPA file has been removed from the JPA project. Clean up any - * hooks to external resources etc. - */ - void dispose(); - } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java index dd5f4753ff..2b4abb5adb 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java @@ -19,7 +19,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; import org.eclipse.jpt.core.context.JpaRootContextNode; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; import org.eclipse.jpt.db.ConnectionProfile; @@ -185,14 +184,15 @@ public interface JpaProject extends JpaNode { JpaRootContextNode getRootContext(); /** - * Return an iterator on all ITypes that are annotated within this project + * Return the names of the JPA project's annotated classes. */ - Iterator<IType> annotatedClasses(); + Iterator<String> annotatedClassNames(); /** * Return the Java persistent type resource for the specified fully qualified type name; * null, if none exists. */ + // TODO rename getJavaResourcePersistentType(String) JavaResourcePersistentType getJavaPersistentTypeResource(String typeName); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/ResourceModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/ResourceModel.java index f5a77731f9..c2c1f6908a 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/ResourceModel.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/ResourceModel.java @@ -55,6 +55,11 @@ public interface ResourceModel extends Model void javaElementChanged(ElementChangedEvent event); + /** + * Update the resource model from the underlying resource. + */ + void updateFromResource(); + void addResourceModelChangeListener(ResourceModelListener listener); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractResourceModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractResourceModel.java index 072eb7fcf3..4b67456ff2 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractResourceModel.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractResourceModel.java @@ -17,10 +17,10 @@ public abstract class AbstractResourceModel extends AbstractModel implements ResourceModel { - protected final IFile file; - + protected AbstractResourceModel(IFile file) { + super(); this.file = file; } @@ -28,9 +28,8 @@ public abstract class AbstractResourceModel return this.file; } - public abstract Object getResource(); - - public void dispose() { + // do nothing by default } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaFile.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaFile.java index 1f15eb65a3..c180d7c15b 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaFile.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaFile.java @@ -123,4 +123,9 @@ public class GenericJpaFile extends AbstractJpaNode implements JpaFile sb.append(getResourceType()); sb.append(")"); } + + public void updateFromResource() { + this.resourceModel.updateFromResource(); + } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaProject.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaProject.java index 566ac28a1c..da6eb5bc3e 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaProject.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaProject.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; + import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -23,14 +24,11 @@ import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jpt.core.JpaDataSource; import org.eclipse.jpt.core.JpaFile; import org.eclipse.jpt.core.JpaPlatform; @@ -392,31 +390,20 @@ public class GenericJpaProject extends AbstractJpaNode implements JpaProject { // ********** more queries ********** - public Iterator<IType> annotatedClasses() { - return new FilteringIterator<IType, IType>( - new TransformationIterator<JavaResourcePersistentType, IType>(annotatedJavaPersistentTypes()) { - @Override - protected IType transform(JavaResourcePersistentType next) { - try { - return getJavaProject().findType(next.getQualifiedName(), new NullProgressMonitor()); - } - catch (JavaModelException jme) { - return null; - } - } - }) { + public Iterator<String> annotatedClassNames() { + return new TransformationIterator<JavaResourcePersistentType, String>(this.annotatedJavaPersistentTypes()) { @Override - protected boolean accept(IType o) { - return o != null; + protected String transform(JavaResourcePersistentType next) { + return next.getQualifiedName(); } }; } protected Iterator<JavaResourcePersistentType> annotatedJavaPersistentTypes() { - return new FilteringIterator<JavaResourcePersistentType, JavaResourcePersistentType>(javaResourcePersistentTypes()) { + return new FilteringIterator<JavaResourcePersistentType, JavaResourcePersistentType>(this.javaResourcePersistentTypes()) { @Override protected boolean accept(JavaResourcePersistentType persistentType) { - return persistentType == null ? false : persistentType.isPersisted(); + return (persistentType == null) ? false : persistentType.isPersisted(); } }; } @@ -442,7 +429,7 @@ public class GenericJpaProject extends AbstractJpaNode implements JpaProject { return new TransformationIterator<JpaFile, JpaCompilationUnit>(this.javaJpaFiles()) { @Override protected JpaCompilationUnit transform(JpaFile jpaFile) { - return ((JavaResourceModel) jpaFile.getResourceModel()).getResource(); + return ((JavaResourceModel) jpaFile.getResourceModel()).getJpaCompilationUnit(); } }; } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/GenericRootContextNode.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/GenericRootContextNode.java index 3df53ba009..9151a05981 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/GenericRootContextNode.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/GenericRootContextNode.java @@ -14,7 +14,6 @@ import java.util.List; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.core.IType; import org.eclipse.jpt.core.JpaProject; import org.eclipse.jpt.core.JptCorePlugin; import org.eclipse.jpt.core.context.JpaContextNode; @@ -224,37 +223,37 @@ public class GenericRootContextNode extends AbstractJpaContextNode if (getJpaProject().discoversAnnotatedClasses()) { return; } - Collection<IType> orphanedClasses = CollectionTools.collection(getJpaProject().annotatedClasses()); + Collection<String> orphanedClassNames = CollectionTools.collection(getJpaProject().annotatedClassNames()); if (getPersistenceXml().getPersistence().persistenceUnitsSize() != 1) { //context model currently only supports 1 persistenceUnit return; } PersistenceUnit persistenceUnit = getPersistenceXml().getPersistence().persistenceUnits().next(); - for (IType type : CollectionTools.iterable(getJpaProject().annotatedClasses())) { + for (String typeName : CollectionTools.iterable(getJpaProject().annotatedClassNames())) { for (ClassRef classRef : CollectionTools.iterable(persistenceUnit.specifiedClassRefs())) { - if (classRef.isFor(type.getFullyQualifiedName('.'))) { - orphanedClasses.remove(type); + if (classRef.isFor(typeName)) { + orphanedClassNames.remove(typeName); } } for (MappingFileRef mappingFileRef : CollectionTools.iterable(persistenceUnit.mappingFileRefs())) { if (mappingFileRef.getOrmXml() == null || mappingFileRef.getOrmXml().getEntityMappings() == null) { continue; } - if (mappingFileRef.getOrmXml().getEntityMappings().getPersistentType(type.getFullyQualifiedName('.')) != null) { - orphanedClasses.remove(type); + if (mappingFileRef.getOrmXml().getEntityMappings().getPersistentType(typeName) != null) { + orphanedClassNames.remove(typeName); } } } - for (IType orphanedType : orphanedClasses) { - JavaResourcePersistentType javaResourcePersistentType = getJpaProject().getJavaPersistentTypeResource(orphanedType.getFullyQualifiedName('.')); + for (String orphanedTypeName : orphanedClassNames) { + JavaResourcePersistentType javaResourcePersistentType = getJpaProject().getJavaPersistentTypeResource(orphanedTypeName); messages.add( DefaultJpaValidationMessages.buildMessage( IMessage.HIGH_SEVERITY, JpaValidationMessages.PERSISTENT_TYPE_UNSPECIFIED_CONTEXT, new String[] {persistenceUnit.getName()}, javaResourcePersistentType.getResourceModel().getFile(), - javaResourcePersistentType.getMappingAnnotation().getTextRange(JDTTools.buildASTRoot(orphanedType))) + javaResourcePersistentType.getMappingAnnotation().getTextRange(JDTTools.buildASTRoot(javaResourcePersistentType.getJpaCompilationUnit().getCompilationUnit()))) ); } } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentAttribute.java index 36cb7608d3..7c0cfcd257 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentAttribute.java @@ -21,6 +21,7 @@ import org.eclipse.jpt.core.context.java.JavaPersistentAttribute; import org.eclipse.jpt.core.context.java.JavaPersistentType; import org.eclipse.jpt.core.context.java.JavaStructureNodes; import org.eclipse.jpt.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.core.internal.utility.jdt.JDTTools; import org.eclipse.jpt.core.resource.java.Annotation; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute; import org.eclipse.jpt.core.utility.TextRange; @@ -193,16 +194,11 @@ public class GenericJavaPersistentAttribute extends AbstractJavaJpaContextNode public boolean contains(int offset, CompilationUnit astRoot) { TextRange fullTextRange = this.getFullTextRange(astRoot); - if (fullTextRange == null) { - //This happens if the attribute no longer exists in the java. - //The text selection event is fired before the update from java so our - //model has not yet had a chance to update appropriately. The list of - //JavaPersistentAttriubtes is stale at this point. For now, we are trying - //to avoid the NPE, not sure of the ultimate solution to these 2 threads accessing - //our model - return false; - } - return fullTextRange.includes(offset); + // 'fullTextRange' will be null if the attribute no longer exists in the java; + // the context model can be out of synch with the resource model + // when a selection event occurs before the context model has a + // chance to synch with the resource model via the update thread + return (fullTextRange == null) ? false : fullTextRange.includes(offset); } @@ -219,52 +215,55 @@ public class GenericJavaPersistentAttribute extends AbstractJavaJpaContextNode } public TextRange getSelectionTextRange() { - return getSelectionTextRange(this.resourcePersistentAttribute.getMember().getAstRoot()); + return getSelectionTextRange(this.buildASTRoot()); + } + + protected CompilationUnit buildASTRoot() { + return JDTTools.buildASTRoot(this.resourcePersistentAttribute.getJpaCompilationUnit().getCompilationUnit()); } - - public void update(JavaResourcePersistentAttribute resourcePersistentAttribute) { - this.resourcePersistentAttribute = resourcePersistentAttribute; - this.setName(this.name(resourcePersistentAttribute)); - this.updateDefaultMapping(resourcePersistentAttribute); - this.updateSpecifiedMapping(resourcePersistentAttribute); + public void update(JavaResourcePersistentAttribute jrpa) { + this.resourcePersistentAttribute = jrpa; + this.setName(this.name(jrpa)); + this.updateDefaultMapping(jrpa); + this.updateSpecifiedMapping(jrpa); } - protected String name(JavaResourcePersistentAttribute resourcePersistentAttribute) { - return resourcePersistentAttribute.getName(); + protected String name(JavaResourcePersistentAttribute jrpa) { + return jrpa.getName(); } public String specifiedMappingAnnotationName() { return (this.specifiedMapping == null) ? null : this.specifiedMapping.getAnnotationName(); } - protected void updateSpecifiedMapping(JavaResourcePersistentAttribute resourcePersistentAttribute) { - String javaMappingAnnotationName = this.javaMappingAnnotationName(resourcePersistentAttribute); + protected void updateSpecifiedMapping(JavaResourcePersistentAttribute jrpa) { + String javaMappingAnnotationName = this.javaMappingAnnotationName(jrpa); if (specifiedMappingAnnotationName() != javaMappingAnnotationName) { - setSpecifiedMapping(createJavaAttributeMappingFromAnnotation(javaMappingAnnotationName, resourcePersistentAttribute)); + setSpecifiedMapping(createJavaAttributeMappingFromAnnotation(javaMappingAnnotationName, jrpa)); } else { if (getSpecifiedMapping() != null) { - getSpecifiedMapping().update(resourcePersistentAttribute); + getSpecifiedMapping().update(jrpa); } } } - protected void updateDefaultMapping(JavaResourcePersistentAttribute resourcePersistentAttribute) { + protected void updateDefaultMapping(JavaResourcePersistentAttribute jrpa) { String defaultMappingKey = getJpaPlatform().defaultJavaAttributeMappingKey(this); if (getDefaultMapping().getKey() != defaultMappingKey) { JavaAttributeMapping oldDefaultMapping = this.defaultMapping; this.defaultMapping = getJpaPlatform().buildDefaultJavaAttributeMapping(this); - this.defaultMapping.initializeFromResource(resourcePersistentAttribute); + this.defaultMapping.initializeFromResource(jrpa); firePropertyChanged(PersistentAttribute.DEFAULT_MAPPING_PROPERTY, oldDefaultMapping, this.defaultMapping); } else { - getDefaultMapping().update(resourcePersistentAttribute); + getDefaultMapping().update(jrpa); } } - protected String javaMappingAnnotationName(JavaResourcePersistentAttribute resourcePersistentAttribute) { - Annotation mappingAnnotation = (Annotation) resourcePersistentAttribute.getMappingAnnotation(); + protected String javaMappingAnnotationName(JavaResourcePersistentAttribute jrpa) { + Annotation mappingAnnotation = (Annotation) jrpa.getMappingAnnotation(); if (mappingAnnotation != null) { return mappingAnnotation.getAnnotationName(); } @@ -278,12 +277,12 @@ public class GenericJavaPersistentAttribute extends AbstractJavaJpaContextNode return getJpaPlatform().buildJavaAttributeMappingFromMappingKey(key, this); } - protected JavaAttributeMapping createJavaAttributeMappingFromAnnotation(String annotationName, JavaResourcePersistentAttribute resourcePersistentAttribute) { + protected JavaAttributeMapping createJavaAttributeMappingFromAnnotation(String annotationName, JavaResourcePersistentAttribute jrpa) { if (annotationName == null) { return null; } JavaAttributeMapping mapping = getJpaPlatform().buildJavaAttributeMappingFromAnnotation(annotationName, this); - mapping.initializeFromResource(resourcePersistentAttribute); + mapping.initializeFromResource(jrpa); return mapping; } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentType.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentType.java index d929b06059..94c1b84132 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentType.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/java/GenericJavaPersistentType.java @@ -14,6 +14,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; + import org.eclipse.core.resources.IResource; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.core.JpaFile; @@ -27,6 +28,7 @@ import org.eclipse.jpt.core.context.java.JavaPersistentAttribute; import org.eclipse.jpt.core.context.java.JavaPersistentType; import org.eclipse.jpt.core.context.java.JavaStructureNodes; import org.eclipse.jpt.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.core.internal.utility.jdt.JDTTools; import org.eclipse.jpt.core.resource.java.Annotation; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; @@ -63,7 +65,7 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem @Override public IResource getResource() { - return this.resourcePersistentType.getResourceModel().getResource().getCompilationUnit().getResource(); + return this.resourcePersistentType.getResourceModel().getJpaCompilationUnit().getCompilationUnit().getResource(); } //****************** JpaStructureNode implementation ******************* @@ -218,13 +220,14 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem return EmptyIterator.instance(); } + // it would be nice if the we passed in an astRoot here, but then we + // would need to pass it to the XML structure nodes too... public JpaStructureNode getStructureNode(int offset) { - //TODO astRoot, possibly get this instead of rebuilding it - CompilationUnit astRoot = this.resourcePersistentType.getMember().getAstRoot(); + CompilationUnit astRoot = this.buildASTRoot(); - if (contains(offset, astRoot)) { - for (Iterator<JavaPersistentAttribute> i = attributes(); i.hasNext();) { - JavaPersistentAttribute persistentAttribute = i.next(); + if (this.contains(offset, astRoot)) { + for (Iterator<JavaPersistentAttribute> stream = this.attributes(); stream.hasNext();) { + JavaPersistentAttribute persistentAttribute = stream.next(); if (persistentAttribute.contains(offset, astRoot)) { return persistentAttribute; } @@ -234,22 +237,21 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem return null; } + protected CompilationUnit buildASTRoot() { + return JDTTools.buildASTRoot(this.resourcePersistentType.getJpaCompilationUnit().getCompilationUnit()); + } + public boolean contains(int offset, CompilationUnit astRoot) { TextRange fullTextRange = this.getFullTextRange(astRoot); - if (fullTextRange == null) { - //This happens if the attribute no longer exists in the java. - //The text selection event is fired before the update from java so our - //model has not yet had a chance to update appropriately. The list of - //JavaPersistentAttriubtes is stale at this point. For now, we are trying - //to avoid the NPE, not sure of the ultimate solution to these 2 threads accessing - //our model - return false; - } - return fullTextRange.includes(offset); + // 'fullTextRange' will be null if the type no longer exists in the java; + // the context model can be out of synch with the resource model + // when a selection event occurs before the context model has a + // chance to synch with the resource model via the update thread + return (fullTextRange == null) ? false : fullTextRange.includes(offset); } - public TextRange getFullTextRange(CompilationUnit astRoot) { + protected TextRange getFullTextRange(CompilationUnit astRoot) { return this.resourcePersistentType.getTextRange(astRoot); } @@ -262,7 +264,7 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem } public TextRange getSelectionTextRange() { - return this.getSelectionTextRange(this.resourcePersistentType.getMember().getAstRoot()); + return this.getSelectionTextRange(this.buildASTRoot()); } @@ -288,13 +290,13 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem } // ******************** Updating ********************** - protected void initialize(JavaResourcePersistentType resourcePersistentType) { - this.resourcePersistentType = resourcePersistentType; - this.parentPersistentType = this.parentPersistentType(resourcePersistentType); - this.access = this.access(resourcePersistentType); - this.name = this.name(resourcePersistentType); - this.initializeMapping(resourcePersistentType); - this.initializePersistentAttributes(resourcePersistentType); + protected void initialize(JavaResourcePersistentType jrpt) { + this.resourcePersistentType = jrpt; + this.parentPersistentType = this.parentPersistentType(jrpt); + this.access = this.access(jrpt); + this.name = this.name(jrpt); + this.initializeMapping(jrpt); + this.initializePersistentAttributes(jrpt); } protected void initializeMapping(JavaResourcePersistentType persistentTypeResource) { @@ -313,18 +315,18 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem } } - public void update(JavaResourcePersistentType resourcePersistentType) { - this.resourcePersistentType = resourcePersistentType; + public void update(JavaResourcePersistentType jrpt) { + this.resourcePersistentType = jrpt; getJpaFile(this.resourcePersistentType.getResourceModel()).addRootStructureNode(this.resourcePersistentType.getQualifiedName(), this); - updateParentPersistentType(resourcePersistentType); - updateAccess(resourcePersistentType); - updateName(resourcePersistentType); - updateMapping(resourcePersistentType); - updatePersistentAttributes(resourcePersistentType); + updateParentPersistentType(jrpt); + updateAccess(jrpt); + updateName(jrpt); + updateMapping(jrpt); + updatePersistentAttributes(jrpt); } - protected void updateAccess(JavaResourcePersistentType resourcePersistentType) { - this.setAccess(this.access(resourcePersistentType)); + protected void updateAccess(JavaResourcePersistentType jrpt) { + this.setAccess(this.access(jrpt)); } /** @@ -336,7 +338,7 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem * If still null check the persistence-unit default Access * Default to FIELD if all else fails. */ - protected AccessType access(JavaResourcePersistentType resourcePersistentType) { + protected AccessType access(JavaResourcePersistentType jrpt) { AccessType javaAccess = null; boolean metadataComplete = false; if (getOrmPersistentType() != null) { @@ -344,7 +346,7 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem metadataComplete = getOrmPersistentType().getMapping().isMetadataComplete(); } if (javaAccess == null && !metadataComplete) { - javaAccess = AccessType.fromJavaResourceModel(resourcePersistentType.getAccess()); + javaAccess = AccessType.fromJavaResourceModel(jrpt.getAccess()); } if (javaAccess == null) { if (getParentPersistentType() != null) { @@ -369,21 +371,21 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem return javaAccess; } - protected void updateName(JavaResourcePersistentType resourcePersistentType) { - this.setName(this.name(resourcePersistentType)); + protected void updateName(JavaResourcePersistentType jrpt) { + this.setName(this.name(jrpt)); } - protected String name(JavaResourcePersistentType resourcePersistentType) { - return resourcePersistentType.getQualifiedName(); + protected String name(JavaResourcePersistentType jrpt) { + return jrpt.getQualifiedName(); } - protected void updateMapping(JavaResourcePersistentType resourcePersistentType) { - String javaMappingAnnotationName = this.javaMappingAnnotationName(resourcePersistentType); + protected void updateMapping(JavaResourcePersistentType jrpt) { + String javaMappingAnnotationName = this.javaMappingAnnotationName(jrpt); if (getMapping().getAnnotationName() != javaMappingAnnotationName) { - setMapping(createJavaTypeMappingFromAnnotation(javaMappingAnnotationName, resourcePersistentType)); + setMapping(createJavaTypeMappingFromAnnotation(javaMappingAnnotationName, jrpt)); } else { - getMapping().update(resourcePersistentType); + getMapping().update(jrpt); } } @@ -391,25 +393,25 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem return getJpaPlatform().buildJavaTypeMappingFromMappingKey(key, this); } - protected JavaTypeMapping createJavaTypeMappingFromAnnotation(String annotationName, JavaResourcePersistentType resourcePersistentType) { - JavaTypeMapping mapping = getJpaPlatform().buildJavaTypeMappingFromAnnotation(annotationName, this); - mapping.initializeFromResource(resourcePersistentType); - return mapping; + protected JavaTypeMapping createJavaTypeMappingFromAnnotation(String annotationName, JavaResourcePersistentType jrpt) { + JavaTypeMapping typeMapping = getJpaPlatform().buildJavaTypeMappingFromAnnotation(annotationName, this); + typeMapping.initializeFromResource(jrpt); + return typeMapping; } - protected String javaMappingAnnotationName(JavaResourcePersistentType resourcePersistentType) { - Annotation mappingAnnotation = (Annotation) resourcePersistentType.getMappingAnnotation(); + protected String javaMappingAnnotationName(JavaResourcePersistentType jrpt) { + Annotation mappingAnnotation = (Annotation) jrpt.getMappingAnnotation(); if (mappingAnnotation != null) { return mappingAnnotation.getAnnotationName(); } return null; } - protected void updatePersistentAttributes(JavaResourcePersistentType resourcePersistentType) { + protected void updatePersistentAttributes(JavaResourcePersistentType jrpt) { ListIterator<JavaPersistentAttribute> contextAttributes = attributes(); - Iterator<JavaResourcePersistentAttribute> resourceAttributes = resourcePersistentType.fields(); + Iterator<JavaResourcePersistentAttribute> resourceAttributes = jrpt.fields(); if (getAccess() == AccessType.PROPERTY) { - resourceAttributes = resourcePersistentType.properties(); + resourceAttributes = jrpt.properties(); } while (contextAttributes.hasNext()) { @@ -463,11 +465,8 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem if (possibleParent != null) { return possibleParent; } - JavaResourcePersistentType resourcePersistentType = getJpaProject().getJavaPersistentTypeResource(fullyQualifiedTypeName); - if (resourcePersistentType != null) { - return possibleParent(resourcePersistentType.getSuperClassQualifiedName()); - } - return null; + JavaResourcePersistentType jrpt = getJpaProject().getJavaPersistentTypeResource(fullyQualifiedTypeName); + return (jrpt == null) ? null : this.possibleParent(jrpt.getSuperClassQualifiedName()); } protected PersistentType getPersistentType(String fullyQualifiedTypeName) { @@ -477,7 +476,7 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem //*************** Validation ****************************************** public void addToMessages(List<IMessage> messages) { //get astRoot here to pass down - addToMessages(messages, this.resourcePersistentType.getMember().getAstRoot()); + addToMessages(messages, this.buildASTRoot()); } @Override @@ -516,4 +515,4 @@ public class GenericJavaPersistentType extends AbstractJavaJpaContextNode implem } } -}
\ No newline at end of file +} diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/persistence/GenericPersistenceUnit.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/persistence/GenericPersistenceUnit.java index 69b4cbf0bb..395bc9c04f 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/persistence/GenericPersistenceUnit.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/context/persistence/GenericPersistenceUnit.java @@ -17,7 +17,6 @@ import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.Set; -import org.eclipse.jdt.core.IType; import org.eclipse.jpt.core.JpaStructureNode; import org.eclipse.jpt.core.JptCorePlugin; import org.eclipse.jpt.core.context.AccessType; @@ -746,10 +745,10 @@ public class GenericPersistenceUnit extends AbstractPersistenceJpaContextNode } protected void initializeImpliedClassRefs(XmlPersistenceUnit xmlPersistenceUnit) { - if (getJpaProject().discoversAnnotatedClasses() && !isExcludeUnlistedClasses()) { - for (IType type : CollectionTools.iterable(getJpaProject().annotatedClasses())) { - if (! classIsSpecified(type.getFullyQualifiedName('.'))) { - impliedClassRefs.add(buildClassRef(type.getFullyQualifiedName('.'))); + if (getJpaProject().discoversAnnotatedClasses() && ! isExcludeUnlistedClasses()) { + for (String typeName : CollectionTools.iterable(this.getJpaProject().annotatedClassNames())) { + if ( ! classIsSpecified(typeName)) { + impliedClassRefs.add(buildClassRef(typeName)); } } } @@ -928,29 +927,29 @@ public class GenericPersistenceUnit extends AbstractPersistenceJpaContextNode protected void updateImpliedClassRefs(XmlPersistenceUnit persistenceUnit) { Iterator<ClassRef> impliedRefs = impliedClassRefs(); - Iterator<IType> annotatedClasses = getJpaProject().annotatedClasses(); + Iterator<String> annotatedClassNames = getJpaProject().annotatedClassNames(); - if (!isExcludeUnlistedClasses()) { + if ( ! isExcludeUnlistedClasses()) { while (impliedRefs.hasNext()) { ClassRef classRef = impliedRefs.next(); boolean updated = false; - while (! updated && annotatedClasses.hasNext()) { - IType annotatedClass = annotatedClasses.next(); - if (! classIsSpecified(annotatedClass.getFullyQualifiedName('.'))) { - classRef.update(annotatedClass.getFullyQualifiedName('.')); + while (! updated && annotatedClassNames.hasNext()) { + String annotatedClassName = annotatedClassNames.next(); + if ( ! classIsSpecified(annotatedClassName)) { + classRef.update(annotatedClassName); updated = true; } } - if (! annotatedClasses.hasNext() && ! updated) { + if (! annotatedClassNames.hasNext() && ! updated) { removeImpliedClassRef(classRef); } } - while (annotatedClasses.hasNext()) { - IType annotatedClass = annotatedClasses.next(); - if (! classIsSpecified(annotatedClass.getFullyQualifiedName('.'))) { - addImpliedClassRef(annotatedClass.getFullyQualifiedName('.')); + while (annotatedClassNames.hasNext()) { + String annotatedClassName = annotatedClassNames.next(); + if ( ! classIsSpecified(annotatedClassName)) { + addImpliedClassRef(annotatedClassName); } } } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourceNode.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourceNode.java index 8dd08a8f71..f0fb9e4117 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourceNode.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourceNode.java @@ -19,12 +19,18 @@ import org.eclipse.jpt.utility.internal.model.AbstractModel; import org.eclipse.jpt.utility.internal.model.CallbackChangeSupport; import org.eclipse.jpt.utility.internal.model.ChangeSupport; +/** + * resource containment hierarchy + */ public abstract class AbstractJavaResourceNode extends AbstractModel implements JavaResourceNode, CallbackChangeSupport.Source { private final JavaResourceNode parent; + + // ********** construction ********** + protected AbstractJavaResourceNode(JavaResourceNode parent) { super(); this.checkParent(parent); @@ -56,17 +62,31 @@ public abstract class AbstractJavaResourceNode return new CallbackChangeSupport(this); } - public JavaResourceNode getParent() { - return this.parent; - } + + // ********** JavaResourceNode implementation ********** public JpaCompilationUnit getJpaCompilationUnit() { return this.parent.getJpaCompilationUnit(); } + public JavaResourceModel getResourceModel() { + return this.getJpaCompilationUnit().getResourceModel(); + } + + + // ********** CallbackChangeSupport.Source implementation ********** - // **************** JavaResource implementation **************************** + public void aspectChanged(String aspectName) { + this.getJpaCompilationUnit().resourceChanged(); + } + + + // ********** convenience methods ********** + protected JavaResourceNode getParent() { + return this.parent; + } + public JpaAnnotationProvider getAnnotationProvider() { return this.getJpaCompilationUnit().getAnnotationProvider(); } @@ -79,15 +99,4 @@ public abstract class AbstractJavaResourceNode return this.getJpaCompilationUnit().getAnnotationEditFormatter(); } - public JavaResourceModel getResourceModel() { - return this.getJpaCompilationUnit().getResourceModel(); - } - - public String displayString() { - return toString(); - } - - public void aspectChanged(String aspectName) { - this.getJpaCompilationUnit().resourceChanged(); - } } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourcePersistentMember.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourcePersistentMember.java index d1d2f9a4b4..34fe50aa5e 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourcePersistentMember.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/AbstractJavaResourcePersistentMember.java @@ -13,9 +13,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.ListIterator; -import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.NormalAnnotation; @@ -29,9 +29,11 @@ import org.eclipse.jpt.core.resource.java.JavaResourcePersistentMember; import org.eclipse.jpt.core.resource.java.NestableAnnotation; import org.eclipse.jpt.core.utility.TextRange; import org.eclipse.jpt.core.utility.jdt.Member; +import org.eclipse.jpt.utility.MethodSignature; import org.eclipse.jpt.utility.internal.CollectionTools; import org.eclipse.jpt.utility.internal.iterators.CloneIterator; import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator; +import org.eclipse.jpt.utility.internal.iterators.FilteringIterator; import org.eclipse.jpt.utility.internal.iterators.SingleElementListIterator; public abstract class AbstractJavaResourcePersistentMember<E extends Member> @@ -60,34 +62,15 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } public void initialize(CompilationUnit astRoot) { - getMember().getBodyDeclaration(astRoot).accept(initializeAnnotationVisitor(astRoot)); - this.persistable = calculatePersistability(astRoot); + getMember().getBodyDeclaration(astRoot).accept(this.buildInitialAnnotationVisitor(astRoot)); + this.persistable = buildPersistable(astRoot); } - - protected ASTVisitor initializeAnnotationVisitor(final CompilationUnit astRoot) { - return new ASTVisitor() { - @Override - public boolean visit(SingleMemberAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - - @Override - public boolean visit(NormalAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - + + protected ASTVisitor buildInitialAnnotationVisitor(CompilationUnit astRoot) { + return new LocalASTVisitor(astRoot, this.getMember().getBodyDeclaration(astRoot)) { @Override - public boolean visit(MarkerAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - - private boolean visit(org.eclipse.jdt.core.dom.Annotation node) { - if (node.getParent() != getMember().getBodyDeclaration(astRoot)) { - //we don't want to look at annotations for child members, only this member - return false; - } - addInitialAnnotation(node, astRoot); - return false; + protected void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node) { + AbstractJavaResourcePersistentMember.this.addInitialAnnotation(node, this.astRoot); } }; } @@ -131,7 +114,10 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> protected abstract boolean isPossibleMappingAnnotation(String annotationName); - protected abstract boolean calculatePersistability(CompilationUnit astRoot); + protected boolean buildPersistable(CompilationUnit astRoot) { + return this.getMember().isPersistable(astRoot); + } + public Annotation getAnnotation(String annotationName) { for (Iterator<Annotation> i = annotations(); i.hasNext(); ) { @@ -202,11 +188,11 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } @SuppressWarnings("unchecked") - protected ContainerAnnotation<NestableAnnotation> containerAnnotation(String containerAnnotationName) { + protected ContainerAnnotation<NestableAnnotation> getContainerAnnotation(String containerAnnotationName) { return (ContainerAnnotation<NestableAnnotation>) getAnnotation(containerAnnotationName); } - protected NestableAnnotation nestableAnnotation(String nestableAnnotationName) { + protected NestableAnnotation getNestableAnnotation(String nestableAnnotationName) { return (NestableAnnotation) getAnnotation(nestableAnnotationName); } @@ -218,7 +204,7 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> public NestableAnnotation addAnnotation(int index, String nestableAnnotationName, String containerAnnotationName) { NestableAnnotation nestedAnnotation = (NestableAnnotation) getAnnotation(nestableAnnotationName); - ContainerAnnotation<NestableAnnotation> containerAnnotation = containerAnnotation(containerAnnotationName); + ContainerAnnotation<NestableAnnotation> containerAnnotation = getContainerAnnotation(containerAnnotationName); if (containerAnnotation != null) { //ignore any nestableAnnotation and just add to the plural one @@ -243,7 +229,7 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } public void move(int targetIndex, int sourceIndex, String containerAnnotationName) { - move(targetIndex, sourceIndex, containerAnnotation(containerAnnotationName)); + move(targetIndex, sourceIndex, getContainerAnnotation(containerAnnotationName)); } protected void move(int targetIndex, int sourceIndex, ContainerAnnotation<NestableAnnotation> containerAnnotation) { @@ -305,7 +291,7 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } public void removeAnnotation(int index, String nestableAnnotationName, String containerAnnotationName) { - ContainerAnnotation<NestableAnnotation> containerAnnotation = containerAnnotation(containerAnnotationName); + ContainerAnnotation<NestableAnnotation> containerAnnotation = getContainerAnnotation(containerAnnotationName); if (containerAnnotation == null) { Annotation annotation = getAnnotation(nestableAnnotationName); removeAnnotation(annotation); @@ -404,11 +390,11 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> @SuppressWarnings("unchecked") public ListIterator<NestableAnnotation> annotations(String nestableAnnotationName, String containerAnnotationName) { - ContainerAnnotation<NestableAnnotation> containerAnnotation = containerAnnotation(containerAnnotationName); + ContainerAnnotation<NestableAnnotation> containerAnnotation = getContainerAnnotation(containerAnnotationName); if (containerAnnotation != null) { return containerAnnotation.nestedAnnotations(); } - NestableAnnotation nestableAnnotation = nestableAnnotation(nestableAnnotationName); + NestableAnnotation nestableAnnotation = getNestableAnnotation(nestableAnnotationName); if (nestableAnnotation != null) { return new SingleElementListIterator<NestableAnnotation>(nestableAnnotation); } @@ -416,16 +402,16 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } public void updateFromJava(CompilationUnit astRoot) { - updateAnnotations(astRoot); - setPersistable(calculatePersistability(astRoot)); + this.updateAnnotations(astRoot); + this.setPersistable(this.buildPersistable(astRoot)); } public void resolveTypes(CompilationUnit astRoot) { - setPersistable(calculatePersistability(astRoot)); + this.setPersistable(this.buildPersistable(astRoot)); } protected void updateAnnotations(CompilationUnit astRoot) { - getMember().getBodyDeclaration(astRoot).accept(annotationVisitor(astRoot)); + getMember().getBodyDeclaration(astRoot).accept(this.buildUpdateAnnotationVisitor(astRoot)); removeMappingAnnotationsNotInSource(astRoot); removeAnnotationsNotInSource(astRoot); } @@ -446,30 +432,11 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } } - protected ASTVisitor annotationVisitor(final CompilationUnit astRoot) { - return new ASTVisitor() { - @Override - public boolean visit(SingleMemberAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - - @Override - public boolean visit(NormalAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - + protected ASTVisitor buildUpdateAnnotationVisitor(CompilationUnit astRoot) { + return new LocalASTVisitor(astRoot, this.getMember().getBodyDeclaration(astRoot)) { @Override - public boolean visit(MarkerAnnotation node) { - return visit((org.eclipse.jdt.core.dom.Annotation) node); - } - - private boolean visit(org.eclipse.jdt.core.dom.Annotation node) { - if (node.getParent() != getMember().getBodyDeclaration(astRoot)) { - //we don't want to look at annotations for child members, only this member - return false; - } - addOrUpdateAnnotation(node, astRoot); - return false; + protected void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node) { + AbstractJavaResourcePersistentMember.this.addOrUpdateAnnotation(node, this.astRoot); } }; } @@ -503,10 +470,14 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } } - public boolean isFor(IMember iMember) { - return getMember().wraps(iMember); + public boolean isFor(String memberName, int occurrence) { + return this.member.matches(memberName, occurrence); } - + + public boolean isFor(MethodSignature methodSignature, int occurrence) { + return false; + } + public boolean isPersistable() { return this.persistable; } @@ -525,7 +496,7 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> } public TextRange fullTextRange(CompilationUnit astRoot) { - return this.getTextRange(getMember().getBodyDeclaration(astRoot)); + return this.getTextRange(this.getMember().getBodyDeclaration(astRoot)); } public TextRange getTextRange(CompilationUnit astRoot) { @@ -540,4 +511,53 @@ public abstract class AbstractJavaResourcePersistentMember<E extends Member> return (astNode == null) ? null : new ASTNodeTextRange(astNode); } + protected static <T extends JavaResourcePersistentMember> Iterator<T> persistableMembers(Iterator<T> attributes) { + return new FilteringIterator<T, T>(attributes) { + @Override + protected boolean accept(T attribute) { + return attribute.isPersistable(); + } + }; + } + + + // ********** AST visitor ********** + + protected abstract class LocalASTVisitor extends ASTVisitor { + protected final CompilationUnit astRoot; + protected final BodyDeclaration bodyDeclaration; + + protected LocalASTVisitor(CompilationUnit astRoot, BodyDeclaration bodyDeclaration) { + super(); + this.astRoot = astRoot; + this.bodyDeclaration = bodyDeclaration; + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + return visit_(node); + } + + @Override + public boolean visit(NormalAnnotation node) { + return visit_(node); + } + + @Override + public boolean visit(MarkerAnnotation node) { + return visit_(node); + } + + protected boolean visit_(org.eclipse.jdt.core.dom.Annotation node) { + // ignore annotations for child members, only this member + if (node.getParent() == this.bodyDeclaration) { + this.visitChildAnnotation(node); + } + return false; + } + + protected abstract void visitChildAnnotation(org.eclipse.jdt.core.dom.Annotation node); + + } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourceModelImpl.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourceModelImpl.java index 2fed16234b..edef877013 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourceModelImpl.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourceModelImpl.java @@ -24,13 +24,14 @@ import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; import org.eclipse.jpt.utility.CommandExecutorProvider; import org.eclipse.jpt.utility.internal.BitTools; +// TODO we need access to the JPA platform public class JavaResourceModelImpl extends AbstractResourceModel implements JavaResourceModel { private final Collection<ResourceModelListener> resourceModelListeners; - private final JpaCompilationUnit compilationUnitResource; + private final JpaCompilationUnit jpaCompilationUnit; public JavaResourceModelImpl( @@ -39,7 +40,8 @@ public class JavaResourceModelImpl AnnotationEditFormatter annotationEditFormatter) { super(file); this.resourceModelListeners = new ArrayList<ResourceModelListener>(); - this.compilationUnitResource = + // TODO use JPA factory, via the platform + this.jpaCompilationUnit = new JpaCompilationUnitImpl(file, annotationProvider, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter, this); } @@ -47,9 +49,8 @@ public class JavaResourceModelImpl return JAVA_RESOURCE_TYPE; } - @Override - public JpaCompilationUnit getResource() { - return this.compilationUnitResource; + public JpaCompilationUnit getJpaCompilationUnit() { + return this.jpaCompilationUnit; } public void addResourceModelChangeListener(ResourceModelListener listener) { @@ -70,7 +71,7 @@ public class JavaResourceModelImpl } public void resourceChanged() { - if (getResource() == null) { + if (this.jpaCompilationUnit == null) { throw new IllegalStateException("Change events should not be fired during construction"); } for (ResourceModelListener listener : this.resourceModelListeners) { @@ -113,16 +114,21 @@ public class JavaResourceModelImpl } if (delta.getKind() == IJavaElementDelta.REMOVED) { //we get the java notification for removal before we get the resource notification. - //we do not need to handle this event and will get exceptions building an AstRoot if we try. + //we do not need to handle this event and will get exceptions building an astRoot if we try. return; } - if (delta.getElement().equals(this.compilationUnitResource.getCompilationUnit())) { + if (delta.getElement().equals(this.jpaCompilationUnit.getCompilationUnit())) { //TODO possibly hop on the UI thread here so that we know only 1 thread is changing our model - this.compilationUnitResource.updateFromJava(); + this.jpaCompilationUnit.updateFromJava(); } } + public void updateFromResource() { + this.jpaCompilationUnit.updateFromJava(); + } + public void resolveTypes() { - this.compilationUnitResource.resolveTypes(); + this.jpaCompilationUnit.resolveTypes(); } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentAttributeImpl.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentAttributeImpl.java index f788f23d18..b8a57e6296 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentAttributeImpl.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentAttributeImpl.java @@ -11,19 +11,23 @@ package org.eclipse.jpt.core.internal.resource.java; import java.util.Iterator; import java.util.ListIterator; + import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; -import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.Modifier; -import org.eclipse.jpt.core.internal.utility.jdt.JPTTools; +import org.eclipse.jpt.core.internal.utility.jdt.JDTFieldAttribute; +import org.eclipse.jpt.core.internal.utility.jdt.JDTMethodAttribute; import org.eclipse.jpt.core.resource.java.Annotation; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; +import org.eclipse.jpt.core.resource.java.JpaCompilationUnit; import org.eclipse.jpt.core.resource.java.NestableAnnotation; import org.eclipse.jpt.core.utility.jdt.Attribute; +import org.eclipse.jpt.core.utility.jdt.MethodAttribute; +import org.eclipse.jpt.core.utility.jdt.Type; +import org.eclipse.jpt.utility.MethodSignature; import org.eclipse.jpt.utility.internal.CollectionTools; public class JavaResourcePersistentAttributeImpl @@ -41,9 +45,53 @@ public class JavaResourcePersistentAttributeImpl private String qualifiedReferenceEntityElementTypeName; - private boolean public_; + private boolean public_; // 'public' is a reserved word - private boolean final_; + private boolean final_; // 'final' is a reserved word + + /** + * construct field attribute + */ + public static JavaResourcePersistentAttribute newInstance( + JavaResourcePersistentType parent, + Type declaringType, + String name, + int occurrence, + JpaCompilationUnit jpaCompilationUnit, + CompilationUnit astRoot) { + Attribute attribute = new JDTFieldAttribute( + declaringType, + name, + occurrence, + jpaCompilationUnit.getCompilationUnit(), + jpaCompilationUnit.getModifySharedDocumentCommandExecutorProvider(), + jpaCompilationUnit.getAnnotationEditFormatter()); + JavaResourcePersistentAttribute field = new JavaResourcePersistentAttributeImpl(parent, attribute); + field.initialize(astRoot); + return field; + } + + /** + * construct property attribute + */ + public static JavaResourcePersistentAttribute newInstance( + JavaResourcePersistentType parent, + Type declaringType, + MethodSignature signature, + int occurrence, + JpaCompilationUnit jpaCompilationUnit, + CompilationUnit astRoot) { + Attribute attribute = JDTMethodAttribute.newInstance( + declaringType, + signature, + occurrence, + jpaCompilationUnit.getCompilationUnit(), + jpaCompilationUnit.getModifySharedDocumentCommandExecutorProvider(), + jpaCompilationUnit.getAnnotationEditFormatter()); + JavaResourcePersistentAttribute field = new JavaResourcePersistentAttributeImpl(parent, attribute); + field.initialize(astRoot); + return field; + } public JavaResourcePersistentAttributeImpl(JavaResourcePersistentType parent, Attribute attribute){ super(parent, attribute); @@ -91,18 +139,6 @@ public class JavaResourcePersistentAttributeImpl } @Override - protected boolean calculatePersistability(CompilationUnit astRoot) { - IBinding binding = getMember().getBinding(astRoot); - if (binding == null) { - return false; - } - if (isForField()) { - return JPTTools.fieldIsPersistable((IVariableBinding) binding); - } - return JPTTools.methodIsPersistablePropertyGetter((IMethodBinding) binding); - } - - @Override @SuppressWarnings("unchecked") //overriding purely to suppress the warning you get at the class level public ListIterator<NestableAnnotation> annotations(String nestableAnnotationName, String containerAnnotationName) { @@ -123,6 +159,11 @@ public class JavaResourcePersistentAttributeImpl return super.annotations(); } + @Override + public boolean isFor(MethodSignature signature, int occurrence) { + return ((MethodAttribute) this.getMember()).matches(signature, occurrence); + } + // ******** JavaPersistentAttributeResource implementation ******** public boolean isForField() { @@ -248,7 +289,7 @@ public class JavaResourcePersistentAttributeImpl } protected boolean typeIsBasic(CompilationUnit astRoot) { - return typeIsBasic(getMember().getTypeBinding(astRoot), astRoot.getAST()); + return typeIsBasic(this.getMember().getTypeBinding(astRoot), astRoot.getAST()); } protected boolean isFinal(CompilationUnit astRoot) { @@ -262,22 +303,22 @@ public class JavaResourcePersistentAttributeImpl } protected String qualifiedReferenceEntityTypeName(CompilationUnit astRoot) { - ITypeBinding typeBinding = getMember().getTypeBinding(astRoot); - if (typeBinding == null) { - return null; - } - return buildReferenceEntityTypeName(typeBinding); + ITypeBinding typeBinding = this.getMember().getTypeBinding(astRoot); + return (typeBinding == null) ? null : buildReferenceEntityTypeName(typeBinding); } public static String buildReferenceEntityTypeName(ITypeBinding typeBinding) { - if (typeBinding != null && !typeBinding.isArray()) { // arrays cannot be entities - return typeBinding.getTypeDeclaration().getQualifiedName(); + if (typeBinding == null) { + return null; + } + if (typeBinding.isArray()) { + return null; // arrays cannot be entities } - return null; + return typeBinding.getTypeDeclaration().getQualifiedName(); } protected String qualifiedReferenceEntityElementTypeName(CompilationUnit astRoot) { - ITypeBinding typeBinding = getMember().getTypeBinding(astRoot); + ITypeBinding typeBinding = this.getMember().getTypeBinding(astRoot); if (typeBinding == null) { return null; } @@ -293,8 +334,8 @@ public class JavaResourcePersistentAttributeImpl protected boolean typeIsContainer(CompilationUnit astRoot) { - String typeName = buildReferenceEntityTypeName(getMember().getTypeBinding(astRoot)); - return typeName == null ? false : typeNamedIsContainer(typeName); + String typeName = buildReferenceEntityTypeName(this.getMember().getTypeBinding(astRoot)); + return (typeName == null) ? false : typeNamedIsContainer(typeName); } /** @@ -313,11 +354,8 @@ public class JavaResourcePersistentAttributeImpl }; protected String qualifiedTypeName(CompilationUnit astRoot) { - ITypeBinding typeBinding = getMember().getTypeBinding(astRoot); - if (typeBinding == null) { - return null; - } - return typeBinding.getQualifiedName(); + ITypeBinding typeBinding = this.getMember().getTypeBinding(astRoot); + return (typeBinding == null) ? null : typeBinding.getQualifiedName(); } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentTypeImpl.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentTypeImpl.java index fd4e63e5e7..5f8d4272db 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentTypeImpl.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JavaResourcePersistentTypeImpl.java @@ -9,91 +9,154 @@ ******************************************************************************/ package org.eclipse.jpt.core.internal.resource.java; -import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Vector; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jpt.core.internal.utility.jdt.JDTFieldAttribute; -import org.eclipse.jpt.core.internal.utility.jdt.JDTMethodAttribute; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jpt.core.internal.utility.jdt.JDTTools; import org.eclipse.jpt.core.internal.utility.jdt.JDTType; -import org.eclipse.jpt.core.internal.utility.jdt.JPTTools; import org.eclipse.jpt.core.resource.java.AccessType; import org.eclipse.jpt.core.resource.java.Annotation; -import org.eclipse.jpt.core.resource.java.JavaResourceNode; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute; import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; +import org.eclipse.jpt.core.resource.java.JpaCompilationUnit; import org.eclipse.jpt.core.resource.java.NestableAnnotation; -import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; -import org.eclipse.jpt.core.utility.jdt.Attribute; import org.eclipse.jpt.core.utility.jdt.Type; -import org.eclipse.jpt.utility.CommandExecutorProvider; +import org.eclipse.jpt.utility.MethodSignature; import org.eclipse.jpt.utility.internal.CollectionTools; +import org.eclipse.jpt.utility.internal.Counter; import org.eclipse.jpt.utility.internal.iterators.CloneIterator; +import org.eclipse.jpt.utility.internal.iterators.CompositeIterator; import org.eclipse.jpt.utility.internal.iterators.FilteringIterator; public class JavaResourcePersistentTypeImpl extends AbstractJavaResourcePersistentMember<Type> implements JavaResourcePersistentType -{ +{ + private String qualifiedName; + + private String name; + + private String superClassQualifiedName; + + private boolean abstract_; // 'abstract' is a reserved word + /** - * store all member types including those that aren't persistable so we can include validation errors. + * store all member types including those that aren't persistable so we can + * generate validation errors */ - private final Collection<JavaResourcePersistentType> nestedTypes; - - private final Collection<JavaResourcePersistentAttribute> attributes; - + private final Vector<JavaResourcePersistentType> nestedTypes; + + private final Vector<JavaResourcePersistentAttribute> fields; + + private final Vector<JavaResourcePersistentAttribute> methods; + private AccessType accessType; - - private String superClassQualifiedName; - - private String qualifiedName; - - private String name; - - private boolean isAbstract; - - public JavaResourcePersistentTypeImpl(JavaResourceNode parent, Type type){ - super(parent, type); - this.nestedTypes = new ArrayList<JavaResourcePersistentType>(); - this.attributes = new ArrayList<JavaResourcePersistentAttribute>(); + + + // ********** construction ********** + + /** + * build top-level persistent type + */ + // TODO use JPA factory + public static JavaResourcePersistentType newInstance( + JpaCompilationUnit jpaCompilationUnit, + TypeDeclaration typeDeclaration, + CompilationUnit astRoot) { + Type type = new JDTType( + typeDeclaration, + jpaCompilationUnit.getCompilationUnit(), + jpaCompilationUnit.getModifySharedDocumentCommandExecutorProvider(), + jpaCompilationUnit.getAnnotationEditFormatter()); + JavaResourcePersistentType jrpt = new JavaResourcePersistentTypeImpl(jpaCompilationUnit, type); + jrpt.initialize(astRoot); + return jrpt; + } + + /** + * build nested persistent type + */ + // TODO use JPA factory + protected static JavaResourcePersistentType newInstance( + JpaCompilationUnit jpaCompilationUnit, + Type declaringType, + TypeDeclaration typeDeclaration, + int occurrence, + CompilationUnit astRoot) { + Type type = new JDTType( + declaringType, + typeDeclaration, + occurrence, + jpaCompilationUnit.getCompilationUnit(), + jpaCompilationUnit.getModifySharedDocumentCommandExecutorProvider(), + jpaCompilationUnit.getAnnotationEditFormatter()); + JavaResourcePersistentType jrpt = new JavaResourcePersistentTypeImpl(jpaCompilationUnit, type); + jrpt.initialize(astRoot); + return jrpt; + } + + public JavaResourcePersistentTypeImpl(JpaCompilationUnit jpaCompilationUnit, Type type) { + super(jpaCompilationUnit, type); + this.nestedTypes = new Vector<JavaResourcePersistentType>(); + this.fields = new Vector<JavaResourcePersistentAttribute>(); + this.methods = new Vector<JavaResourcePersistentAttribute>(); } @Override public void initialize(CompilationUnit astRoot) { super.initialize(astRoot); - this.qualifiedName = this.qualifiedName(astRoot); - this.name = this.name(astRoot); + this.qualifiedName = this.buildQualifiedName(astRoot); + this.name = this.buildName(astRoot); + this.superClassQualifiedName = this.buildSuperClassQualifiedName(astRoot); + this.abstract_ = this.buildAbstract(astRoot); this.initializeNestedTypes(astRoot); - this.initializePersistentProperties(astRoot); - this.accessType = this.calculateAccessType(); - this.superClassQualifiedName = this.superClassQualifiedName(astRoot); - this.isAbstract = this.isAbstract(astRoot); + this.initializeFields(astRoot); + this.initializeMethods(astRoot); + this.accessType = this.buildAccessType(); } - + protected void initializeNestedTypes(CompilationUnit astRoot) { - for (IType declaredType : getMember().jdtTypes()) { - this.nestedTypes.add(buildJavaResourcePersistentType(declaredType, astRoot)); + CounterMap counters = new CounterMap(); + for (TypeDeclaration td : this.getMember().getTypes(astRoot)) { + String tdName = td.getName().getFullyQualifiedName(); + int occurrence = counters.increment(tdName); + this.nestedTypes.add(this.buildNestedType(td, occurrence, astRoot)); } } - - protected void initializePersistentProperties(CompilationUnit astRoot) { - for (IField field : getMember().jdtFields()) { - this.attributes.add(createJavaPersistentAttribute(field, astRoot)); + + protected void initializeFields(CompilationUnit astRoot) { + CounterMap counters = new CounterMap(); + for (FieldDeclaration fieldDeclaration : this.getMember().getFields(astRoot)) { + for (VariableDeclarationFragment fragment : fragments(fieldDeclaration)) { + String fieldName = fragment.getName().getFullyQualifiedName(); + int occurrence = counters.increment(fieldName); + this.fields.add(this.buildField(fieldName, occurrence, astRoot)); + } } - for (IMethod method : getMember().jdtMethods()) { - this.attributes.add(createJavaPersistentAttribute(method, astRoot)); + } + + protected void initializeMethods(CompilationUnit astRoot) { + CounterMap counters = new CounterMap(); + for (MethodDeclaration methodDeclaration : this.getMember().getMethods(astRoot)) { + MethodSignature signature = JDTTools.buildMethodSignature(methodDeclaration); + int occurrence = counters.increment(signature); + this.methods.add(this.buildMethod(signature, occurrence, astRoot)); } } - - // ******** AbstractJavaPersistentResource implementation ******** + + + // ********** AbstractJavaResourcePersistentMember implementation ********** @Override protected Annotation buildMappingAnnotation(String mappingAnnotationName) { @@ -131,12 +194,6 @@ public class JavaResourcePersistentTypeImpl } @Override - protected boolean calculatePersistability(CompilationUnit astRoot) { - return JPTTools.typeIsPersistable(getMember().getBinding(astRoot)); - } - - - @Override @SuppressWarnings("unchecked") //overriding purely to suppress the warning you get at the class level public ListIterator<NestableAnnotation> annotations(String nestableAnnotationName, String containerAnnotationName) { @@ -157,290 +214,388 @@ public class JavaResourcePersistentTypeImpl return super.annotations(); } - - // ******** JavaPersistentTypeResource implementation ******** + @Override + public void resolveTypes(CompilationUnit astRoot) { + super.resolveTypes(astRoot); + + this.setSuperClassQualifiedName(this.buildSuperClassQualifiedName(astRoot)); + + for (Iterator<JavaResourcePersistentAttribute> stream = this.fields_(); stream.hasNext(); ) { + stream.next().resolveTypes(astRoot); + } + + // a new type can trigger a method parameter type to be a resolved, + // fully-qualified name, so we need to rebuild our list of methods: + // "setFoo(Foo)" is not the same as "setFoo(com.bar.Foo)" + // and, vice-versa, a removed type can "unresolve" a parameter type + this.updateMethods(astRoot); + + for (Iterator<JavaResourcePersistentAttribute> stream = this.methods_(); stream.hasNext(); ) { + stream.next().resolveTypes(astRoot); + } + for (Iterator<JavaResourcePersistentType> stream = this.nestedTypes_(); stream.hasNext(); ) { + stream.next().resolveTypes(astRoot); + } + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } + + + // ******** JavaResourcePersistentType implementation ******** + public JavaResourcePersistentType getJavaPersistentTypeResource(String fullyQualifiedTypeName) { - if (getQualifiedName().equals(fullyQualifiedTypeName)) { + // TODO not sure why a null name is coming through here... ~bjv +// if (fullyQualifiedTypeName.equals(this.getQualifiedName())) { + if (this.getQualifiedName().equals(fullyQualifiedTypeName)) { return this; } - for (JavaResourcePersistentType jptr : CollectionTools.iterable(nestedTypes())) { - if (jptr.getQualifiedName().equals(fullyQualifiedTypeName)) { - return jptr; + for (Iterator<JavaResourcePersistentType> stream = this.nestedTypes(); stream.hasNext(); ) { + JavaResourcePersistentType jrpt = stream.next(); + // recurse + JavaResourcePersistentType nestedJRPT = jrpt.getJavaPersistentTypeResource(fullyQualifiedTypeName); + if (nestedJRPT != null) { + return nestedJRPT; } } return null; } + /** + * check only persistable attributes + */ + public boolean hasAnyAttributeAnnotations() { + for (Iterator<JavaResourcePersistentAttribute> stream = this.attributes(); stream.hasNext(); ) { + if (stream.next().hasAnyAnnotation()) { + return true; + } + } + return false; + } + + + // ********** nested types ********** + + /** + * return only persistable nested types + */ public Iterator<JavaResourcePersistentType> nestedTypes() { //TODO since we are filtering how do we handle the case where a type becomes persistable? //what kind of change notificiation for that case? - return new FilteringIterator<JavaResourcePersistentType, JavaResourcePersistentType>(new CloneIterator<JavaResourcePersistentType>(this.nestedTypes)) { + return new FilteringIterator<JavaResourcePersistentType, JavaResourcePersistentType>(this.nestedTypes_()) { @Override - protected boolean accept(JavaResourcePersistentType o) { - return o.isPersistable(); + protected boolean accept(JavaResourcePersistentType jrpt) { + return jrpt.isPersistable(); } }; } - - protected JavaResourcePersistentType nestedTypeFor(IType type) { - for (JavaResourcePersistentType nestedType : this.nestedTypes) { - if (nestedType.isFor(type)) { - return nestedType; - } - } - return null; - } - - protected JavaResourcePersistentType addNestedType(IType nestedType, CompilationUnit astRoot) { - JavaResourcePersistentType persistentType = buildJavaResourcePersistentType(nestedType, astRoot); - addNestedType(persistentType); - return persistentType; + + /** + * *all* nested types + */ + protected Iterator<JavaResourcePersistentType> nestedTypes_() { + return new CloneIterator<JavaResourcePersistentType>(this.nestedTypes); } protected void addNestedType(JavaResourcePersistentType nestedType) { - addItemToCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); + this.addItemToCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); } - + protected void removeNestedType(JavaResourcePersistentType nestedType) { - removeItemFromCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); + this.removeItemFromCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); } - - protected JavaResourcePersistentType buildJavaResourcePersistentType(IType nestedType, CompilationUnit astRoot) { - return buildJavaResourcePersistentType(this, nestedType, getModifySharedDocumentCommandExecutorProvider(), getAnnotationEditFormatter(), astRoot); - } - - public static JavaResourcePersistentType buildJavaResourcePersistentType( - JavaResourceNode parent, - IType nestedType, - CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, - AnnotationEditFormatter annotationEditFormatter, - CompilationUnit astRoot) { - - Type type = new JDTType(nestedType, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); - JavaResourcePersistentTypeImpl javaPersistentType = new JavaResourcePersistentTypeImpl(parent, type); - javaPersistentType.initialize(astRoot); - return javaPersistentType; + + protected void removeNestedTypes(Collection<JavaResourcePersistentType> remove) { + this.removeItemsFromCollection(remove, this.nestedTypes, NESTED_TYPES_COLLECTION); } - - public Iterator<JavaResourcePersistentAttribute> attributes() { - //TODO since we are filtering how do we handle the case where an attribute becomes persistable? - //what kind of change notificiation for that case? - return new FilteringIterator<JavaResourcePersistentAttribute, JavaResourcePersistentAttribute>(new CloneIterator<JavaResourcePersistentAttribute>(this.attributes)) { - @Override - protected boolean accept(JavaResourcePersistentAttribute o) { - return o.isPersistable(); + + protected JavaResourcePersistentType getNestedType(String typeName, int occurrence) { + for (Iterator<JavaResourcePersistentType> stream = this.nestedTypes_(); stream.hasNext(); ) { + JavaResourcePersistentType nestedType = stream.next(); + if (nestedType.isFor(typeName, occurrence)) { + return nestedType; } - }; + } + return null; } - - public Iterator<JavaResourcePersistentAttribute> fields() { - return new FilteringIterator<JavaResourcePersistentAttribute, JavaResourcePersistentAttribute>(attributes()) { - @Override - protected boolean accept(JavaResourcePersistentAttribute o) { - return o.isForField(); - } - }; + + + // ********** attributes ********** + + /** + * return only persistable attributes + */ + // TODO since we are filtering, how do we handle the case where an attribute becomes persistable? + // what kind of change notification for that case? + public Iterator<JavaResourcePersistentAttribute> attributes() { + return persistableMembers(this.attributes_()); } - - public Iterator<JavaResourcePersistentAttribute> properties() { - return new FilteringIterator<JavaResourcePersistentAttribute, JavaResourcePersistentAttribute>(attributes()) { - @Override - protected boolean accept(JavaResourcePersistentAttribute o) { - return o.isForProperty(); - } - }; + + /** + * *all* fields and methods + */ + @SuppressWarnings("unchecked") + protected Iterator<JavaResourcePersistentAttribute> attributes_() { + return new CompositeIterator<JavaResourcePersistentAttribute>(this.fields_(), this.methods_()); } - protected JavaResourcePersistentAttribute addAttribute(IMember jdtMember, CompilationUnit astRoot) { - JavaResourcePersistentAttribute persistentAttribute = createJavaPersistentAttribute(jdtMember, astRoot); - addAttribute(persistentAttribute); - return persistentAttribute; + + // ********** fields ********** + + /** + * return only persistable fields + */ + public Iterator<JavaResourcePersistentAttribute> fields() { + return persistableMembers(this.fields_()); } - protected void addAttribute(JavaResourcePersistentAttribute attribute) { - addItemToCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION); + /** + * *all* fields + */ + protected Iterator<JavaResourcePersistentAttribute> fields_() { + return new CloneIterator<JavaResourcePersistentAttribute>(this.fields); } - protected JavaResourcePersistentAttribute createJavaPersistentAttribute(IMember member, CompilationUnit astRoot) { - Attribute attribute = null; - if (member instanceof IField) { - attribute = new JDTFieldAttribute((IField) member, this.getModifySharedDocumentCommandExecutorProvider(), this.getAnnotationEditFormatter()); - } - else if (member instanceof IMethod) { - attribute = new JDTMethodAttribute((IMethod) member, this.getModifySharedDocumentCommandExecutorProvider(), this.getAnnotationEditFormatter()); - } - else { - throw new IllegalArgumentException(); - } - JavaResourcePersistentAttribute javaPersistentAttribute = new JavaResourcePersistentAttributeImpl(this, attribute); - javaPersistentAttribute.initialize(astRoot); - return javaPersistentAttribute; + protected void addField(JavaResourcePersistentAttribute attribute) { + this.addItemToCollection(attribute, this.fields, ATTRIBUTES_COLLECTION); } - - protected void removeAttribute(JavaResourcePersistentAttribute attribute) { - removeItemFromCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION); + + protected void removeField(JavaResourcePersistentAttribute attribute) { + this.removeItemFromCollection(attribute, this.fields, ATTRIBUTES_COLLECTION); } - - protected JavaResourcePersistentAttribute attributeFor(IMember member) { - for (JavaResourcePersistentAttribute persistentAttribute : this.attributes) { - if (persistentAttribute.isFor(member)) { - return persistentAttribute; + + protected void removeFields(Collection<JavaResourcePersistentAttribute> remove) { + this.removeItemsFromCollection(remove, this.fields, ATTRIBUTES_COLLECTION); + } + + protected JavaResourcePersistentAttribute getField(String fieldName, int occurrence) { + for (Iterator<JavaResourcePersistentAttribute> stream = this.fields_(); stream.hasNext(); ) { + JavaResourcePersistentAttribute field = stream.next(); + if (field.isFor(fieldName, occurrence)) { + return field; } } return null; } - - public AccessType getAccess() { - return this.accessType; + + + // ********** methods ********** + + /** + * return only persistable properties + */ + public Iterator<JavaResourcePersistentAttribute> properties() { + return persistableMembers(this.methods_()); } - - //seems we could have a public changeAccess() api which would - //move all annotations from fields to their corresponding methods or vice versa - //though of course it's more complicated than that since what if the - //corresponding field/method does not exist? - //making this internal since it should only be set based on changes in the source, the - //context model should not need to set this - protected void setAccess(AccessType newAccess) { - AccessType oldAccess = this.accessType; - this.accessType = newAccess; - firePropertyChanged(ACCESS_PROPERTY, oldAccess, newAccess); + + /** + * *all* methods + */ + protected Iterator<JavaResourcePersistentAttribute> methods_() { + return new CloneIterator<JavaResourcePersistentAttribute>(this.methods); } - public String getSuperClassQualifiedName() { - return this.superClassQualifiedName; + protected void addMethod(JavaResourcePersistentAttribute attribute) { + this.addItemToCollection(attribute, this.methods, ATTRIBUTES_COLLECTION); } - - private void setSuperClassQualifiedName(String newSuperClassQualifiedName) { - String oldSuperClassQualifiedName = this.superClassQualifiedName; - this.superClassQualifiedName = newSuperClassQualifiedName; - firePropertyChanged(SUPER_CLASS_QUALIFIED_NAME_PROPERTY, oldSuperClassQualifiedName, newSuperClassQualifiedName); + + protected void removeMethod(JavaResourcePersistentAttribute attribute) { + this.removeItemFromCollection(attribute, this.methods, ATTRIBUTES_COLLECTION); } + protected void removeMethods(Collection<JavaResourcePersistentAttribute> remove) { + this.removeItemsFromCollection(remove, this.methods, ATTRIBUTES_COLLECTION); + } + + protected JavaResourcePersistentAttribute getMethod(MethodSignature signature, int occurrence) { + for (Iterator<JavaResourcePersistentAttribute> stream = this.methods_(); stream.hasNext(); ) { + JavaResourcePersistentAttribute method = stream.next(); + if (method.isFor(signature, occurrence)) { + return method; + } + } + return null; + } + + + // ********** simple instance variables ********** + public String getQualifiedName() { return this.qualifiedName; } - - protected void setQualifiedName(String newQualifiedName) { - String oldQualifiedName = this.qualifiedName; - this.qualifiedName = newQualifiedName; - firePropertyChanged(QUALIFIED_NAME_PROPERTY, oldQualifiedName, newQualifiedName); + + protected void setQualifiedName(String qualifiedName) { + String old = this.qualifiedName; + this.qualifiedName = qualifiedName; + this.firePropertyChanged(QUALIFIED_NAME_PROPERTY, old, qualifiedName); } - + public String getName() { return this.name; } - - protected void setName(String newName) { - String oldName = this.name; - this.name = newName; - firePropertyChanged(NAME_PROPERTY, oldName, newName); + + protected void setName(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); } - - public boolean isAbstract() { - return this.isAbstract; + + public String getSuperClassQualifiedName() { + return this.superClassQualifiedName; } - - protected void setAbstract(boolean newAbstract) { - boolean oldAbstract = this.isAbstract; - this.isAbstract = newAbstract; - firePropertyChanged(ABSTRACT_PROPERTY, oldAbstract, newAbstract); + + protected void setSuperClassQualifiedName(String superClassQualifiedName) { + String old = this.superClassQualifiedName; + this.superClassQualifiedName = superClassQualifiedName; + this.firePropertyChanged(SUPER_CLASS_QUALIFIED_NAME_PROPERTY, old, superClassQualifiedName); } - - @Override - public void updateFromJava(CompilationUnit astRoot) { - super.updateFromJava(astRoot); - this.setQualifiedName(this.qualifiedName(astRoot)); - this.setName(this.name(astRoot)); - this.updateNestedTypes(astRoot); - this.updatePersistentAttributes(astRoot); - this.setAccess(this.calculateAccessType()); - this.setSuperClassQualifiedName(this.superClassQualifiedName(astRoot)); - this.setAbstract(isAbstract(astRoot)); + + public boolean isAbstract() { + return this.abstract_; } - - @Override - public void resolveTypes(CompilationUnit astRoot) { - super.resolveTypes(astRoot); - this.setSuperClassQualifiedName(this.superClassQualifiedName(astRoot)); - for (JavaResourcePersistentAttribute attribute : this.attributes) { - attribute.resolveTypes(astRoot); - } - for (JavaResourcePersistentType persistentType : this.nestedTypes) { - persistentType.resolveTypes(astRoot); - } + protected void setAbstract(boolean abstract_) { + boolean old = this.abstract_; + this.abstract_ = abstract_; + this.firePropertyChanged(ABSTRACT_PROPERTY, old, abstract_); } - - protected boolean isAbstract(CompilationUnit astRoot) { - return JPTTools.typeIsAbstract(getMember().getBinding(astRoot)); + + public AccessType getAccess() { + return this.accessType; } - protected String qualifiedName(CompilationUnit astRoot) { - return getMember().getBinding(astRoot).getQualifiedName(); + // TODO + //seems we could have a public changeAccess() api which would + //move all annotations from fields to their corresponding methods or vice versa + //though of course it's more complicated than that since what if the + //corresponding field/method does not exist? + //making this internal since it should only be set based on changes in the source, the + //context model should not need to set this + protected void setAccess(AccessType accessType) { + AccessType old = this.accessType; + this.accessType = accessType; + this.firePropertyChanged(ACCESS_PROPERTY, old, accessType); } - - protected String name(CompilationUnit astRoot) { - return getMember().getBinding(astRoot).getName(); + + + // ********** update from Java ********** + + @Override + public void updateFromJava(CompilationUnit astRoot) { + super.updateFromJava(astRoot); + this.setQualifiedName(this.buildQualifiedName(astRoot)); + this.setName(this.buildName(astRoot)); + this.setSuperClassQualifiedName(this.buildSuperClassQualifiedName(astRoot)); + this.setAbstract(this.buildAbstract(astRoot)); + this.updateNestedTypes(astRoot); + this.updateFields(astRoot); + this.updateMethods(astRoot); + this.setAccess(this.buildAccessType()); } - + protected void updateNestedTypes(CompilationUnit astRoot) { - IType[] declaredTypes = getMember().jdtTypes(); - - List<JavaResourcePersistentType> nestedTypesToRemove = new ArrayList<JavaResourcePersistentType>(this.nestedTypes); - for (IType declaredType : declaredTypes) { - JavaResourcePersistentType nestedType = nestedTypeFor(declaredType); + CounterMap counters = new CounterMap(); + @SuppressWarnings("unchecked") + Vector<JavaResourcePersistentType> nestedTypesToRemove = (Vector<JavaResourcePersistentType>) this.nestedTypes.clone(); + for (TypeDeclaration typeDeclaration : this.getMember().getTypes(astRoot)) { + String tdName = typeDeclaration.getName().getFullyQualifiedName(); + int occurrence = counters.increment(tdName); + + JavaResourcePersistentType nestedType = this.getNestedType(tdName, occurrence); if (nestedType == null) { - nestedType = addNestedType(declaredType, astRoot); - } - else { + this.addNestedType(this.buildNestedType(typeDeclaration, occurrence, astRoot)); + } else { nestedTypesToRemove.remove(nestedType); + nestedType.updateFromJava(astRoot); } - nestedType.updateFromJava(astRoot); } - for (JavaResourcePersistentType nestedType : nestedTypesToRemove) { - removeNestedType(nestedType); + this.removeNestedTypes(nestedTypesToRemove); + } + + protected void updateFields(CompilationUnit astRoot) { + CounterMap counters = new CounterMap(); + @SuppressWarnings("unchecked") + Vector<JavaResourcePersistentAttribute> fieldsToRemove = (Vector<JavaResourcePersistentAttribute>) this.fields.clone(); + for (FieldDeclaration fieldDeclaration : this.getMember().getFields(astRoot)) { + for (VariableDeclarationFragment fragment : fragments(fieldDeclaration)) { + String fieldName = fragment.getName().getFullyQualifiedName(); + int occurrence = counters.increment(fieldName); + + JavaResourcePersistentAttribute field = this.getField(fieldName, occurrence); + if (field == null) { + this.addField(this.buildField(fieldName, occurrence, astRoot)); + } else { + fieldsToRemove.remove(field); + field.updateFromJava(astRoot); + } + } } + this.removeFields(fieldsToRemove); } - - protected void updatePersistentAttributes(CompilationUnit astRoot) { - List<JavaResourcePersistentAttribute> persistentAttributesToRemove = new ArrayList<JavaResourcePersistentAttribute>(this.attributes); - updatePersistentFields(astRoot, persistentAttributesToRemove); - updatePersistentProperties(astRoot, persistentAttributesToRemove); - for (JavaResourcePersistentAttribute persistentAttribute : persistentAttributesToRemove) { - removeAttribute(persistentAttribute); + + protected void updateMethods(CompilationUnit astRoot) { + CounterMap counters = new CounterMap(); + @SuppressWarnings("unchecked") + Vector<JavaResourcePersistentAttribute> methodsToRemove = (Vector<JavaResourcePersistentAttribute>) this.methods.clone(); + for (MethodDeclaration methodDeclaration : this.getMember().getMethods(astRoot)) { + MethodSignature signature = JDTTools.buildMethodSignature(methodDeclaration); + int occurrence = counters.increment(signature); + + JavaResourcePersistentAttribute method = this.getMethod(signature, occurrence); + if (method == null) { + this.addMethod(this.buildMethod(signature, occurrence, astRoot)); + } else { + methodsToRemove.remove(method); + method.updateFromJava(astRoot); + } } + this.removeMethods(methodsToRemove); } - - protected void updatePersistentFields(CompilationUnit astRoot, List<JavaResourcePersistentAttribute> persistentAttributesToRemove) { - updatePersistentAttributes(astRoot, persistentAttributesToRemove, getMember().jdtFields()); + + + // ********** building state from AST ********** + + protected String buildQualifiedName(CompilationUnit astRoot) { + return this.getMember().getBinding(astRoot).getQualifiedName(); } - protected void updatePersistentProperties(CompilationUnit astRoot, List<JavaResourcePersistentAttribute> persistentAttributesToRemove) { - updatePersistentAttributes(astRoot, persistentAttributesToRemove, getMember().jdtMethods()); + protected String buildName(CompilationUnit astRoot) { + return this.getMember().getBinding(astRoot).getName(); } - protected void updatePersistentAttributes(CompilationUnit astRoot, List<JavaResourcePersistentAttribute> persistentAttributesToRemove, IMember[] members) { - for (IMember member : members) { - JavaResourcePersistentAttribute persistentAttribute = attributeFor(member); - if (persistentAttribute == null) { - persistentAttribute = addAttribute(member, astRoot); - } - else { - persistentAttributesToRemove.remove(persistentAttribute); - } - persistentAttribute.updateFromJava(astRoot); + protected String buildSuperClassQualifiedName(CompilationUnit astRoot) { + ITypeBinding typeBinding = this.getMember().getBinding(astRoot); + if (typeBinding == null) { + return null; } - } - - public boolean hasAnyAttributeAnnotations() { - for (JavaResourcePersistentAttribute attribute : CollectionTools.iterable(attributes())) { - if (attribute.hasAnyAnnotation()) { - return true; - } + ITypeBinding superClassTypeBinding = typeBinding.getSuperclass(); + if (superClassTypeBinding == null) { + return null; } - return false; + return superClassTypeBinding.getQualifiedName(); } - + + protected boolean buildAbstract(CompilationUnit astRoot) { + return Modifier.isAbstract(this.getMember().getBinding(astRoot).getModifiers()); + } + + // TODO use JPA factory + protected JavaResourcePersistentType buildNestedType(TypeDeclaration nestedTypeDeclaration, int occurrence, CompilationUnit astRoot) { + return newInstance(this.getJpaCompilationUnit(), this.getMember(), nestedTypeDeclaration, occurrence, astRoot); + } + + // TODO use JPA factory + protected JavaResourcePersistentAttribute buildField(String fieldName, int occurrence, CompilationUnit astRoot) { + return JavaResourcePersistentAttributeImpl.newInstance(this, this.getMember(), fieldName, occurrence, this.getJpaCompilationUnit(), astRoot); + } + + // TODO use JPA factory + protected JavaResourcePersistentAttribute buildMethod(MethodSignature signature, int occurrence, CompilationUnit astRoot) { + return JavaResourcePersistentAttributeImpl.newInstance(this, this.getMember(), signature, occurrence, this.getJpaCompilationUnit(), astRoot); + } + /** * Return the AccessType currently implied by the Java source code: * - if only Fields are annotated => FIELD @@ -451,7 +606,7 @@ public class JavaResourcePersistentTypeImpl * - and properties exist, but no fields exist => PROPERTY * - and neither fields nor properties exist => null at this level (FIELD in the context model) */ - private AccessType calculateAccessType() { + protected AccessType buildAccessType() { boolean hasPersistableFields = false; boolean hasPersistableProperties = false; for (JavaResourcePersistentAttribute field : CollectionTools.iterable(fields())) { @@ -475,22 +630,34 @@ public class JavaResourcePersistentTypeImpl //no annotations exist, access is null at the resource model level return null; } - - private String superClassQualifiedName(CompilationUnit astRoot) { - ITypeBinding typeBinding = getMember().getBinding(astRoot); - if (typeBinding == null) { - return null; - } - ITypeBinding superClassTypeBinding = typeBinding.getSuperclass(); - if (superClassTypeBinding == null) { - return null; - } - return superClassTypeBinding.getQualifiedName(); + + + // ********** static methods ********** + + // minimize scope of suppressed warnings + @SuppressWarnings("unchecked") + protected static List<VariableDeclarationFragment> fragments(FieldDeclaration fd) { + return fd.fragments(); } - - @Override - public void toString(StringBuilder sb) { - sb.append(getName()); + + + // ********** StringCounter ********** + + protected static class CounterMap { + HashMap<Object, Counter> counters = new HashMap<Object, Counter>(); + + /** + * Return the incremented count for the specified object. + */ + int increment(Object o) { + Counter counter = this.counters.get(o); + if (counter == null) { + counter = new Counter(); + this.counters.put(o, counter); + } + counter.increment(); + return counter.count(); + } } } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JpaCompilationUnitImpl.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JpaCompilationUnitImpl.java index 9516cc2618..a4697ebf26 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JpaCompilationUnitImpl.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/resource/java/JpaCompilationUnitImpl.java @@ -9,12 +9,16 @@ ******************************************************************************/ package org.eclipse.jpt.core.internal.resource.java; +import java.util.List; + import org.eclipse.core.resources.IFile; import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jpt.core.JpaAnnotationProvider; import org.eclipse.jpt.core.internal.utility.jdt.JDTTools; import org.eclipse.jpt.core.resource.java.JavaResourceModel; @@ -29,61 +33,67 @@ public class JpaCompilationUnitImpl implements JpaCompilationUnit { protected final JpaAnnotationProvider annotationProvider; - + protected final CommandExecutorProvider modifySharedDocumentCommandExecutorProvider; - + protected final AnnotationEditFormatter annotationEditFormatter; - + + protected final JavaResourceModel javaResourceModel; + protected final ICompilationUnit compilationUnit; - + /** - * The primary type of the CompilationUnit. Not going to handle - * multiple Types defined in a compilation unit. Entities must have - * a public/protected no-arg constructor and there is no way to access - * it in a non-public/protected class. + * The primary type of the AST compilation unit. We are not going to handle + * multiple types defined in a single compilation unit. Entities must have + * a public/protected no-arg constructor, and there is no way to access + * the constructor in a package class (which is what all top-level, + * non-primary classes must be). */ protected JavaResourcePersistentType persistentType; - public static final String PERSISTENT_TYPE_PROPERTY = "persistentTypeProperty"; - - protected final JavaResourceModel javaResourceModel; - + + + // ********** construction ********** + public JpaCompilationUnitImpl( IFile file, JpaAnnotationProvider annotationProvider, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter, JavaResourceModel javaResourceModel) { - // The jpa compilation unit is the root of its sub-tree - super(null); + super(null); // the JPA compilation unit is the root of its sub-tree this.annotationProvider = annotationProvider; this.modifySharedDocumentCommandExecutorProvider = modifySharedDocumentCommandExecutorProvider; this.annotationEditFormatter = annotationEditFormatter; this.javaResourceModel = javaResourceModel; - this.compilationUnit = compilationUnitFrom(file); - this.initialize(JDTTools.buildASTRoot(this.compilationUnit)); + this.compilationUnit = JavaCore.createCompilationUnitFrom(file); + this.openCompilationUnit(); + this.persistentType = this.buildJavaResourcePersistentType(); } - - protected ICompilationUnit compilationUnitFrom(IFile file) { - ICompilationUnit cu = JavaCore.createCompilationUnitFrom(file); + + protected void openCompilationUnit() { try { - cu.open(null); - } - catch (JavaModelException jme) { + this.compilationUnit.open(null); + } catch (JavaModelException ex) { // do nothing - we just won't have a primary type in this case } - return cu; } - + + protected JavaResourcePersistentType buildJavaResourcePersistentType() { + return this.buildJavaResourcePersistentType(this.buildASTRoot()); + } + + protected JavaResourcePersistentType buildJavaResourcePersistentType(CompilationUnit astRoot) { + TypeDeclaration td = this.getPrimaryType(astRoot); + return (td == null) ? null : this.buildJavaResourcePersistentType(astRoot, td); + } + public void initialize(CompilationUnit astRoot) { - IType iType = this.compilationUnit.findPrimaryType(); - if (iType != null) { - this.persistentType = buildJavaResourcePersistentType(iType, astRoot); - } + // never called? } - - // **************** overrides ********************************************** - - + + + // ********** overrides ********** + @Override protected boolean requiresParent() { return false; @@ -114,18 +124,15 @@ public class JpaCompilationUnitImpl return this.javaResourceModel; } - - // ************************************************************************* - + + // ********** JpaCompilationUnit implementation ********** + public ICompilationUnit getCompilationUnit() { return this.compilationUnit; } public JavaResourcePersistentType getJavaPersistentTypeResource(String fullyQualifiedTypeName) { - if (getPersistentType() != null) { - return getPersistentType().getJavaPersistentTypeResource(fullyQualifiedTypeName); - } - return null; + return (this.persistentType == null) ? null : this.persistentType.getJavaPersistentTypeResource(fullyQualifiedTypeName); } /** @@ -136,79 +143,97 @@ public class JpaCompilationUnitImpl return this.persistentType; //TODO should i only be returning this if it returns true to isPersistable? //that's how we handle nestedTypes on JavaPersistentTypeResource - -// if (this.persistentType.isPersistable()) { -// return this.persistentType; -// } -// return null; + //return this.persistentType.isPersistable() ? this.persistentType : null; } - protected void setPersistentType(JavaResourcePersistentType newPersistentType) { - JavaResourcePersistentType oldPersistentType = this.persistentType; - this.persistentType = newPersistentType; - firePropertyChanged(PERSISTENT_TYPE_PROPERTY, oldPersistentType, newPersistentType); + protected void setPersistentType(JavaResourcePersistentType persistentType) { + JavaResourcePersistentType old = this.persistentType; + this.persistentType = persistentType; + this.firePropertyChanged(PERSISTENT_TYPE_PROPERTY, old, persistentType); } - - private JavaResourcePersistentType buildJavaResourcePersistentType(IType iType, CompilationUnit astRoot) { - //TODO put this hook in to avoid the NPE that we get trying to initialize a persistentTypeResource - //from an annotation type. Entered bug # to handle the bigger issue of when we need to - //not build a persistent type(annotation types) and when we need to have validation instead(final types) - try { - if (iType.isAnnotation() || iType.isEnum()) { - return null; - } - } - catch (JavaModelException e) { - throw new RuntimeException(e); - } - return - JavaResourcePersistentTypeImpl.buildJavaResourcePersistentType(this, - iType, - getModifySharedDocumentCommandExecutorProvider(), - getAnnotationEditFormatter(), - astRoot); - } - public void updateFromJava() { - updateFromJava(JDTTools.buildASTRoot(getCompilationUnit())); + this.updateFromJava(this.buildASTRoot()); } - + public void updateFromJava(CompilationUnit astRoot) { - IType iType = this.compilationUnit.findPrimaryType(); - if (iType == null) { - setPersistentType(null); - } - else { - if (getPersistentType() == null) { - setPersistentType(buildJavaResourcePersistentType(iType, astRoot)); - } - else { - getPersistentType().updateFromJava(astRoot); + TypeDeclaration td = this.getPrimaryType(astRoot); + if (td == null) { + this.setPersistentType(null); + } else { + if (this.persistentType == null) { + this.setPersistentType(this.buildJavaResourcePersistentType(astRoot, td)); + } else { + this.persistentType.updateFromJava(astRoot); } } } - - + public TextRange getTextRange(CompilationUnit astRoot) { - return null;//this.selectionTextRange(); + return null; } -// /** -// * Return null for selection textRange. Entire java file will appear selected when -// * switching files otherwise -// */ -// public ITextRange selectionTextRange() { -// return null; -// } - public void resourceChanged() { this.javaResourceModel.resourceChanged(); } public void resolveTypes() { - if (getPersistentType() != null) { - getPersistentType().resolveTypes(JDTTools.buildASTRoot(getCompilationUnit())); + if (this.persistentType != null) { + this.persistentType.resolveTypes(this.buildASTRoot()); + } + } + + + // ********** internal ********** + + protected CompilationUnit buildASTRoot() { + return JDTTools.buildASTRoot(this.compilationUnit); + } + + // TODO use JPA factory + protected JavaResourcePersistentType buildJavaResourcePersistentType(CompilationUnit astRoot, TypeDeclaration typeDeclaration) { + return JavaResourcePersistentTypeImpl.newInstance(this, typeDeclaration, astRoot); + } + + /** + * i.e. the type with the same name as the compilation unit; + * return the first class or interface (ignore annotations and enums) with + * the same name as the compilation unit (file); + * NB: this type could be in error if there is an annotation or enum + * with the same name preceding it in the compilation unit + */ + protected TypeDeclaration getPrimaryType(CompilationUnit astRoot) { + String primaryTypeName = this.getPrimaryTypeName(); + for (AbstractTypeDeclaration atd : types(astRoot)) { + if ((atd.getNodeType() == ASTNode.TYPE_DECLARATION) + && atd.getName().getFullyQualifiedName().equals(primaryTypeName)) { + return (TypeDeclaration) atd; + } } + return null; + } + + // minimize scope of suppressed warnings + @SuppressWarnings("unchecked") + protected static List<AbstractTypeDeclaration> types(CompilationUnit astRoot) { + return astRoot.types(); } + + /** + * i.e. the name of the compilation unit + */ + protected String getPrimaryTypeName() { + return removeJavaExtension(this.compilationUnit.getElementName()); + } + + protected static String removeJavaExtension(String fileName) { + int index = fileName.lastIndexOf(".java"); + return (index == -1) ? fileName : fileName.substring(0, index); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.persistentType.getName()); + } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/synch/SynchronizeClassesJob.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/synch/SynchronizeClassesJob.java index 2e7872b51d..fbf88c16b5 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/synch/SynchronizeClassesJob.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/synch/SynchronizeClassesJob.java @@ -10,13 +10,14 @@ package org.eclipse.jpt.core.internal.synch; import java.io.IOException; +import java.util.Iterator; + import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IType; import org.eclipse.jpt.core.JpaProject; import org.eclipse.jpt.core.JptCorePlugin; import org.eclipse.jpt.core.context.persistence.MappingFileRef; @@ -82,11 +83,11 @@ public class SynchronizeClassesJob extends WorkspaceJob persistenceUnitResource.getClasses().clear(); - monitor.worked(25); - - for (IType type : CollectionTools.iterable(jpaProject.annotatedClasses())) { - String fullyQualifiedTypeName = type.getFullyQualifiedName('.'); - if (!mappingFileContains(jpaProject, fullyQualifiedTypeName)) { + monitor.worked(25); + + for (Iterator<String> stream = jpaProject.annotatedClassNames(); stream.hasNext(); ) { + String fullyQualifiedTypeName = stream.next(); + if ( ! mappingFileContains(jpaProject, fullyQualifiedTypeName)) { XmlJavaClassRef classRef = PersistenceFactory.eINSTANCE.createXmlJavaClassRef(); classRef.setJavaClass(fullyQualifiedTypeName); persistenceUnitResource.getClasses().add(classRef); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodeSearchUtil.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodeSearchUtil.java deleted file mode 100644 index c1abe0ece0..0000000000 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodeSearchUtil.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jpt.core.internal.utility.jdt; - -import java.util.List; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; -import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; -import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; -import org.eclipse.jdt.core.dom.BodyDeclaration; -import org.eclipse.jdt.core.dom.ClassInstanceCreation; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.EnumConstantDeclaration; -import org.eclipse.jdt.core.dom.EnumDeclaration; -import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclarationFragment; - -//copied from org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil -//deleted code to limit the number of classes I had to copy -public class ASTNodeSearchUtil { - - private ASTNodeSearchUtil() { - //no instance - } - - - public static MethodDeclaration getMethodDeclarationNode(IMethod iMethod, CompilationUnit cuNode) throws JavaModelException { - return (MethodDeclaration)ASTNodes.getParent(getNameNode(iMethod, cuNode), MethodDeclaration.class); - } - - public static ASTNode getParent(ASTNode node, Class<?> parentClass) { - do { - node= node.getParent(); - } while (node != null && !parentClass.isInstance(node)); - return node; - } - - - public static AnnotationTypeMemberDeclaration getAnnotationTypeMemberDeclarationNode(IMethod iMethod, CompilationUnit cuNode) throws JavaModelException { - return (AnnotationTypeMemberDeclaration) ASTNodes.getParent(getNameNode(iMethod, cuNode), AnnotationTypeMemberDeclaration.class); - } - - public static VariableDeclarationFragment getFieldDeclarationFragmentNode(IField iField, CompilationUnit cuNode) throws JavaModelException { - ASTNode node= getNameNode(iField, cuNode); - if (node instanceof VariableDeclarationFragment) - return (VariableDeclarationFragment)node; - return (VariableDeclarationFragment)ASTNodes.getParent(node, VariableDeclarationFragment.class); - } - - public static FieldDeclaration getFieldDeclarationNode(IField iField, CompilationUnit cuNode) throws JavaModelException { - return (FieldDeclaration) ASTNodes.getParent(getNameNode(iField, cuNode), FieldDeclaration.class); - } - - public static EnumConstantDeclaration getEnumConstantDeclaration(IField iField, CompilationUnit cuNode) throws JavaModelException { - return (EnumConstantDeclaration) ASTNodes.getParent(getNameNode(iField, cuNode), EnumConstantDeclaration.class); - } - - public static EnumDeclaration getEnumDeclarationNode(IType iType, CompilationUnit cuNode) throws JavaModelException { - return (EnumDeclaration) ASTNodes.getParent(getNameNode(iType, cuNode), EnumDeclaration.class); - } - - public static AnnotationTypeDeclaration getAnnotationTypeDeclarationNode(IType iType, CompilationUnit cuNode) throws JavaModelException { - return (AnnotationTypeDeclaration) ASTNodes.getParent(getNameNode(iType, cuNode), AnnotationTypeDeclaration.class); - } - - public static BodyDeclaration getBodyDeclarationNode(IMember iMember, CompilationUnit cuNode) throws JavaModelException { - return (BodyDeclaration) ASTNodes.getParent(getNameNode(iMember, cuNode), BodyDeclaration.class); - } - - public static AbstractTypeDeclaration getAbstractTypeDeclarationNode(IType iType, CompilationUnit cuNode) throws JavaModelException { - return (AbstractTypeDeclaration) ASTNodes.getParent(getNameNode(iType, cuNode), AbstractTypeDeclaration.class); - } - - public static TypeDeclaration getTypeDeclarationNode(IType iType, CompilationUnit cuNode) throws JavaModelException { - return (TypeDeclaration) ASTNodes.getParent(getNameNode(iType, cuNode), TypeDeclaration.class); - } - - public static ClassInstanceCreation getClassInstanceCreationNode(IType iType, CompilationUnit cuNode) throws JavaModelException { - return (ClassInstanceCreation) ASTNodes.getParent(getNameNode(iType, cuNode), ClassInstanceCreation.class); - } - - @SuppressWarnings("unchecked") - public static List<BodyDeclaration> getBodyDeclarationList(IType iType, CompilationUnit cuNode) throws JavaModelException { - if (iType.isAnonymous()) - return getClassInstanceCreationNode(iType, cuNode).getAnonymousClassDeclaration().bodyDeclarations(); - return getAbstractTypeDeclarationNode(iType, cuNode).bodyDeclarations(); - } - - private static ASTNode getNameNode(IMember iMember, CompilationUnit cuNode) throws JavaModelException { - return NodeFinder.perform(cuNode, iMember.getNameRange()); - } -} - diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodes.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodes.java deleted file mode 100644 index 6a14ee33a8..0000000000 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/ASTNodes.java +++ /dev/null @@ -1,726 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for - * bug "inline method - doesn't handle implicit cast" (see - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=24941). - * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for - * bug Encapsulate field can fail when two variables in one variable declaration (see - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=51540). - *******************************************************************************/ -package org.eclipse.jpt.core.internal.utility.jdt; - -import java.util.ArrayList; -import java.util.List; -import org.eclipse.core.runtime.Assert; -import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.ISourceReference; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; -import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; -import org.eclipse.jdt.core.dom.ArrayType; -import org.eclipse.jdt.core.dom.Assignment; -import org.eclipse.jdt.core.dom.BodyDeclaration; -import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; -import org.eclipse.jdt.core.dom.ClassInstanceCreation; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.DoStatement; -import org.eclipse.jdt.core.dom.EnhancedForStatement; -import org.eclipse.jdt.core.dom.EnumConstantDeclaration; -import org.eclipse.jdt.core.dom.Expression; -import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.ForStatement; -import org.eclipse.jdt.core.dom.IBinding; -import org.eclipse.jdt.core.dom.IExtendedModifier; -import org.eclipse.jdt.core.dom.IMethodBinding; -import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; -import org.eclipse.jdt.core.dom.IfStatement; -import org.eclipse.jdt.core.dom.InfixExpression; -import org.eclipse.jdt.core.dom.Message; -import org.eclipse.jdt.core.dom.MethodInvocation; -import org.eclipse.jdt.core.dom.Modifier; -import org.eclipse.jdt.core.dom.Name; -import org.eclipse.jdt.core.dom.ParameterizedType; -import org.eclipse.jdt.core.dom.PrimitiveType; -import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.core.dom.QualifiedType; -import org.eclipse.jdt.core.dom.ReturnStatement; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.SimpleType; -import org.eclipse.jdt.core.dom.SingleVariableDeclaration; -import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; -import org.eclipse.jdt.core.dom.Type; -import org.eclipse.jdt.core.dom.VariableDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclarationExpression; -import org.eclipse.jdt.core.dom.VariableDeclarationFragment; -import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.core.dom.WhileStatement; - - -//copied from org.eclipse.jdt.internal.corext.dom.ASTNodes -//deleted code to limit the number of classes I had to copy -public class ASTNodes { - - public static final int NODE_ONLY= 0; - public static final int INCLUDE_FIRST_PARENT= 1; - public static final int INCLUDE_ALL_PARENTS= 2; - - public static final int WARNING= 1 << 0; - public static final int ERROR= 1 << 1; - public static final int PROBLEMS= WARNING | ERROR; - - private static final Message[] EMPTY_MESSAGES= new Message[0]; - private static final IProblem[] EMPTY_PROBLEMS= new IProblem[0]; - - private static final int CLEAR_VISIBILITY= ~(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); - - - private ASTNodes() { - // no instance; - } - - /** - * Returns the list that contains the given ASTNode. If the node - * isn't part of any list, <code>null</code> is returned. - * - * @param node the node in question - * @return the list that contains the node or <code>null</code> - */ - @SuppressWarnings("unchecked") - public static List<ASTNode> getContainingList(ASTNode node) { - StructuralPropertyDescriptor locationInParent= node.getLocationInParent(); - if (locationInParent != null && locationInParent.isChildListProperty()) { - return (List<ASTNode>) node.getParent().getStructuralProperty(locationInParent); - } - return null; - } - - /** - * Returns a list of the direct children of a node. The siblings are ordered by start offset. - * @param node the node to get the children for - * @return the children - */ - public static List<ASTNode> getChildren(ASTNode node) { - ChildrenCollector visitor= new ChildrenCollector(); - node.accept(visitor); - return visitor.result; - } - - private static class ChildrenCollector extends GenericVisitor { - public List<ASTNode> result; - - public ChildrenCollector() { - super(true); - result= null; - } - @Override - protected boolean visitNode(ASTNode node) { - if (result == null) { // first visitNode: on the node's parent: do nothing, return true - result= new ArrayList<ASTNode>(); - return true; - } - result.add(node); - return false; - } - } - - /** - * Returns true if this is an existing node, i.e. it was created as part of - * a parsing process of a source code file. Returns false if this is a newly - * created node which has not yet been given a source position. - * - * @param node the node to be tested. - * @return true if this is an existing node, false if not. - */ - public static boolean isExistingNode(ASTNode node) { - return node.getStartPosition() != -1; - } - - /** - * Returns the element type. This is a convenience method that returns its - * argument if it is a simple type and the element type if the parameter is an array type. - * @param type The type to get the element type from. - * @return The element type of the type or the type itself. - */ - public static Type getElementType(Type type) { - if (! type.isArrayType()) - return type; - return ((ArrayType)type).getElementType(); - } - - public static ASTNode findDeclaration(IBinding binding, ASTNode root) { - root= root.getRoot(); - if (root instanceof CompilationUnit) { - return ((CompilationUnit)root).findDeclaringNode(binding); - } - return null; - } - - public static VariableDeclaration findVariableDeclaration(IVariableBinding binding, ASTNode root) { - if (binding.isField()) - return null; - ASTNode result= findDeclaration(binding, root); - if (result instanceof VariableDeclaration) - return (VariableDeclaration)result; - - return null; - } - - /** - * Returns the type node for the given declaration. - * @param declaration the declaration - * @return the type node - */ - public static Type getType(VariableDeclaration declaration) { - if (declaration instanceof SingleVariableDeclaration) { - return ((SingleVariableDeclaration)declaration).getType(); - } else if (declaration instanceof VariableDeclarationFragment) { - ASTNode parent= ((VariableDeclarationFragment)declaration).getParent(); - if (parent instanceof VariableDeclarationExpression) - return ((VariableDeclarationExpression)parent).getType(); - else if (parent instanceof VariableDeclarationStatement) - return ((VariableDeclarationStatement)parent).getType(); - else if (parent instanceof FieldDeclaration) - return ((FieldDeclaration)parent).getType(); - } - Assert.isTrue(false, "Unknown VariableDeclaration"); //$NON-NLS-1$ - return null; - } - - public static int getDimensions(VariableDeclaration declaration) { - int dim= declaration.getExtraDimensions(); - Type type= getType(declaration); - if (type instanceof ArrayType) { - dim += ((ArrayType) type).getDimensions(); - } - return dim; - } - - @SuppressWarnings("unchecked") - public static List<IExtendedModifier> getModifiers(VariableDeclaration declaration) { - Assert.isNotNull(declaration); - if (declaration instanceof SingleVariableDeclaration) { - return ((SingleVariableDeclaration)declaration).modifiers(); - } else if (declaration instanceof VariableDeclarationFragment) { - ASTNode parent= declaration.getParent(); - if (parent instanceof VariableDeclarationExpression) - return ((VariableDeclarationExpression)parent).modifiers(); - else if (parent instanceof VariableDeclarationStatement) - return ((VariableDeclarationStatement)parent).modifiers(); - } - return new ArrayList<IExtendedModifier>(0); - } - - public static boolean isSingleDeclaration(VariableDeclaration declaration) { - Assert.isNotNull(declaration); - if (declaration instanceof SingleVariableDeclaration) { - return true; - } else if (declaration instanceof VariableDeclarationFragment) { - ASTNode parent= declaration.getParent(); - if (parent instanceof VariableDeclarationExpression) - return ((VariableDeclarationExpression)parent).fragments().size() == 1; - else if (parent instanceof VariableDeclarationStatement) - return ((VariableDeclarationStatement)parent).fragments().size() == 1; - } - return false; - } - - public static boolean isLiteral(Expression expression) { - int type= expression.getNodeType(); - return type == ASTNode.BOOLEAN_LITERAL || type == ASTNode.CHARACTER_LITERAL || type == ASTNode.NULL_LITERAL || - type == ASTNode.NUMBER_LITERAL || type == ASTNode.STRING_LITERAL || type == ASTNode.TYPE_LITERAL; - } - - public static boolean isLabel(SimpleName name) { - int parentType= name.getParent().getNodeType(); - return parentType == ASTNode.LABELED_STATEMENT || - parentType == ASTNode.BREAK_STATEMENT || parentType != ASTNode.CONTINUE_STATEMENT; - } - - public static boolean isStatic(BodyDeclaration declaration) { - return Modifier.isStatic(declaration.getModifiers()); - } - - @SuppressWarnings("unchecked") - public static List<BodyDeclaration> getBodyDeclarations(ASTNode node) { - if (node instanceof AbstractTypeDeclaration) { - return ((AbstractTypeDeclaration)node).bodyDeclarations(); - } else if (node instanceof AnonymousClassDeclaration) { - return ((AnonymousClassDeclaration)node).bodyDeclarations(); - } - // should not happen. - Assert.isTrue(false); - return null; - } - - public static ChildListPropertyDescriptor getBodyDeclarationsProperty(ASTNode node) { - if (node instanceof AbstractTypeDeclaration) { - return ((AbstractTypeDeclaration)node).getBodyDeclarationsProperty(); - } else if (node instanceof AnonymousClassDeclaration) { - return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY; - } - // should not happen. - Assert.isTrue(false); - return null; - } - - public static String getTypeName(Type type) { - final StringBuffer buffer= new StringBuffer(); - ASTVisitor visitor= new ASTVisitor() { - @Override - public boolean visit(PrimitiveType node) { - buffer.append(node.getPrimitiveTypeCode().toString()); - return false; - } - @Override - public boolean visit(SimpleName node) { - buffer.append(node.getIdentifier()); - return false; - } - @Override - public boolean visit(QualifiedName node) { - buffer.append(node.getName().getIdentifier()); - return false; - } - @Override - public void endVisit(ArrayType node) { - buffer.append("[]"); //$NON-NLS-1$ - } - }; - type.accept(visitor); - return buffer.toString(); - } - - public static InfixExpression.Operator convertToInfixOperator(Assignment.Operator operator) { - if (operator.equals(Assignment.Operator.PLUS_ASSIGN)) - return InfixExpression.Operator.PLUS; - - if (operator.equals(Assignment.Operator.MINUS_ASSIGN)) - return InfixExpression.Operator.MINUS; - - if (operator.equals(Assignment.Operator.TIMES_ASSIGN)) - return InfixExpression.Operator.TIMES; - - if (operator.equals(Assignment.Operator.DIVIDE_ASSIGN)) - return InfixExpression.Operator.DIVIDE; - - if (operator.equals(Assignment.Operator.BIT_AND_ASSIGN)) - return InfixExpression.Operator.AND; - - if (operator.equals(Assignment.Operator.BIT_OR_ASSIGN)) - return InfixExpression.Operator.OR; - - if (operator.equals(Assignment.Operator.BIT_XOR_ASSIGN)) - return InfixExpression.Operator.XOR; - - if (operator.equals(Assignment.Operator.REMAINDER_ASSIGN)) - return InfixExpression.Operator.REMAINDER; - - if (operator.equals(Assignment.Operator.LEFT_SHIFT_ASSIGN)) - return InfixExpression.Operator.LEFT_SHIFT; - - if (operator.equals(Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN)) - return InfixExpression.Operator.RIGHT_SHIFT_SIGNED; - - if (operator.equals(Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN)) - return InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED; - - Assert.isTrue(false, "Cannot convert assignment operator"); //$NON-NLS-1$ - return null; - } - - /** - * Returns true if a node at a given location is a body of a control statement. Such body nodes are - * interesting as when replacing them, it has to be evaluates if a Block is needed instead. - * E.g. <code> if (x) do(); -> if (x) { do1(); do2() } </code> - * - * @param locationInParent Location of the body node - * @return Returns true if the location is a body node location of a control statement. - */ - public static boolean isControlStatementBody(StructuralPropertyDescriptor locationInParent) { - return locationInParent == IfStatement.THEN_STATEMENT_PROPERTY - || locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY - || locationInParent == ForStatement.BODY_PROPERTY - || locationInParent == EnhancedForStatement.BODY_PROPERTY - || locationInParent == WhileStatement.BODY_PROPERTY - || locationInParent == DoStatement.BODY_PROPERTY; - } - - public static boolean needsParentheses(Expression expression) { - int type= expression.getNodeType(); - return type == ASTNode.INFIX_EXPRESSION || type == ASTNode.CONDITIONAL_EXPRESSION || - type == ASTNode.PREFIX_EXPRESSION || type == ASTNode.POSTFIX_EXPRESSION || - type == ASTNode.CAST_EXPRESSION || type == ASTNode.INSTANCEOF_EXPRESSION; - } - - - public static boolean substituteMustBeParenthesized(Expression substitute, Expression location) { - if (!needsParentheses(substitute)) - return false; - - ASTNode parent= location.getParent(); - if (parent instanceof VariableDeclarationFragment){ - VariableDeclarationFragment vdf= (VariableDeclarationFragment)parent; - if (vdf.getInitializer().equals(location)) - return false; - } else if (parent instanceof MethodInvocation){ - MethodInvocation mi= (MethodInvocation)parent; - if (mi.arguments().contains(location)) - return false; - } else if (parent instanceof ReturnStatement) - return false; - - return true; - } - - public static ASTNode getParent(ASTNode node, Class<? extends ASTNode> parentClass) { - do { - node= node.getParent(); - } while (node != null && !parentClass.isInstance(node)); - return node; - } - - public static ASTNode getParent(ASTNode node, int nodeType) { - do { - node= node.getParent(); - } while (node != null && node.getNodeType() != nodeType); - return node; - } - - public static ASTNode findParent(ASTNode node, StructuralPropertyDescriptor[][] pathes) { - for (int p= 0; p < pathes.length; p++) { - StructuralPropertyDescriptor[] path= pathes[p]; - ASTNode current= node; - int d= path.length - 1; - for (; d >= 0 && current != null; d--) { - StructuralPropertyDescriptor descriptor= path[d]; - if (!descriptor.equals(current.getLocationInParent())) - break; - current= current.getParent(); - } - if (d < 0) - return current; - } - return null; - } - - public static ASTNode getNormalizedNode(ASTNode node) { - ASTNode current= node; - // normalize name - if (QualifiedName.NAME_PROPERTY.equals(current.getLocationInParent())) { - current= current.getParent(); - } - // normalize type - if (QualifiedType.NAME_PROPERTY.equals(current.getLocationInParent()) || - SimpleType.NAME_PROPERTY.equals(current.getLocationInParent())) { - current= current.getParent(); - } - // normalize parameterized types - if (ParameterizedType.TYPE_PROPERTY.equals(current.getLocationInParent())) { - current= current.getParent(); - } - return current; - } - - public static boolean isParent(ASTNode node, ASTNode parent) { - Assert.isNotNull(parent); - do { - node= node.getParent(); - if (node == parent) - return true; - } while (node != null); - return false; - } - - public static int getExclusiveEnd(ASTNode node){ - return node.getStartPosition() + node.getLength(); - } - - public static int getInclusiveEnd(ASTNode node){ - return node.getStartPosition() + node.getLength() - 1; - } - - public static IMethodBinding getMethodBinding(Name node) { - IBinding binding= node.resolveBinding(); - if (binding instanceof IMethodBinding) - return (IMethodBinding)binding; - return null; - } - - public static IVariableBinding getVariableBinding(Name node) { - IBinding binding= node.resolveBinding(); - if (binding instanceof IVariableBinding) - return (IVariableBinding)binding; - return null; - } - - public static IVariableBinding getLocalVariableBinding(Name node) { - IVariableBinding result= getVariableBinding(node); - if (result == null || result.isField()) - return null; - - return result; - } - - public static IVariableBinding getFieldBinding(Name node) { - IVariableBinding result= getVariableBinding(node); - if (result == null || !result.isField()) - return null; - - return result; - } - - public static ITypeBinding getTypeBinding(Name node) { - IBinding binding= node.resolveBinding(); - if (binding instanceof ITypeBinding) - return (ITypeBinding)binding; - return null; - } - - /** - * Returns the receiver's type binding of the given method invocation. - * - * @param invocation method invocation to resolve type of - * @return the type binding of the receiver - */ - public static ITypeBinding getReceiverTypeBinding(MethodInvocation invocation) { - ITypeBinding result= null; - Expression exp= invocation.getExpression(); - if(exp != null) { - return exp.resolveTypeBinding(); - } - AbstractTypeDeclaration type= (AbstractTypeDeclaration)getParent(invocation, AbstractTypeDeclaration.class); - if (type != null) - return type.resolveBinding(); - return result; - } - - public static ITypeBinding getEnclosingType(ASTNode node) { - while(node != null) { - if (node instanceof AbstractTypeDeclaration) { - return ((AbstractTypeDeclaration)node).resolveBinding(); - } else if (node instanceof AnonymousClassDeclaration) { - return ((AnonymousClassDeclaration)node).resolveBinding(); - } - node= node.getParent(); - } - return null; - } - - public static IProblem[] getProblems(ASTNode node, int scope, int severity) { - ASTNode root= node.getRoot(); - if (!(root instanceof CompilationUnit)) - return EMPTY_PROBLEMS; - IProblem[] problems= ((CompilationUnit)root).getProblems(); - if (root == node) - return problems; - final int iterations= computeIterations(scope); - List<IProblem> result= new ArrayList<IProblem>(5); - for (int i= 0; i < problems.length; i++) { - IProblem problem= problems[i]; - boolean consider= false; - if ((severity & PROBLEMS) == PROBLEMS) - consider= true; - else if ((severity & WARNING) != 0) - consider= problem.isWarning(); - else if ((severity & ERROR) != 0) - consider= problem.isError(); - if (consider) { - ASTNode temp= node; - int count= iterations; - do { - int nodeOffset= temp.getStartPosition(); - int problemOffset= problem.getSourceStart(); - if (nodeOffset <= problemOffset && problemOffset < nodeOffset + temp.getLength()) { - result.add(problem); - count= 0; - } else { - count--; - } - } while ((temp= temp.getParent()) != null && count > 0); - } - } - return result.toArray(new IProblem[result.size()]); - } - - public static Message[] getMessages(ASTNode node, int flags) { - ASTNode root= node.getRoot(); - if (!(root instanceof CompilationUnit)) - return EMPTY_MESSAGES; - Message[] messages= ((CompilationUnit)root).getMessages(); - if (root == node) - return messages; - final int iterations= computeIterations(flags); - List<Message> result= new ArrayList<Message>(5); - for (int i= 0; i < messages.length; i++) { - Message message= messages[i]; - ASTNode temp= node; - int count= iterations; - do { - int nodeOffset= temp.getStartPosition(); - int messageOffset= message.getStartPosition(); - if (nodeOffset <= messageOffset && messageOffset < nodeOffset + temp.getLength()) { - result.add(message); - count= 0; - } else { - count--; - } - } while ((temp= temp.getParent()) != null && count > 0); - } - return result.toArray(new Message[result.size()]); - } - - private static int computeIterations(int flags) { - switch (flags) { - case NODE_ONLY: - return 1; - case INCLUDE_ALL_PARENTS: - return Integer.MAX_VALUE; - case INCLUDE_FIRST_PARENT: - return 2; - default: - return 1; - } - } - - public static SimpleName getLeftMostSimpleName(Name name) { - if (name instanceof SimpleName) { - return (SimpleName)name; - } - final SimpleName[] result= new SimpleName[1]; - ASTVisitor visitor= new ASTVisitor() { - @Override - public boolean visit(QualifiedName qualifiedName) { - Name left= qualifiedName.getQualifier(); - if (left instanceof SimpleName) - result[0]= (SimpleName)left; - else - left.accept(this); - return false; - } - }; - name.accept(visitor); - return result[0]; - } - - public static SimpleType getLeftMostSimpleType(QualifiedType type) { - final SimpleType[] result= new SimpleType[1]; - ASTVisitor visitor= new ASTVisitor() { - @Override - public boolean visit(QualifiedType qualifiedType) { - Type left= qualifiedType.getQualifier(); - if (left instanceof SimpleType) - result[0]= (SimpleType)left; - else - left.accept(this); - return false; - } - }; - type.accept(visitor); - return result[0]; - } - - public static Name getTopMostName(Name name) { - Name result= name; - while(result.getParent() instanceof Name) { - result= (Name)result.getParent(); - } - return result; - } - - public static Type getTopMostType(Type type) { - Type result= type; - while(result.getParent() instanceof Type) { - result= (Type)result.getParent(); - } - return result; - } - - public static int changeVisibility(int modifiers, int visibility) { - return (modifiers & CLEAR_VISIBILITY) | visibility; - } - - /** - * Adds flags to the given node and all its descendants. - * @param root The root node - * @param flags The flags to set - */ - public static void setFlagsToAST(ASTNode root, final int flags) { - root.accept(new GenericVisitor(true) { - @Override - protected boolean visitNode(ASTNode node) { - node.setFlags(node.getFlags() | flags); - return true; - } - }); - } - - public static String getQualifier(Name name) { - if (name.isQualifiedName()) { - return ((QualifiedName) name).getQualifier().getFullyQualifiedName(); - } - return ""; //$NON-NLS-1$ - } - - public static String getSimpleNameIdentifier(Name name) { - if (name.isQualifiedName()) { - return ((QualifiedName) name).getName().getIdentifier(); - } - return ((SimpleName) name).getIdentifier(); - } - - public static boolean isDeclaration(Name name) { - if (name.isQualifiedName()) { - return ((QualifiedName) name).getName().isDeclaration(); - } - return ((SimpleName) name).isDeclaration(); - } - - public static Modifier findModifierNode(int flag, List<?> modifiers) { - for (int i= 0; i < modifiers.size(); i++) { - Object curr= modifiers.get(i); - if (curr instanceof Modifier && ((Modifier) curr).getKeyword().toFlagValue() == flag) { - return (Modifier) curr; - } - } - return null; - } - - public static ITypeBinding getTypeBinding(CompilationUnit root, IType type) throws JavaModelException { - if (type.isAnonymous()) { - final IJavaElement parent= type.getParent(); - if (parent instanceof IField && Flags.isEnum(((IMember) parent).getFlags())) { - final EnumConstantDeclaration constant= (EnumConstantDeclaration) NodeFinder.perform(root, ((ISourceReference) parent).getSourceRange()); - if (constant != null) { - final AnonymousClassDeclaration declaration= constant.getAnonymousClassDeclaration(); - if (declaration != null) - return declaration.resolveBinding(); - } - } else { - final ClassInstanceCreation creation= (ClassInstanceCreation) getParent(NodeFinder.perform(root, type.getNameRange()), ClassInstanceCreation.class); - if (creation != null) - return creation.resolveTypeBinding(); - } - } else { - final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) getParent(NodeFinder.perform(root, type.getNameRange()), AbstractTypeDeclaration.class); - if (declaration != null) - return declaration.resolveBinding(); - } - return null; - } -} - diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTAttribute.java index 8e4059748a..0de59055c8 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTAttribute.java @@ -9,29 +9,47 @@ ******************************************************************************/ package org.eclipse.jpt.core.internal.utility.jdt; -import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; import org.eclipse.jpt.core.utility.jdt.Attribute; +import org.eclipse.jpt.core.utility.jdt.Type; import org.eclipse.jpt.utility.CommandExecutorProvider; /** - * Combine behavior common to FieldAttribute and MethodAttribute. + * Combine behavior common to JDTFieldAttribute and JDTMethodAttribute. + * Not so sure this is useful.... */ public abstract class JDTAttribute extends JDTMember implements Attribute { - JDTAttribute(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { - super(jdtMember, modifySharedDocumentCommandExecutorProvider); + // ********** constructors ********** + + protected JDTAttribute( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + super(declaringType, name, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider); } - - JDTAttribute(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) { - super(jdtMember, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); + + protected JDTAttribute( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + super(declaringType, name, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); } + + // ********** Member/Attribute implementation ********** + public boolean isField() { return false; } @@ -40,11 +58,13 @@ public abstract class JDTAttribute return false; } - /** - * this will throw a NPE for a top-level type - */ - TypeDeclaration declaringTypeDeclaration(CompilationUnit astRoot) { - //assume no enums or annotation types since they have no field or method declarations - return (TypeDeclaration) this.declaringType().getBodyDeclaration(astRoot); + + // ********** internal ********** + + protected TypeDeclaration getDeclaringTypeDeclaration(CompilationUnit astRoot) { + // assume the declaring type is not an enum or annotation + // since they do not have field or method declarations + return this.getDeclaringType().getBodyDeclaration(astRoot); } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTFieldAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTFieldAttribute.java index 262775d06c..bdcbec67db 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTFieldAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTFieldAttribute.java @@ -10,7 +10,9 @@ package org.eclipse.jpt.core.internal.utility.jdt; import java.util.List; -import org.eclipse.jdt.core.IField; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; @@ -19,10 +21,11 @@ import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jpt.core.utility.TextRange; import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; import org.eclipse.jpt.core.utility.jdt.FieldAttribute; +import org.eclipse.jpt.core.utility.jdt.Type; import org.eclipse.jpt.utility.CommandExecutorProvider; /** - * Adapt and extend a jdt field. + * Adapt and extend a JDT field. * Attribute based on a Java field, e.g. * private int foo; */ @@ -31,75 +34,148 @@ public class JDTFieldAttribute implements FieldAttribute { - public JDTFieldAttribute(IField field, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { - super(field, modifySharedDocumentCommandExecutorProvider); + // ********** constructors ********** + + public JDTFieldAttribute( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + this(declaringType, name, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); } - public JDTFieldAttribute(IField field, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) { - super(field, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); + public JDTFieldAttribute( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + super(declaringType, name, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); } - @Override - public IField getJdtMember() { - return (IField) super.getJdtMember(); + /** + * constructor for testing + */ + public JDTFieldAttribute(Type declaringType, String name, int occurrence, ICompilationUnit compilationUnit) { + this(declaringType, name, occurrence, compilationUnit, CommandExecutorProvider.Default.instance(), DefaultAnnotationEditFormatter.instance()); } - // ********** Member implementation ********** + // ********** Member/Attribute/FieldAttribute implementation ********** - public FieldDeclaration getBodyDeclaration(CompilationUnit astRoot) { - String fieldName = this.getName(); - for (FieldDeclaration fieldDeclaration : this.declaringTypeDeclaration(astRoot).getFields()) { - // handle multiple fields declared in a single statement: - // private int foo, bar; - for (VariableDeclarationFragment fragment : this.fragments(fieldDeclaration)) { - if (fragment.getName().getFullyQualifiedName().equals(fieldName)) { - return fieldDeclaration; - } - } - } - return null; + public IVariableBinding getBinding(CompilationUnit astRoot) { + return this.getFragment(astRoot).resolveBinding(); } - private VariableDeclarationFragment getFragment(CompilationUnit astRoot) { - FieldDeclaration fieldDeclaration = getBodyDeclaration(astRoot); - for (VariableDeclarationFragment fragment : this.fragments(fieldDeclaration)) { - if (fragment.getName().getFullyQualifiedName().equals(getName())) { - return fragment; - } - } - //TODO could this ever happen, should I throw an exception instead? - return null; - } - - public IVariableBinding getBinding(CompilationUnit astRoot) { - return getFragment(astRoot).resolveBinding(); + public FieldDeclaration getBodyDeclaration(CompilationUnit astRoot) { + return this.getSelectedDeclaration(astRoot, FIELD_DECLARATION_SELECTOR); } - + public TextRange getNameTextRange(CompilationUnit astRoot) { - return new ASTNodeTextRange(getFragment(astRoot).getName()); + return new ASTNodeTextRange(this.getFragment(astRoot).getName()); } - // ********** Attribute implementation ********** + public String getAttributeName() { + return this.getName_(); + } + + public ITypeBinding getTypeBinding(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).getType().resolveBinding(); + } @Override public boolean isField() { return true; } - public String getAttributeName() { - return this.getName(); + public boolean isPersistable(CompilationUnit astRoot) { + IVariableBinding binding = this.getBinding(astRoot); + return (binding == null) ? false : JPTTools.fieldIsPersistable(binding); } - public ITypeBinding getTypeBinding(CompilationUnit astRoot) { - return getBodyDeclaration(astRoot).getType().resolveBinding(); + + // ********** internal ********** + + protected VariableDeclarationFragment getFragment(CompilationUnit astRoot) { + return this.getSelectedDeclaration(astRoot, VARIABLE_DECLARATION_FRAGMENT_SELECTOR); } - // ********** miscellaneous ********** + /** + * return either a FieldDeclaration or a VariableDeclarationFragment, + * depending on the specified selector; + * + * handle multiple fields declared in a single statement: + * private int foo, bar; + */ + protected <T extends ASTNode> T getSelectedDeclaration(CompilationUnit astRoot, Selector<T> selector) { + String name = this.getName_(); + int occurrence = this.getOccurrence(); + int count = 0; + for (FieldDeclaration fieldDeclaration : this.getDeclaringTypeFieldDeclarations(astRoot)) { + for (VariableDeclarationFragment fragment : fragments(fieldDeclaration)) { + if (fragment.getName().getFullyQualifiedName().equals(name)) { + count++; + if (count == occurrence) { + return selector.select(fieldDeclaration, fragment); + } + } + } + } + // return null if the field is no longer in the source code; + // this can happen when the context model has not yet + // been synchronized with the resource model but is still + // asking for an ASTNode (e.g. during a selection event) + return null; + } + protected FieldDeclaration[] getDeclaringTypeFieldDeclarations(CompilationUnit astRoot) { + return this.getDeclaringTypeDeclaration(astRoot).getFields(); + } + + // minimize scope of suppressed warnings @SuppressWarnings("unchecked") - protected List<VariableDeclarationFragment> fragments(FieldDeclaration fd) { + protected static List<VariableDeclarationFragment> fragments(FieldDeclaration fd) { return fd.fragments(); } + + // ********** Selector ********** + + // I'm not quite sure this interface is worth the resulting obfuscation, + // but, then, I kept changing both methods, so... ~bjv + protected interface Selector<T extends ASTNode> { + T select(FieldDeclaration fieldDeclaration, VariableDeclarationFragment variableDeclarationFragment); + String getDescription(); + } + + protected static final Selector<FieldDeclaration> FIELD_DECLARATION_SELECTOR = + new Selector<FieldDeclaration>() { + public FieldDeclaration select(FieldDeclaration fieldDeclaration, VariableDeclarationFragment variableDeclarationFragment) { + return fieldDeclaration; + } + public String getDescription() { + return "field declaration"; + } + @Override + public String toString() { + return "FIELD_DECLARATION_SELECTOR"; + } + }; + + protected static final Selector<VariableDeclarationFragment> VARIABLE_DECLARATION_FRAGMENT_SELECTOR = + new Selector<VariableDeclarationFragment>() { + public VariableDeclarationFragment select(FieldDeclaration fieldDeclaration, VariableDeclarationFragment variableDeclarationFragment) { + return variableDeclarationFragment; + } + public String getDescription() { + return "variable declaration fragment"; + } + @Override + public String toString() { + return "VARIABLE_DECLARATION_FRAGMENT_SELECTOR"; + } + }; + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMember.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMember.java index 29816fab7b..fec82d670a 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMember.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMember.java @@ -13,8 +13,6 @@ import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IMember; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jface.text.BadLocationException; @@ -37,80 +35,100 @@ import org.eclipse.text.edits.TextEdit; public abstract class JDTMember implements Member { + /** this will be null for the primary type */ + private final Type declaringType; - private final IMember jdtMember; + /** the member's name (duh) */ + private final String name; - /** this will be null for a top-level type */ - private final Type declaringType; + /** + * members can occur more than once in non-compiling source; + * count starts at 1; the primary type will have occurrence 1 + */ + private final int occurrence; + /** + * the compilation unit (file) containing the member; + * used for building an AST when we modify the member + */ + private final ICompilationUnit compilationUnit; + + /** + * this allows clients to provide a way to modify the compilation unit + * (file) when it is open in an editor and should be modified on the UI + * thread + */ private final CommandExecutorProvider modifySharedDocumentCommandExecutorProvider; + /** this will format the member's annotations a bit */ private final AnnotationEditFormatter annotationEditFormatter; - // ********** constructor ********** - - JDTMember(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { - this(jdtMember, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); - } + + // ********** constructors ********** - JDTMember(IMember jdtMember, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) { + protected JDTMember( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + this(declaringType, name, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); + } + + protected JDTMember( + Type declaringType, + String name, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { super(); - this.jdtMember = jdtMember; - IType jdtDeclaringType = jdtMember.getDeclaringType(); - this.declaringType = (jdtDeclaringType == null) ? null : new JDTType(jdtDeclaringType, modifySharedDocumentCommandExecutorProvider); + this.declaringType = declaringType; + this.name = name; + this.occurrence = occurrence; + this.compilationUnit = compilationUnit; this.modifySharedDocumentCommandExecutorProvider = modifySharedDocumentCommandExecutorProvider; this.annotationEditFormatter = annotationEditFormatter; } - // ********** accessors ********** + // ********** Member implementation ********** - protected IMember getJdtMember() { - return this.jdtMember; + public ModifiedDeclaration getModifiedDeclaration(CompilationUnit astRoot) { + return new JDTModifiedDeclaration(this.getBodyDeclaration(astRoot)); } - public boolean wraps(IMember member) { - return this.jdtMember.exists() - && this.jdtMember.equals(member); + public ModifiedDeclaration getModifiedDeclaration() { + return this.getModifiedDeclaration(this.buildASTRoot()); } - /** - * this will return null for a top-level type - */ - protected Type declaringType() { - return this.declaringType; + public boolean matches(String memberName, int occur) { + return memberName.equals(this.name) && (occur == this.occurrence); } + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.name); + } - // ********** miscellaneous ********** - protected ICompilationUnit getCompilationUnit() { - return this.jdtMember.getCompilationUnit(); + // ********** internal ********** + + protected String getName_() { + return this.name; } - public String getName() { - return this.jdtMember.getElementName(); + protected int getOccurrence() { + return this.occurrence; } /** - * note: this creates a *new* AST + * this will return null for a top-level type */ - public CompilationUnit getAstRoot() { - return JDTTools.buildASTRoot(this.jdtMember); - } - - public ModifiedDeclaration getModifiedDeclaration() { - return this.getModifiedDeclaration(this.getAstRoot()); - } - - public ModifiedDeclaration getModifiedDeclaration(CompilationUnit astRoot) { - return new JDTModifiedDeclaration(this.getBodyDeclaration(astRoot)); + protected Type getDeclaringType() { + return this.declaringType; } - @Override - public String toString() { - return StringTools.buildToStringFor(this, this.getName()); - } // ********** editing ********** @@ -138,25 +156,24 @@ public abstract class JDTMember * - when editing via a plain text editor, make a working copy or else things are screwed * up the second time you edit through the XmlPersistence XmlProperties View */ - private void edit_(Editor editor) throws JavaModelException, BadLocationException { - ICompilationUnit compilationUnit = this.getCompilationUnit(); - if ( ! compilationUnit.isWorkingCopy()) { - compilationUnit.becomeWorkingCopy(null); + protected void edit_(Editor editor) throws JavaModelException, BadLocationException { + if ( ! this.compilationUnit.isWorkingCopy()) { + this.compilationUnit.becomeWorkingCopy(null); } - ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(compilationUnit.getResource().getFullPath(), LocationKind.NORMALIZE); + ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(this.compilationUnit.getResource().getFullPath(), LocationKind.NORMALIZE); boolean sharedDocument = (buffer != null); // documents are typically shared when they are already open in an editor IDocument doc = sharedDocument ? buffer.getDocument() : - new Document(compilationUnit.getBuffer().getContents()); + new Document(this.compilationUnit.getBuffer().getContents()); - CompilationUnit astRoot = this.getAstRoot(); + CompilationUnit astRoot = this.buildASTRoot(); astRoot.recordModifications(); editor.edit(this.getModifiedDeclaration(astRoot)); - TextEdit edits = astRoot.rewrite(doc, compilationUnit.getJavaProject().getOptions(true)); + TextEdit edits = astRoot.rewrite(doc, this.compilationUnit.getJavaProject().getOptions(true)); if (sharedDocument) { this.getModifySharedDocumentCommandExecutor().execute(new ModifySharedDocumentCommand(edits, doc)); } else { @@ -164,9 +181,9 @@ public abstract class JDTMember } if ( ! sharedDocument) { - compilationUnit.getBuffer().setContents(doc.get()); - compilationUnit.commitWorkingCopy(true, null); // true="force" - compilationUnit.discardWorkingCopy(); + this.compilationUnit.getBuffer().setContents(doc.get()); + this.compilationUnit.commitWorkingCopy(true, null); // true="force" + this.compilationUnit.discardWorkingCopy(); } } @@ -174,16 +191,16 @@ public abstract class JDTMember * apply the specified edits to the specified document, * reformatting the document if necessary */ - void applyEdits(TextEdit edits, IDocument doc) throws MalformedTreeException, BadLocationException { + protected void applyEdits(TextEdit edits, IDocument doc) throws MalformedTreeException, BadLocationException { edits.apply(doc, TextEdit.UPDATE_REGIONS); - this.getAnnotationEditFormatter().format(doc, edits); + this.annotationEditFormatter.format(doc, edits); } - private AnnotationEditFormatter getAnnotationEditFormatter() { - return this.annotationEditFormatter; + protected CompilationUnit buildASTRoot() { + return JDTTools.buildASTRoot(this.compilationUnit); } - private CommandExecutor getModifySharedDocumentCommandExecutor() { + protected CommandExecutor getModifySharedDocumentCommandExecutor() { return this.modifySharedDocumentCommandExecutorProvider.getCommandExecutor(); } @@ -194,11 +211,11 @@ public abstract class JDTMember * simple command that calls back to the member to apply the edits * in the same way as if the document were not shared */ - class ModifySharedDocumentCommand implements Command { + protected class ModifySharedDocumentCommand implements Command { private final TextEdit edits; private final IDocument doc; - ModifySharedDocumentCommand(TextEdit edits, IDocument doc) { + protected ModifySharedDocumentCommand(TextEdit edits, IDocument doc) { super(); this.edits = edits; this.doc = doc; diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMethodAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMethodAttribute.java index dc86ae772b..d0844d6606 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMethodAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTMethodAttribute.java @@ -10,19 +10,26 @@ package org.eclipse.jpt.core.internal.utility.jdt; import java.beans.Introspector; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.JavaModelException; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jpt.core.utility.TextRange; import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; import org.eclipse.jpt.core.utility.jdt.MethodAttribute; +import org.eclipse.jpt.core.utility.jdt.Type; import org.eclipse.jpt.utility.CommandExecutorProvider; +import org.eclipse.jpt.utility.JavaType; +import org.eclipse.jpt.utility.MethodSignature; +import org.eclipse.jpt.utility.internal.SimpleMethodSignature; /** - * Adapt and extend a jdt method. + * Adapt and extend a JDT method. * Attribute based on a Java property, e.g. * private int getFoo() { * return foo; @@ -30,68 +37,129 @@ import org.eclipse.jpt.utility.CommandExecutorProvider; * private void setFoo(int foo) { * this.foo = foo; * } - * - * For now we only hold the getter method, since that's where the - * annotations are put. */ public class JDTMethodAttribute extends JDTAttribute implements MethodAttribute { + /** we need the parameter types to build the method signature */ + private final JavaType[] parameterTypes; + - public JDTMethodAttribute(IMethod getMethod, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { - super(getMethod, modifySharedDocumentCommandExecutorProvider); + // ********** constructors ********** + + public static JDTMethodAttribute newInstance( + Type declaringType, + MethodSignature signature, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + return newInstance(declaringType, signature, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); } - - public JDTMethodAttribute(IMethod getMethod, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) { - super(getMethod, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); + + public static JDTMethodAttribute newInstance( + Type declaringType, + MethodSignature signature, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + return new JDTMethodAttribute(declaringType, signature, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); } - @Override - public IMethod getJdtMember() { - return (IMethod) super.getJdtMember(); + public JDTMethodAttribute( + Type declaringType, + MethodSignature methodSignature, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + this(declaringType, methodSignature, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); } - - // ********** Member implementation ********** + public JDTMethodAttribute( + Type declaringType, + MethodSignature methodSignature, + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + super(declaringType, methodSignature.getName(), occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); + this.parameterTypes = methodSignature.getParameterTypes(); + } + + /** + * constructor for testing + */ + public JDTMethodAttribute(Type declaringType, String name, String[] parameterTypeNames, int occurrence, ICompilationUnit compilationUnit) { + this(declaringType, new SimpleMethodSignature(name, parameterTypeNames), occurrence, compilationUnit, CommandExecutorProvider.Default.instance(), DefaultAnnotationEditFormatter.instance()); + } + + + // ********** Member/Attribute/MethodAttribute implementation ********** + + public IMethodBinding getBinding(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).resolveBinding(); + } public MethodDeclaration getBodyDeclaration(CompilationUnit astRoot) { - try { - return ASTNodeSearchUtil.getMethodDeclarationNode(getJdtMember(), astRoot); - } catch(JavaModelException e) { - throw new RuntimeException(e); + int count = 0; + for (MethodDeclaration methodDeclaration : this.getDeclaringTypeMethodDeclarations(astRoot)) { + if (this.matches(methodDeclaration)) { + count++; + if (count == this.getOccurrence()) { + return methodDeclaration; + } + } } + // return null if the method is no longer in the source code; + // this can happen when the context model has not yet + // been synchronized with the resource model but is still + // asking for an ASTNode (e.g. during a selection event) + return null; } - - public IMethodBinding getBinding(CompilationUnit astRoot) { - return getBodyDeclaration(astRoot).resolveBinding(); + + public boolean matches(MethodSignature signature, int occurrence) { + return this.matches(signature) && (occurrence == this.getOccurrence()); } - - public TextRange getNameTextRange(CompilationUnit astRoot) { - return new ASTNodeTextRange(getBodyDeclaration(astRoot).getName()); + + protected boolean matches(MethodSignature signature) { + return signature.getName().equals(this.getName_()) + && Arrays.equals(this.parameterTypes, signature.getParameterTypes()); } - // ********** Attribute implementation ********** + protected boolean matches(MethodDeclaration methodDeclaration) { + return this.matches(JDTTools.buildMethodSignature(methodDeclaration)); + } + + // minimize scope of suppressed warnings + @SuppressWarnings("unchecked") + protected static List<SingleVariableDeclaration> parameters(MethodDeclaration methodDeclaration) { + return methodDeclaration.parameters(); + } @Override - public boolean isMethod() { - return true; + public boolean matches(String memberName, int occurrence) { + throw new UnsupportedOperationException("Use #matches(org.eclipse.jdt.core.dom.MethodDeclaration, int)."); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + return new ASTNodeTextRange(this.getBodyDeclaration(astRoot).getName()); } /** - * "foo" returned for a method named "getFoo" or "isFoo" + * return "foo" for a method named "getFoo" or "isFoo" */ public String getAttributeName() { - String methodName = super.getName(); + String name = this.getName_(); int beginIndex = 0; - if (methodName.startsWith("get")) { + if (name.startsWith("get")) { beginIndex = 3; - } else if (methodName.startsWith("is")) { + } else if (name.startsWith("is")) { beginIndex = 2; } - return Introspector.decapitalize(methodName.substring(beginIndex)); + return Introspector.decapitalize(name.substring(beginIndex)); } - + public ITypeBinding getTypeBinding(CompilationUnit astRoot) { IMethodBinding methodBinding = getBodyDeclaration(astRoot).resolveBinding(); if (methodBinding != null) { @@ -99,4 +167,22 @@ public class JDTMethodAttribute } return null; } + + @Override + public boolean isMethod() { + return true; + } + + public boolean isPersistable(CompilationUnit astRoot) { + IMethodBinding binding = this.getBinding(astRoot); + return (binding == null) ? false : JPTTools.methodIsPersistablePropertyGetter(binding); + } + + + // ********** internal ********** + + protected MethodDeclaration[] getDeclaringTypeMethodDeclarations(CompilationUnit astRoot) { + return this.getDeclaringTypeDeclaration(astRoot).getMethods(); + } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTModifiedDeclaration.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTModifiedDeclaration.java index 361d1c2ec8..266fa7c8a0 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTModifiedDeclaration.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTModifiedDeclaration.java @@ -13,7 +13,6 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; @@ -88,10 +87,6 @@ public class JDTModifiedDeclaration return (ICompilationUnit) this.getCompilationUnit().getJavaElement(); } - public IType getType() { - return this.getCompilationUnit().getTypeRoot().findPrimaryType(); - } - /** * Return the declaration's annotations. */ diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTTools.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTTools.java index f440d5647d..2050011ede 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTTools.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTTools.java @@ -9,9 +9,9 @@ ******************************************************************************/ package org.eclipse.jpt.core.internal.utility.jdt; -import org.eclipse.jdt.core.IClassFile; +import java.util.List; + import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; @@ -22,62 +22,26 @@ 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; +import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.TypeLiteral; +import org.eclipse.jpt.utility.JavaType; +import org.eclipse.jpt.utility.MethodSignature; +import org.eclipse.jpt.utility.internal.SimpleJavaType; +import org.eclipse.jpt.utility.internal.SimpleMethodSignature; public class JDTTools { - // TODO get rid of the "lightweight" methods after reworking how - // ValidationMessages determine line numbers /** - * Build an AST for the specified member's compilation unit or - * (source-attached) class file. Build the AST without its bindings - * resolved. - */ - public static CompilationUnit buildLightweightASTRoot(IMember member) { - return buildASTRoot(member, false); - } - - /** - * Build an AST for the specified member's compilation unit or - * (source-attached) class file. Build the AST with its bindings + * Build an AST for the specified compilation unit with its bindings * resolved (and the resultant performance hit). */ - public static CompilationUnit buildASTRoot(IMember member) { - return buildASTRoot(member, true); - } - - /** - * Build an AST for the specified member's compilation unit or - * (source-attached) class file. - */ - private static CompilationUnit buildASTRoot(IMember member, boolean resolveBindings) { - return (member.isBinary()) ? - buildASTRoot(member.getClassFile(), resolveBindings) // the class file must have a source attachment - : - buildASTRoot(member.getCompilationUnit(), resolveBindings); - } - - public static CompilationUnit buildASTRoot(IClassFile classFile) { - return buildASTRoot(classFile, true); - } - - private static CompilationUnit buildASTRoot(IClassFile classFile, boolean resolveBindings) { - ASTParser parser = ASTParser.newParser(AST.JLS3); - parser.setSource(classFile); - parser.setResolveBindings(resolveBindings); - return (CompilationUnit) parser.createAST(null); - } - public static CompilationUnit buildASTRoot(ICompilationUnit compilationUnit) { - return buildASTRoot(compilationUnit, true); - } - - private static CompilationUnit buildASTRoot(ICompilationUnit compilationUnit, boolean resolveBindings) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setSource(compilationUnit); - parser.setResolveBindings(resolveBindings); - parser.setBindingsRecovery(true); //see bugs 196200, 222735 + parser.setResolveBindings(true); + parser.setBindingsRecovery(true); // see bugs 196200, 222735 return (CompilationUnit) parser.createAST(null); } @@ -128,4 +92,28 @@ public class JDTTools { return null; } + public static MethodSignature buildMethodSignature(MethodDeclaration methodDeclaration) { + return new SimpleMethodSignature( + methodDeclaration.getName().getFullyQualifiedName(), + buildParameterTypes(methodDeclaration) + ); + } + + public static JavaType[] buildParameterTypes(MethodDeclaration methodDeclaration) { + List<SingleVariableDeclaration> parameters = parameters(methodDeclaration); + int len = parameters.size(); + JavaType[] parameterTypes = new JavaType[len]; + for (int i = 0; i < len; i++) { + ITypeBinding type = parameters.get(i).getType().resolveBinding(); + parameterTypes[i] = new SimpleJavaType(type.getQualifiedName(), type.getDimensions()); + } + return parameterTypes; + } + + // minimize scope of suppressed warnings + @SuppressWarnings("unchecked") + private static List<SingleVariableDeclaration> parameters(MethodDeclaration methodDeclaration) { + return methodDeclaration.parameters(); + } + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTType.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTType.java index 7f276aca1c..22ca6c302b 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTType.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JDTType.java @@ -9,121 +9,167 @@ ******************************************************************************/ package org.eclipse.jpt.core.internal.utility.jdt; -import java.util.ArrayList; import java.util.List; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; -import org.eclipse.jdt.core.dom.BodyDeclaration; + +import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jpt.core.utility.TextRange; import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; import org.eclipse.jpt.core.utility.jdt.Type; import org.eclipse.jpt.utility.CommandExecutorProvider; +/** + * Adapt and extend a JDT type. + */ public class JDTType extends JDTMember implements Type { - public JDTType(IType type, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { - super(type, modifySharedDocumentCommandExecutorProvider); + /** + * constructor for the compilation unit's primary type + */ + public JDTType( + TypeDeclaration typeDeclaration, // exclude annotations and enums + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + this(typeDeclaration, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); } - public JDTType(IType type, CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, AnnotationEditFormatter annotationEditFormatter) { - super(type, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); + /** + * constructor for the compilation unit's primary type + */ + public JDTType( + TypeDeclaration typeDeclaration, // exclude annotations and enums + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + this(null, typeDeclaration, 1, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); } - @Override - public IType getJdtMember() { - return (IType) super.getJdtMember(); + /** + * constructor for nested types + */ + public JDTType( + Type declaringType, + TypeDeclaration typeDeclaration, // exclude annotations and enums + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider) { + this(declaringType, typeDeclaration, occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, DefaultAnnotationEditFormatter.instance()); } - public IType[] jdtTypes() { - try { - return getJdtMember().getTypes(); - } - catch(JavaModelException e) { - throw new RuntimeException(e); - } + /** + * constructor for nested types + */ + public JDTType( + Type declaringType, + TypeDeclaration typeDeclaration, // exclude annotations and enums + int occurrence, + ICompilationUnit compilationUnit, + CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, + AnnotationEditFormatter annotationEditFormatter) { + super(declaringType, typeDeclaration.getName().getFullyQualifiedName(), occurrence, compilationUnit, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); } - - public IField[] jdtFields() { - try { - return getJdtMember().getFields(); - } - catch(JavaModelException e) { - throw new RuntimeException(e); - } + + /** + * constructor for testing + */ + public JDTType(Type declaringType, String name, int occurrence, ICompilationUnit compilationUnit) { + super(declaringType, name, occurrence, compilationUnit, CommandExecutorProvider.Default.instance(), DefaultAnnotationEditFormatter.instance()); } - - public IMethod[] jdtMethods() { - try { - return getJdtMember().getMethods(); - } - catch(JavaModelException e) { - throw new RuntimeException(e); - } + + + // ********** Member/Type implementation ********** + + public ITypeBinding getBinding(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).resolveBinding(); } - - // ********** Member implementation ********** - public AbstractTypeDeclaration getBodyDeclaration(CompilationUnit astRoot) { - Type declaringType = this.declaringType(); - if (declaringType != null) { - return this.getTypeDeclaration(declaringType.getBodyDeclaration(astRoot)); - } - return this.getTypeDeclaration(this.types(astRoot)); + /** + * find the type's body declaration in the specified AST + */ + public TypeDeclaration getBodyDeclaration(CompilationUnit astRoot) { + Type declaringType = this.getDeclaringType(); + return (declaringType == null) ? + this.getTopLevelTypeDeclaration(astRoot) + : + this.getNestedTypeDeclaration(declaringType.getBodyDeclaration(astRoot)); } - - public AbstractTypeDeclaration getTypeDeclaration(AbstractTypeDeclaration declaringTypeDeclaration) { - return getTypeDeclaration(this.types(declaringTypeDeclaration)); + + public boolean isPersistable(CompilationUnit astRoot) { + ITypeBinding binding = this.getBinding(astRoot); + return (binding == null) ? false : JPTTools.typeIsPersistable(binding); } - - private AbstractTypeDeclaration getTypeDeclaration(List<AbstractTypeDeclaration> typeDeclarations) { - String name = this.getName(); - for (AbstractTypeDeclaration typeDeclaration : typeDeclarations) { - if (typeDeclaration.getName().getFullyQualifiedName().equals(name)) { - return typeDeclaration; - } - } - return null; + + public TextRange getNameTextRange(CompilationUnit astRoot) { + return new ASTNodeTextRange(this.getBodyDeclaration(astRoot).getName()); } - public ITypeBinding getBinding(CompilationUnit astRoot) { - return getBodyDeclaration(astRoot).resolveBinding(); + public TypeDeclaration[] getTypes(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).getTypes(); } - public TextRange getNameTextRange(CompilationUnit astRoot) { - return new ASTNodeTextRange(getBodyDeclaration(astRoot).getName()); + public FieldDeclaration[] getFields(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).getFields(); } - // ********** miscellaneous ********** + public MethodDeclaration[] getMethods(CompilationUnit astRoot) { + return this.getBodyDeclaration(astRoot).getMethods(); + } - @SuppressWarnings("unchecked") - protected List<AbstractTypeDeclaration> types(CompilationUnit astRoot) { - return astRoot.types(); + + // ********** internal ********** + + /** + * return the first top-level type in the specified AST with a matching name + */ + protected TypeDeclaration getTopLevelTypeDeclaration(CompilationUnit astRoot) { + return this.getTypeDeclaration(types(astRoot)); + } + + protected TypeDeclaration getTypeDeclaration(List<TypeDeclaration> typeDeclarations) { + return this.getTypeDeclaration(typeDeclarations.toArray(new TypeDeclaration[typeDeclarations.size()])); + } + + /** + * return the nested type with a matching name and occurrence + */ + protected TypeDeclaration getNestedTypeDeclaration(TypeDeclaration declaringTypeDeclaration) { + return this.getTypeDeclaration(declaringTypeDeclaration.getTypes()); } - - protected List<AbstractTypeDeclaration> types(AbstractTypeDeclaration typeDeclaration) { - List<AbstractTypeDeclaration> typeDeclarations = new ArrayList<AbstractTypeDeclaration>(); - for (BodyDeclaration bodyDeclaration : bodyDeclarations(typeDeclaration)) - if (bodyDeclaration.getNodeType() == ASTNode.TYPE_DECLARATION || - bodyDeclaration.getNodeType() == ASTNode.ANNOTATION_TYPE_DECLARATION || - bodyDeclaration.getNodeType() == ASTNode.ENUM_DECLARATION) { - typeDeclarations.add((AbstractTypeDeclaration) bodyDeclaration); + + /** + * return the type declaration corresponding to the type from the specified + * set of type declarations (match name and occurrence) + */ + protected TypeDeclaration getTypeDeclaration(TypeDeclaration[] typeDeclarations) { + String name = this.getName_(); + int occurrence = this.getOccurrence(); + int count = 0; + for (TypeDeclaration typeDeclaration : typeDeclarations) { + if (typeDeclaration.getName().getFullyQualifiedName().equals(name)) { + count++; + if (count == occurrence) { + return typeDeclaration; + } } - return typeDeclarations; + } + // return null if the type is no longer in the source code; + // this can happen when the context model has not yet + // been synchronized with the resource model but is still + // asking for an ASTNode (e.g. during a selection event) + return null; } - + + // minimize scope of suppressed warnings @SuppressWarnings("unchecked") - protected List<BodyDeclaration> bodyDeclarations(AbstractTypeDeclaration typeDeclaration) { - return typeDeclaration.bodyDeclarations(); + protected static List<TypeDeclaration> types(CompilationUnit astRoot) { + return astRoot.types(); } - } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JPTTools.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JPTTools.java index 8726b19526..dcaed04e05 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JPTTools.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/JPTTools.java @@ -179,8 +179,4 @@ public class JPTTools { return true; } - public static boolean typeIsAbstract(ITypeBinding typeBinding) { - return Modifier.isAbstract(typeBinding.getModifiers()); - } - } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/NodeFinder.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/NodeFinder.java deleted file mode 100644 index 04d0895690..0000000000 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/jdt/NodeFinder.java +++ /dev/null @@ -1,111 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jpt.core.internal.utility.jdt; - -import org.eclipse.jdt.core.ISourceRange; -import org.eclipse.jdt.core.dom.ASTNode; -/** - * For a give range finds the node covered and the node covering. - * - * @since 2.1 - */ -//copied from org.eclipse.jdt.internal.corext.dom.NodeFinder -//deleted code to limit the number of classes I had to copy -public class NodeFinder extends GenericVisitor { - - /** - * A visitor that maps a selection to a given ASTNode. The result node is - * determined as follows: - * <ul> - * <li>first the visitor tries to find a node with the exact start and length</li> - * <li>if no such node exists than the node that encloses the range defined by - * start and end is returned.</li> - * <li>if the length is zero than also nodes are considered where the node's - * start or end position matches <code>start</code>.</li> - * <li>otherwise <code>null</code> is returned.</li> - * </ul> - * - * @param root the root node from which the search starts - * @param start the start offset - * @param length the length - * - * @return the result node - * - * @since 2.1 - */ - public static ASTNode perform(ASTNode root, int start, int length) { - NodeFinder finder= new NodeFinder(start, length); - root.accept(finder); - ASTNode result= finder.getCoveredNode(); - if (result == null || result.getStartPosition() != start || result.getLength() != length) { - return finder.getCoveringNode(); - } - return result; - } - - public static ASTNode perform(ASTNode root, ISourceRange range) { - return perform(root, range.getOffset(), range.getLength()); - } - - private int fStart; - private int fEnd; - - private ASTNode fCoveringNode; - private ASTNode fCoveredNode; - - public NodeFinder(int offset, int length) { - super(true); // include Javadoc tags - fStart= offset; - fEnd= offset + length; - } - - @Override - protected boolean visitNode(ASTNode node) { - int nodeStart= node.getStartPosition(); - int nodeEnd= nodeStart + node.getLength(); - if (nodeEnd < fStart || fEnd < nodeStart) { - return false; - } - if (nodeStart <= fStart && fEnd <= nodeEnd) { - fCoveringNode= node; - } - if (fStart <= nodeStart && nodeEnd <= fEnd) { - if (fCoveringNode == node) { // nodeStart == fStart && nodeEnd == fEnd - fCoveredNode= node; - return true; // look further for node with same length as parent - } else if (fCoveredNode == null) { // no better found - fCoveredNode= node; - } - return false; - } - return true; - } - - /** - * Returns the covered node. If more than one nodes are covered by the selection, the - * returned node is first covered node found in a top-down traversal of the AST - * @return ASTNode - */ - public ASTNode getCoveredNode() { - return fCoveredNode; - } - - /** - * Returns the covering node. If more than one nodes are covering the selection, the - * returned node is last covering node found in a top-down traversal of the AST - * @return ASTNode - */ - public ASTNode getCoveringNode() { - return fCoveringNode; - } - -} - diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResource.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResource.java index 565c5952d9..cfee949099 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResource.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResource.java @@ -131,6 +131,8 @@ public abstract class JpaXmlResource extends TranslatorResourceImpl public abstract void javaElementChanged(ElementChangedEvent event); + public abstract void updateFromResource(); + public JpaXmlResourceModel getResourceModel() { return this.resourceModel; } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResourceModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResourceModel.java index f5c0060c98..42fabbd300 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResourceModel.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/common/JpaXmlResourceModel.java @@ -50,21 +50,24 @@ public abstract class JpaXmlResourceModel extends AbstractResourceModel return new ReloadListener(resource); } - @Override public JpaXmlResource getResource() { return this.resource; } public void javaElementChanged(ElementChangedEvent event) { - getResource().javaElementChanged(event); + this.resource.javaElementChanged(event); + } + + public void updateFromResource() { + this.resource.updateFromResource(); } public void addResourceModelChangeListener(ResourceModelListener listener) { - getResource().addResourceModelChangeListener(listener); + this.resource.addResourceModelChangeListener(listener); } public void removeResourceModelChangeListener(ResourceModelListener listener) { - getResource().removeResourceModelChangeListener(listener); + this.resource.removeResourceModelChangeListener(listener); } @Override diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceModel.java index 00b803af45..22bc7d0427 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceModel.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceModel.java @@ -22,7 +22,7 @@ import org.eclipse.jpt.core.ResourceModel; */ public interface JavaResourceModel extends ResourceModel { - JpaCompilationUnit getResource(); + JpaCompilationUnit getJpaCompilationUnit(); void resourceChanged(); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceNode.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceNode.java index d0402fd7c3..9574f0874e 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceNode.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourceNode.java @@ -10,9 +10,7 @@ package org.eclipse.jpt.core.resource.java; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jpt.core.JpaAnnotationProvider; import org.eclipse.jpt.core.utility.TextRange; -import org.eclipse.jpt.utility.CommandExecutorProvider; import org.eclipse.jpt.utility.model.Model; /** @@ -24,22 +22,16 @@ import org.eclipse.jpt.utility.model.Model; * pioneering adopters on the understanding that any code that uses this API * will almost certainly be broken (repeatedly) as the API evolves. */ -public interface JavaResourceNode extends Model -{ +public interface JavaResourceNode extends Model { + void initialize(CompilationUnit astRoot); - + JavaResourceModel getResourceModel(); - + JpaCompilationUnit getJpaCompilationUnit(); - - JpaAnnotationProvider getAnnotationProvider(); - - CommandExecutorProvider getModifySharedDocumentCommandExecutorProvider(); - + void updateFromJava(CompilationUnit astRoot); - - /** - * Return the ITextRange - */ + TextRange getTextRange(CompilationUnit astRoot); + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentMember.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentMember.java index ef35bd26f9..234cbd259b 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentMember.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentMember.java @@ -11,9 +11,9 @@ package org.eclipse.jpt.core.resource.java; import java.util.Iterator; import java.util.ListIterator; -import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.core.utility.TextRange; +import org.eclipse.jpt.utility.MethodSignature; /** * @@ -34,8 +34,7 @@ public interface JavaResourcePersistentMember extends JavaResourceNode * <p>Does not return duplicate annotations as this error is handled by the java compiler. */ <T extends JavaResourceNode> Iterator<T> mappingAnnotations(); - - String MAPPING_ANNOTATIONS_COLLECTION = "mappingAnnotationsCollection"; + String MAPPING_ANNOTATIONS_COLLECTION = "mappingAnnotations"; int mappingAnnotationsSize(); /** @@ -43,7 +42,6 @@ public interface JavaResourcePersistentMember extends JavaResourceNode * In the case of multiples the first one will be returned as defined by the order of * {@link org.eclipse.jpt.core.internal.platform.GenericJpaPlatform#typeMappingAnnotationDefinitions()} or * {@link org.eclipse.jpt.core.internal.platform.GenericJpaPlatform#attributeMappingAnnotationDefinitions()} - * @return */ JavaResourceNode getMappingAnnotation(); @@ -53,7 +51,6 @@ public interface JavaResourcePersistentMember extends JavaResourceNode * and "javax.persistence.MappedSuperclass" * Return the first if there are duplicates in the source code * @param annotationName - fully qualified annotation name - * @return */ //TODO not sure we need this API, first 2 seem sufficient JavaResourceNode getMappingAnnotation(String annotationName); @@ -74,7 +71,7 @@ public interface JavaResourcePersistentMember extends JavaResourceNode */ <T extends JavaResourceNode> Iterator<T> annotations(); - String ANNOTATIONS_COLLECTION = "annotationsCollection"; + String ANNOTATIONS_COLLECTION = "annotations"; int annotationsSize(); @@ -92,8 +89,6 @@ public interface JavaResourcePersistentMember extends JavaResourceNode /** * Returns the <code>JavaResource</code> with this fully qualifed annotation name. * Return the first if there are duplicates in the source code. - * @param annotationName - * @return */ JavaResourceNode getAnnotation(String annotationName); @@ -101,8 +96,6 @@ public interface JavaResourcePersistentMember extends JavaResourceNode * Returns the <code>JavaResource</code> with this fully qualifed annotation name. * Return the first if there are duplicates in the source code. Will not return null, * but a null Object instead if no annotation with this name exists in the java source. - * @param annotationName - * @return */ JavaResourceNode getNonNullAnnotation(String annotationName); @@ -110,8 +103,6 @@ public interface JavaResourcePersistentMember extends JavaResourceNode * Return a null implementation of <code>JavaResourceNode</code> with this fully qualifed annotation name. * The corresponding AnnotationDefinition needs to implement buildNullAnnotation() * {@link AnnotationDefinition#buildNullAnnotation(JavaResourcePersistentMember, org.eclipse.jpt.core.internal.jdtutility.Member)} - * @param annotationName - * @return */ JavaResourceNode getNullMappingAnnotation(String annotationName); @@ -142,10 +133,9 @@ public interface JavaResourcePersistentMember extends JavaResourceNode /** * Return whether the underlying JDT member is persistable according to the JPA spec - * @return */ boolean isPersistable(); - String PERSISTABLE_PROPERTY = "persistableProperty"; + String PERSISTABLE_PROPERTY = "persistable"; /** * Return whether the underlying JDT member is currently annotated as being persistent @@ -154,13 +144,17 @@ public interface JavaResourcePersistentMember extends JavaResourceNode boolean isPersisted(); /** - * Return true if this JavaPersistentResource represents the underlying JDT IMeber - * @param member - * @return + * Return whether the Java resource persistent member is for the specified + * member. */ - boolean isFor(IMember member); - - + boolean isFor(String memberName, int occurrence); + + /** + * Return whether the Java resource persistent member is for the specified + * method. + */ + boolean isFor(MethodSignature methodSignature, int occurrence); + /** * return the text range for the name of the persistent resource */ diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentType.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentType.java index 114692a64a..f71a3f3849 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentType.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JavaResourcePersistentType.java @@ -24,25 +24,23 @@ import org.eclipse.jpt.core.utility.jdt.Member; public interface JavaResourcePersistentType extends JavaResourcePersistentMember { /** - * Return only the persistable nestedTypes + * Return only the immediately nested persistable nestedTypes */ Iterator<JavaResourcePersistentType> nestedTypes(); - String NESTED_TYPES_COLLECTION = "nestedTypesCollection"; + String NESTED_TYPES_COLLECTION = "nestedTypes"; /** * Return only the persistable attributes, those that respond true to * {@link JavaResourcePersistentAttribute#isPersistable()} * This returns fields and properties - * @return */ Iterator<JavaResourcePersistentAttribute> attributes(); - String ATTRIBUTES_COLLECTION = "attributesCollection"; + String ATTRIBUTES_COLLECTION = "attributes"; /** * Return only the persistable fields, those that respond true to * {@link JavaResourcePersistentAttribute#isPersistable()} * This returns filters out all properties and only returns fields - * @return */ Iterator<JavaResourcePersistentAttribute> fields(); @@ -50,32 +48,32 @@ public interface JavaResourcePersistentType extends JavaResourcePersistentMember * Return only the persistable fields, those that respond true to * {@link JavaResourcePersistentAttribute#isPersistable()} * This returns filters out all fields and only returns properties - * @return */ Iterator<JavaResourcePersistentAttribute> properties(); + // TODO rename to getJavaResourcePersistentType(String) JavaResourcePersistentType getJavaPersistentTypeResource(String fullyQualifiedTypeName); /** * Return the fully qualified type name */ String getQualifiedName(); - String QUALIFIED_NAME_PROPERTY = "qualifiedNameProperty"; + String QUALIFIED_NAME_PROPERTY = "qualifiedName"; /** * Return the fully unqualified type name */ String getName(); - String NAME_PROPERTY = "nameProperty"; + String NAME_PROPERTY = "name"; String getSuperClassQualifiedName(); - String SUPER_CLASS_QUALIFIED_NAME_PROPERTY = "superClassQualifiedNameProperty"; + String SUPER_CLASS_QUALIFIED_NAME_PROPERTY = "superClassQualifiedName"; AccessType getAccess(); - String ACCESS_PROPERTY = "accessProperty"; + String ACCESS_PROPERTY = "access"; boolean isAbstract(); - String ABSTRACT_PROPERTY = "abstractProperty"; + String ABSTRACT_PROPERTY = "abstract"; Member getMember(); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JpaCompilationUnit.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JpaCompilationUnit.java index 8d4a96ed81..d6e88f793e 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JpaCompilationUnit.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/java/JpaCompilationUnit.java @@ -10,7 +10,9 @@ package org.eclipse.jpt.core.resource.java; import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jpt.core.JpaAnnotationProvider; import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; +import org.eclipse.jpt.utility.CommandExecutorProvider; /** * @@ -26,9 +28,15 @@ public interface JpaCompilationUnit extends JavaResourceNode { ICompilationUnit getCompilationUnit(); JavaResourcePersistentType getPersistentType(); + String PERSISTENT_TYPE_PROPERTY = "persistentType"; + // TODO rename getJavaResourcePersistentType(String) JavaResourcePersistentType getJavaPersistentTypeResource(String typeName); + JpaAnnotationProvider getAnnotationProvider(); + + CommandExecutorProvider getModifySharedDocumentCommandExecutorProvider(); + AnnotationEditFormatter getAnnotationEditFormatter(); void resourceChanged(); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/orm/OrmResource.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/orm/OrmResource.java index 0aa1f932ed..af0199ce33 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/orm/OrmResource.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/orm/OrmResource.java @@ -41,7 +41,12 @@ public class OrmResource extends JpaXmlResource @Override public void javaElementChanged(ElementChangedEvent event) { - // TODO Auto-generated method stub + // TODO + } + + @Override + public void updateFromResource() { + // TODO } public XmlEntityMappings getEntityMappings() { diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/persistence/PersistenceResource.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/persistence/PersistenceResource.java index e8e5450eda..2089873bf7 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/persistence/PersistenceResource.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/persistence/PersistenceResource.java @@ -41,7 +41,12 @@ public class PersistenceResource extends JpaXmlResource @Override public void javaElementChanged(ElementChangedEvent event) { - // TODO Auto-generated method stub + // TODO + } + + @Override + public void updateFromResource() { + // TODO } public XmlPersistence getPersistence() { diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Attribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Attribute.java index ce89b36409..c4e917a82c 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Attribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Attribute.java @@ -13,6 +13,8 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ITypeBinding; /** + * Attributes are either represented by fields ('foo') or properties/method + * pairs ('getFoo()'/'setFoo()'). * * Provisional API: This interface is part of an interim API that is still * under development and expected to change significantly before reaching @@ -24,6 +26,11 @@ import org.eclipse.jdt.core.dom.ITypeBinding; */ public interface Attribute extends Member { + /** + * Return the attribute's name, as opposed to the member's name + * (e.g. "getFoo()" returns "foo"). + */ + // TODO rename to getName()? String getAttributeName(); /** @@ -32,8 +39,15 @@ public interface Attribute extends Member { */ ITypeBinding getTypeBinding(CompilationUnit astRoot); + /** + * Return whether the attribute is a field. + */ boolean isField(); + /** + * Return whether the attribute is a property/method pair. + */ + // TODO rename to isProperty()? boolean isMethod(); } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/FieldAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/FieldAttribute.java index 2d92f48d94..4046cf9f49 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/FieldAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/FieldAttribute.java @@ -10,9 +10,11 @@ package org.eclipse.jpt.core.utility.jdt; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IVariableBinding; /** + * Field attribute: just some covariant overrides. * * Provisional API: This interface is part of an interim API that is still * under development and expected to change significantly before reaching @@ -24,6 +26,14 @@ import org.eclipse.jdt.core.dom.IVariableBinding; */ public interface FieldAttribute extends Attribute { + /** + * Covariant override. + */ IVariableBinding getBinding(CompilationUnit astRoot); + /** + * Covariant override. + */ + FieldDeclaration getBodyDeclaration(CompilationUnit astRoot); + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Member.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Member.java index 0d1a28831f..d36bbf6862 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Member.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Member.java @@ -9,13 +9,14 @@ ******************************************************************************/ package org.eclipse.jpt.core.utility.jdt; -import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jpt.core.utility.TextRange; /** + * Dali manipulates annotations on members (types, fields, and methods). + * This interface simplifies those manipulations. * * Provisional API: This interface is part of an interim API that is still * under development and expected to change significantly before reaching @@ -27,23 +28,47 @@ import org.eclipse.jpt.core.utility.TextRange; */ public interface Member { - boolean wraps(IMember member); - - CompilationUnit getAstRoot(); - /** - * Return the member's body declaration. + * Return the member's body declaration from the specified AST. + * This can be null if the member is no longer present in the AST + * because the source has been changed in another thread. */ BodyDeclaration getBodyDeclaration(CompilationUnit astRoot); + /** + * Return the member's binding from the specified AST. + */ IBinding getBinding(CompilationUnit astRoot); + /** + * Return the member's "modified" declaration from the specified AST. + */ + ModifiedDeclaration getModifiedDeclaration(CompilationUnit astRoot); + + /** + * Return the member's "modified" declaration from a newly-generated AST. + */ ModifiedDeclaration getModifiedDeclaration(); - ModifiedDeclaration getModifiedDeclaration(CompilationUnit astRoot); + /** + * Return whether the attribute is a persistable field or property getter. + */ + boolean isPersistable(CompilationUnit astRoot); + + /** + * Return whether the member matches the specified member + * and occurrence. + */ + boolean matches(String memberName, int occurrence); + /** + * Return the member's name text range from the specified AST. + */ TextRange getNameTextRange(CompilationUnit astRoot); + /** + * Edit the member's declaration using the specified editor. + */ void edit(Editor editor); @@ -51,12 +76,13 @@ public interface Member { /** * This interface defines a callback that is invoked when the member's - * compilation unit is in a state to be manipulated. + * compilation unit/AST is in a state to be manipulated. */ public interface Editor { /** - * Edit the specified declaration. + * Edit the specified declaration. Any changes made to the declaration + * will be captured and applied to the member's compilation unit. */ void edit(ModifiedDeclaration declaration); diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/MethodAttribute.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/MethodAttribute.java index 9736c1d63a..4637ab76cf 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/MethodAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/MethodAttribute.java @@ -11,8 +11,11 @@ package org.eclipse.jpt.core.utility.jdt; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jpt.utility.MethodSignature; /** + * Property attribute: just some covariant overrides. * * Provisional API: This interface is part of an interim API that is still * under development and expected to change significantly before reaching @@ -22,8 +25,22 @@ import org.eclipse.jdt.core.dom.IMethodBinding; * * This interface is not intended to be implemented by clients. */ +// TODO rename PropertyAttribute? public interface MethodAttribute extends Attribute { + /** + * Covariant override. + */ IMethodBinding getBinding(CompilationUnit astRoot); + /** + * Covariant override. + */ + MethodDeclaration getBodyDeclaration(CompilationUnit astRoot); + + /** + * This method must be used instead of Member#matches(String, int). + */ + boolean matches(MethodSignature signature, int occurrence); + } diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Type.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Type.java index 5931c9e38f..26726d98a7 100644 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Type.java +++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/utility/jdt/Type.java @@ -9,14 +9,14 @@ ******************************************************************************/ package org.eclipse.jpt.core.utility.jdt; -import org.eclipse.jdt.core.IField; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclaration; /** + * Type: just some covariant overrides. * * Provisional API: This interface is part of an interim API that is still * under development and expected to change significantly before reaching @@ -28,14 +28,29 @@ import org.eclipse.jdt.core.dom.ITypeBinding; */ public interface Type extends Member { + /** + * Covariant override. + */ ITypeBinding getBinding(CompilationUnit astRoot); - IType[] jdtTypes(); - - IField[] jdtFields(); - - IMethod[] jdtMethods(); - - AbstractTypeDeclaration getBodyDeclaration(CompilationUnit astRoot); + /** + * Covariant override. + */ + TypeDeclaration getBodyDeclaration(CompilationUnit astRoot); + + /** + * Return the type's nested types (does not include annotations or enums). + */ + TypeDeclaration[] getTypes(CompilationUnit astRoot); + + /** + * Return the type's fields. + */ + FieldDeclaration[] getFields(CompilationUnit astRoot); + + /** + * Return the type's methods. + */ + MethodDeclaration[] getMethods(CompilationUnit astRoot); } diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/DefaultJpaSelection.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/DefaultJpaSelection.java index a5dccd080d..4f64a64780 100644 --- a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/DefaultJpaSelection.java +++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/DefaultJpaSelection.java @@ -11,13 +11,17 @@ package org.eclipse.jpt.ui.internal.selection; import org.eclipse.jpt.core.JpaStructureNode; +/** + * Straightforward implementation of the JpaSelection interface. + */ public class DefaultJpaSelection implements JpaSelection { - private JpaStructureNode selectedNode; + private final JpaStructureNode selectedNode; public DefaultJpaSelection(JpaStructureNode selectedNode) { + super(); if (selectedNode == null) { throw new NullPointerException("A 'selectedNode' is required; otherwise use NULL_SELECTION."); } @@ -36,11 +40,11 @@ public class DefaultJpaSelection @Override public boolean equals(Object obj) { - if (! (obj instanceof DefaultJpaSelection)) { + if (! (obj instanceof JpaSelection)) { return false; } - - return this.selectedNode.equals(((DefaultJpaSelection) obj).selectedNode); + JpaSelection other = (JpaSelection) obj; + return ( ! other.isEmpty()) && this.selectedNode.equals(other.getSelectedNode()); } @Override @@ -52,4 +56,5 @@ public class DefaultJpaSelection public String toString() { return this.selectedNode.toString(); } + } diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/TextEditorSelectionParticipant.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/TextEditorSelectionParticipant.java index 1178f05401..27046fcedc 100644 --- a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/TextEditorSelectionParticipant.java +++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/selection/TextEditorSelectionParticipant.java @@ -49,7 +49,7 @@ public class TextEditorSelectionParticipant this.editorInputListener = new EditorInputListener(); this.textEditor.addPropertyListener(this.editorInputListener); this.editorSelectionListener = new EditorSelectionListener(); - this.postSelectionProvider().addPostSelectionChangedListener(this.editorSelectionListener); + this.getPostSelectionProvider().addPostSelectionChangedListener(this.editorSelectionListener); this.currentSelection = this.calculateSelection(); } @@ -61,16 +61,16 @@ public class TextEditorSelectionParticipant public void selectionChanged(JpaSelectionEvent evt) { JpaSelection newSelection = evt.getSelection(); - + if ((newSelection == JpaSelection.NULL_SELECTION) || newSelection.equals(this.currentSelection)) { return; } - - if (getActiveTextEditor() != textEditor) { + + if (getActiveTextEditor() != this.textEditor) { return; } - + this.forwardSelection = false; TextRange textRange = newSelection.getSelectedNode().getSelectionTextRange(); if (textRange != null) { @@ -86,54 +86,57 @@ public class TextEditorSelectionParticipant public void dispose() { this.textEditor.removePropertyListener(this.editorInputListener); - this.postSelectionProvider().removePostSelectionChangedListener(this.editorSelectionListener); + this.getPostSelectionProvider().removePostSelectionChangedListener(this.editorSelectionListener); } // ********** internal methods ********** - private JpaSelection calculateSelection() { + protected JpaSelection calculateSelection() { ISelection selection = this.textEditor.getSelectionProvider().getSelection(); if (! (selection instanceof ITextSelection)) { return JpaSelection.NULL_SELECTION; } - JpaFile jpaFile = this.jpaFile(); + JpaFile jpaFile = this.getJpaFile(); if (jpaFile == null) { return JpaSelection.NULL_SELECTION; } - JpaStructureNode selectedNode = jpaFile.getStructureNode(((ITextSelection) selection).getOffset()); - if (selectedNode == null) { - return JpaSelection.NULL_SELECTION; - } + // the resource model might be out of synch when we get this event + // so we force it to update before we ask it for the "selected node"; + // TODO synchronously update the context model? + jpaFile.updateFromResource(); + return this.buildSelection(jpaFile.getStructureNode(((ITextSelection) selection).getOffset())); + } - return new DefaultJpaSelection(selectedNode); + protected JpaSelection buildSelection(JpaStructureNode selectedNode) { + return (selectedNode == null) ? JpaSelection.NULL_SELECTION : new DefaultJpaSelection(selectedNode); } - - private IWorkbenchPage getActivePage() { - return textEditor.getEditorSite().getWorkbenchWindow().getActivePage(); + + protected IWorkbenchPage getActivePage() { + return this.textEditor.getEditorSite().getWorkbenchWindow().getActivePage(); } - private IWorkbenchPart getActivePart() { + protected IWorkbenchPart getActivePart() { IWorkbenchPage activePage = getActivePage(); return (activePage == null) ? null: activePage.getActivePart(); } - private IEditorPart getActiveEditor() { + protected IEditorPart getActiveEditor() { IWorkbenchPage activePage = getActivePage(); return (activePage == null) ? null: activePage.getActiveEditor(); } - private ITextEditor getActiveTextEditor() { + protected ITextEditor getActiveTextEditor() { return getTextEditor(getActiveEditor()); } - private ITextEditor getTextEditor(IWorkbenchPart part) { + protected ITextEditor getTextEditor(IWorkbenchPart part) { return (part == null) ? null : (ITextEditor) part.getAdapter(ITextEditor.class); } - private JpaFile jpaFile() { + protected JpaFile getJpaFile() { IEditorInput input = this.textEditor.getEditorInput(); if ( ! (input instanceof IFileEditorInput)) { return null; @@ -141,38 +144,30 @@ public class TextEditorSelectionParticipant return JptCorePlugin.getJpaFile(((IFileEditorInput) input).getFile()); } - private IPostSelectionProvider postSelectionProvider() { + protected IPostSelectionProvider getPostSelectionProvider() { return (IPostSelectionProvider) this.textEditor.getSelectionProvider(); } // ********** listener callbacks ********** - void editorInputChanged() { - JpaSelection newSelection = this.calculateSelection(); - if (newSelection.equals(this.currentSelection)) { - return; - } - this.currentSelection = newSelection; - - if (this.forwardSelection) { - this.selectionManager.select(newSelection, this); - } + protected void editorInputChanged() { + this.selectionChanged(); } - void editorSelectionChanged(SelectionChangedEvent event) { + protected void editorSelectionChanged(SelectionChangedEvent event) { // This is a bit kludgey. We check to see if the selection event // occurred when a participating part is active (and so, ostensibly, // *because* of the participating part). If so, we reselect the valid // text. IWorkbenchPart activePart = getActivePart(); - if (getTextEditor(activePart) != textEditor && selectionManager.isRegistered(activePart)) { - if (currentSelection.isEmpty()) { + if (getTextEditor(activePart) != this.textEditor && this.selectionManager.isRegistered(activePart)) { + if (this.currentSelection.isEmpty()) { return; } this.forwardSelection = false; - TextRange textRange = currentSelection.getSelectedNode().getSelectionTextRange(); + TextRange textRange = this.currentSelection.getSelectedNode().getSelectionTextRange(); if (textRange != null) { this.textEditor.selectAndReveal(textRange.getOffset(), textRange.getLength()); } @@ -181,12 +176,16 @@ public class TextEditorSelectionParticipant return; } + this.selectionChanged(); + } + + protected void selectionChanged() { JpaSelection newSelection = this.calculateSelection(); if (newSelection.equals(this.currentSelection)) { return; } this.currentSelection = newSelection; - + if (this.forwardSelection) { this.selectionManager.select(newSelection, this); } @@ -195,8 +194,8 @@ public class TextEditorSelectionParticipant // ********** listeners ********** - private class EditorInputListener implements IPropertyListener { - EditorInputListener() { + protected class EditorInputListener implements IPropertyListener { + protected EditorInputListener() { super(); } public void propertyChanged(Object source, int propId) { @@ -208,8 +207,8 @@ public class TextEditorSelectionParticipant } - private class EditorSelectionListener implements ISelectionChangedListener { - EditorSelectionListener() { + protected class EditorSelectionListener implements ISelectionChangedListener { + protected EditorSelectionListener() { super(); } public void selectionChanged(SelectionChangedEvent event) { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java index 03b62531e4..ea1f5c68ea 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/CommandExecutorProvider.java @@ -27,4 +27,27 @@ public interface CommandExecutorProvider { */ CommandExecutor getCommandExecutor(); + + /** + * Straightforward implementation of the command executor provider + * interface the returns the default command executor. + */ + final class Default implements CommandExecutorProvider { + public static final CommandExecutorProvider INSTANCE = new Default(); + public static CommandExecutorProvider instance() { + return INSTANCE; + } + // ensure single instance + private Default() { + super(); + } + public CommandExecutor getCommandExecutor() { + return CommandExecutor.Default.instance(); + } + @Override + public String toString() { + return "CommandExecutorProvider.Default"; + } + } + } diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java new file mode 100644 index 0000000000..08fcbc21d3 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/MethodSignature.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2008 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.utility; + +import java.io.PrintWriter; + +/** + * This interface describes a Java method signature; i.e. its "name" + * and its "parameter types". The parameter types are referenced by name, + * allowing us to reference classes that are not (or cannot be) loaded. + * + * Provisional API: This interface is part of an interim API that is still + * under development and expected to change significantly before reaching + * stability. It is available at this early stage to solicit feedback from + * pioneering adopters on the understanding that any code that uses this API + * will almost certainly be broken (repeatedly) as the API evolves. + * + * This interface is not intended to be implemented by clients. + */ +public interface MethodSignature + extends Comparable<MethodSignature> +{ + + /** + * Return the method's name. + */ + String getName(); + + /** + * Return the method's parameter types. + */ + JavaType[] getParameterTypes(); + + boolean equals(String otherName, JavaType[] otherParameterTypes); + + boolean equals(MethodSignature other); + + /** + * Return a string representation of the method signature: + * "foo(int, java.lang.String)" + */ + String getSignature(); + + /** + * Append a string representation of the method signature: + * "foo(int, java.lang.String)" + */ + void appendSignatureTo(StringBuilder sb); + + /** + * Print a string representation of the method signature: + * "foo(int, java.lang.String)" + */ + void printSignatureOn(PrintWriter pw); + +} diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java index faa3177b91..3ec253f142 100644 --- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleJavaType.java @@ -144,7 +144,7 @@ public final class SimpleJavaType @Override public boolean equals(Object o) { - return (o instanceof JavaType) ? this.equals((JavaType) o) : false; + return (this == o) ? true : (o instanceof JavaType) ? this.equals((JavaType) o) : false; } @Override @@ -217,6 +217,9 @@ public final class SimpleJavaType return sb.toString(); } + + // ********** cloning ********** + @Override public Object clone() { try { diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java new file mode 100644 index 0000000000..48c5481c47 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleMethodSignature.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2008 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.utility.internal; + +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Method; +import java.text.Collator; +import java.util.Arrays; + +import org.eclipse.jpt.utility.JavaType; +import org.eclipse.jpt.utility.MethodSignature; + +/** + * Straightforward implementation of the MethodSignature interface. + */ +public final class SimpleMethodSignature + implements MethodSignature, Cloneable, Serializable +{ + private final String name; + + /** + * store the parameter types as names, so we can reference classes + * that are not loaded + */ + private final JavaType[] parameterTypes; + + private static final long serialVersionUID = 1L; + + public static final JavaType[] EMPTY_PARAMETER_TYPES = new JavaType[0]; + + + // ********** constructors ********** + + /** + * Construct a method signature with the specified name and + * no parameter types. + */ + public SimpleMethodSignature(String name) { + this(name, EMPTY_PARAMETER_TYPES); + } + + /** + * Construct a method signature with the specified name and parameter + * types. + */ + public SimpleMethodSignature(String name, JavaType... parameterTypes) { + super(); + if ((name == null) || (name.length() == 0)) { + throw new IllegalArgumentException("The name is required."); + } + if (parameterTypes == null) { + throw new IllegalArgumentException("The parameter types are required."); + } + checkParameterTypes(parameterTypes); + this.name = name; + this.parameterTypes = parameterTypes; + } + + private static void checkParameterTypes(JavaType[] parameterTypes) { + for (int i = 0; i < parameterTypes.length; i++) { + if (parameterTypes[i] == null) { + throw new IllegalArgumentException("Missing parameter type: " + i); + } + if (parameterTypes[i].getElementTypeName().equals(void.class.getName())) { + throw new IllegalArgumentException("A parameter type of 'void' is not allowed: " + i); + } + } + } + + /** + * Construct a method signature with the specified name and parameter + * types. + */ + public SimpleMethodSignature(String name, String... parameterTypeNames) { + this(name, buildParameterTypes(parameterTypeNames)); + } + + private static JavaType[] buildParameterTypes(String[] parameterTypeNames) { + if (parameterTypeNames == null) { + throw new IllegalArgumentException("The parameter type names are required."); + } + JavaType[] parameterTypes = new JavaType[parameterTypeNames.length]; + for (int i = 0; i < parameterTypeNames.length; i++) { + if (parameterTypeNames[i] == null) { + throw new IllegalArgumentException("Missing parameter type name: " + i); + } + parameterTypes[i] = new SimpleJavaType(parameterTypeNames[i]); + } + return parameterTypes; + } + + /** + * Construct a method signature with the specified name and parameter + * types. + */ + public SimpleMethodSignature(String name, Class<?>... parameterJavaClasses) { + this(name, buildParameterTypeNames(parameterJavaClasses)); + } + + private static String[] buildParameterTypeNames(Class<?>[] parameterJavaClasses) { + if (parameterJavaClasses == null) { + throw new IllegalArgumentException("The parameter Java classes are required."); + } + String[] parameterTypeNames = new String[parameterJavaClasses.length]; + for (int i = 0; i < parameterJavaClasses.length; i++) { + if (parameterJavaClasses[i] == null) { + throw new IllegalArgumentException("Missing parameter Java class: " + i); + } + parameterTypeNames[i] = parameterJavaClasses[i].getName(); + } + return parameterTypeNames; + } + + /** + * Construct a method signature for the specified Java method. + */ + public SimpleMethodSignature(Method method) { + this(method.getName(), method.getParameterTypes()); + } + + + // ********** accessors ********** + + public String getName() { + return this.name; + } + + public JavaType[] getParameterTypes() { + return this.parameterTypes; + } + + + // ********** comparison ********** + + public boolean equals(String otherName, JavaType[] otherParameterTypes) { + return this.name.equals(otherName) + && Arrays.equals(this.parameterTypes, otherParameterTypes); + } + + public boolean equals(MethodSignature other) { + return this.equals(other.getName(), other.getParameterTypes()); + } + + @Override + public boolean equals(Object o) { + return (this == o) ? true : (o instanceof MethodSignature) ? this.equals((MethodSignature) o) : false; + } + + @Override + public int hashCode() { + return this.name.hashCode() ^ Arrays.hashCode(this.parameterTypes); + } + + public int compareTo(MethodSignature ms) { + int compare = Collator.getInstance().compare(this.name, ms.getName()); + return (compare != 0) ? compare : this.compareParameterTypes(ms.getParameterTypes()); + } + + private int compareParameterTypes(JavaType[] otherParameterTypes) { + int len1 = this.parameterTypes.length; + int len2 = otherParameterTypes.length; + int min = Math.min(len1, len2); + for (int i = 0; i < min; i++) { + int compare = this.parameterTypes[i].compareTo(otherParameterTypes[i]); + if (compare != 0) { + return compare; + } + } + return (len1 == len2) ? 0 : (len1 < len2) ? -1 : 1; + } + + + // ********** printing and displaying ********** + + public String getSignature() { + StringBuilder sb = new StringBuilder(200); + this.appendSignatureTo(sb); + return sb.toString(); + } + + public void appendSignatureTo(StringBuilder sb) { + sb.append(this.name); + sb.append('('); + for (int i = 0; i < this.parameterTypes.length; i++) { + if (i != 0) { + sb.append(", "); + } + this.parameterTypes[i].appendDeclarationTo(sb); + } + sb.append(')'); + } + + public void printSignatureOn(PrintWriter pw) { + pw.print(this.name); + pw.print('('); + for (int i = 0; i < this.parameterTypes.length; i++) { + if (i != 0) { + pw.print(", "); + } + this.parameterTypes[i].printDeclarationOn(pw); + } + pw.print(')'); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(200); + sb.append(ClassTools.shortClassNameForObject(this)); + sb.append('('); + this.appendSignatureTo(sb); + sb.append(')'); + return sb.toString(); + } + + + // ********** cloning ********** + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + throw new InternalError(); + } + } + +} diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/resource/ClassTools.java b/jpa/tests/org.eclipse.jpt.utility.tests/resource/ClassTools.java new file mode 100644 index 0000000000..aac17b6044 --- /dev/null +++ b/jpa/tests/org.eclipse.jpt.utility.tests/resource/ClassTools.java @@ -0,0 +1,1680 @@ +/******************************************************************************* + * Copyright (c) 2005, 2008 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 test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.Stack; + +/** + * Convenience methods related to the java.lang.reflect package. + * These methods provide shortcuts for manipulating objects via + * reflection; particularly when dealing with fields and/or methods that + * are not publicly accessible or are inherited. + * + * In most cases, all the exceptions are handled and + * wrapped in java.lang.RuntimeExceptions; so these methods should + * be used when you are confident that you will not having any problems + * using reflection. + * + * There are also a number of methods whose names + * begin with "attempt". These methods will throw a NoSuchMethodException + * or NoSuchFieldException when appropriate, allowing you to probe + * for methods that should be present but might not. + */ +public final class ClassTools { + + public static final Class<?>[] ZERO_PARAMETER_TYPES = new Class[0]; + public static final Object[] ZERO_PARAMETERS = new Object[0]; + private static final String CR = StringTools.CR; + + public static final char NESTED_CLASS_NAME_SEPARATOR = '$'; + + public static final char ARRAY_INDICATOR = '['; + public static final char TYPE_DECLARATION_ARRAY_OPEN = '['; + public static final char TYPE_DECLARATION_ARRAY_CLOSE = ']'; + + public static final char REFERENCE_CLASS_CODE = 'L'; + public static final char REFERENCE_CLASS_NAME_DELIMITER = ';'; + + private static Primitive[] PRIMITIVES; // pseudo-'final' - lazy-initialized + public static final char BYTE_CODE = 'B'; + public static final char CHAR_CODE = 'C'; + public static final char DOUBLE_CODE = 'D'; + public static final char FLOAT_CODE = 'F'; + public static final char INT_CODE = 'I'; + public static final char LONG_CODE = 'J'; + public static final char SHORT_CODE = 'S'; + public static final char BOOLEAN_CODE = 'Z'; + public static final char VOID_CODE = 'V'; + private static int MAX_PRIMITIVE_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized + private static int MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = -1; // pseudo-'final' - lazy-initialized + + public static final String VOID_CLASS_NAME = void.class.getName(); + public static final String VOID_WRAPPER_CLASS_NAME = java.lang.Void.class.getName(); + + + /** + * Return all the fields for the + * specified class, including inherited fields. + * Class#allFields() + */ + @Deprecated + public static Field[] allFields(Class<?> javaClass) { + Stack<Field> stack = new Stack<Field>(); + for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { + pushDeclaredFields(tempClass, stack); + } + Collections.reverse(stack); + return stack.toArray(new Field[stack.size()]); + } + + /** + * Return all the methods for the + * specified class, including inherited methods. + * Class#allMethods() + */ + public static Method[] allMethods(Class<?> javaClass) { + Stack<Method> stack = new Stack<Method>(); + for (Class<?> tempClass = javaClass; tempClass != null; tempClass = tempClass.getSuperclass()) { + pushDeclaredMethods(tempClass, stack); + } + Collections.reverse(stack); + return stack.toArray(new Method[stack.size()]); + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * using the class's default (zero-argument) constructor. + * Throw an exception if the default constructor is not defined. + * Class#newInstance() throws NoSuchMethodException + */ + @Deprecated + public static <T> T attemptNewInstance(Class<T> javaClass) throws NoSuchMethodException { + return attemptNewInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter types and parameters. + * Throw an exception if the constructor is not defined. + * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException + */ + public static <T> T attemptNewInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { + try { + return constructor(javaClass, parameterTypes).newInstance(parameters); + } catch (InstantiationException ie) { + throw new RuntimeException(ie + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), ie); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), iae); + } catch (InvocationTargetException ite) { + throw new RuntimeException(fullyQualifiedConstructorSignature(javaClass, parameterTypes) + CR + ite.getTargetException(), ite); + } + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * given the constructor parameter type and parameter. + * Throw an exception if the constructor is not defined. + * Class#newInstance(Class<?> parameterType, Object parameter) throws NoSuchMethodException + */ + public static <T> T attemptNewInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) throws NoSuchMethodException { + return attemptNewInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Attempt to get a field value, given the containing object and field name. + * Return its result. + * Useful for accessing private, package, or protected fields. + * Throw an exception if the field is not defined. + * Object#getFieldValue(String fieldName) throws NoSuchFieldException + */ + public static Object attemptToGetFieldValue(Object object, String fieldName) throws NoSuchFieldException { + try { + return field(object, fieldName).get(object); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae); + } + } + + /** + * Attempt to get a static field value, given the containing object and field name. + * Return its result. + * Useful for accessing private, package, or protected fields. + * Throw an exception if the field is not defined. + * Class#getStaticFieldValue(String fieldName) throws NoSuchFieldException + */ + public static Object attemptToGetStaticFieldValue(Class<?> javaClass, String fieldName) throws NoSuchFieldException { + try { + return field(javaClass, fieldName).get(null); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae); + } + } + + /** + * Convenience method. + * Attempt to execute a zero-argument method, + * given the receiver and method name. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName) throws NoSuchMethodException + */ + public static Object attemptToExecuteMethod(Object receiver, String methodName) throws NoSuchMethodException { + return attemptToExecuteMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Convenience method. + * Attempt to execute a method, given the receiver, + * method name, parameter type, and parameter. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException + */ + public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException { + return attemptToExecuteMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Attempt to execute a method, given the receiver, + * method name, parameter types, and parameters. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException + */ + public static Object attemptToExecuteMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { + return executeMethod(method(receiver, methodName, parameterTypes), receiver, parameters); + } + + /** + * Attempt to execute a method, given the receiver, + * method name, parameter types, and parameters. + * Return its result. + * Throw an exception if the method is not found. + * If the executed method throws an exception, rethrow that exception. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException + */ + public static Object attemptToExecuteMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) + throws Throwable, NoSuchMethodException + { + return executeMethodWithException(method(receiver, methodName, parameterTypes), receiver, parameters); + } + + /** + * Convenience method. + * Attempt to execute a zero-argument static method, + * given the class and method name. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName) throws NoSuchMethodException + */ + public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException { + return attemptToExecuteStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Attempt to execute a static method, given the class, + * method name, parameter types, and parameters. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException + */ + public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) throws NoSuchMethodException { + return executeStaticMethod(staticMethod(javaClass, methodName, parameterTypes), parameters); + } + + /** + * Convenience method. + * Attempt to execute a static method, given the class, + * method name, parameter type, and parameter. + * Return its result. + * Throw an exception if the method is not found. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException + */ + public static Object attemptToExecuteStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) throws NoSuchMethodException { + return attemptToExecuteStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Attempt to set a field value, given the + * containing object, field name, and new field value. + * Useful for accessing private, package, or protected fields. + * Throw an exception if the field is not defined. + * Object#setFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException + */ + public static void attemptToSetFieldValue(Object object, String fieldName, Object fieldValue) throws NoSuchFieldException { + try { + field(object, fieldName).set(object, fieldValue); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + fullyQualifiedFieldName(object, fieldName), iae); + } + } + + /** + * Attempt to set a static field value, given the + * containing class, field name, and new field value. + * Useful for accessing private, package, or protected fields. + * Throw an exception if the field is not defined. + * Class#setStaticFieldValue(String fieldName, Object fieldValue) throws NoSuchFieldException + */ + public static void attemptToSetStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) throws NoSuchFieldException { + try { + field(javaClass, fieldName).set(null, fieldValue); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + fullyQualifiedFieldName(javaClass, fieldName), iae); + } + } + + /** + * Convenience method. + * Return the default (zero-argument) constructor + * for the specified class. + * Set accessible to true, so we can access + * private/package/protected constructors. + * Class#constructor() throws NoSuchMethodException + */ + public static <T> Constructor<T> constructor(Class<T> javaClass) throws NoSuchMethodException { + return constructor(javaClass, ZERO_PARAMETER_TYPES); + } + + /** + * Return the constructor for the specified class + * and formal parameter types. + * Set accessible to true, so we can access + * private/package/protected constructors. + * Class#constructor(Class<?>[] parameterTypes) throws NoSuchMethodException + */ + public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?>[] parameterTypes) throws NoSuchMethodException { + Constructor<T> constructor = javaClass.getDeclaredConstructor(parameterTypes); + constructor.setAccessible(true); + return constructor; + } + + /** + * Convenience method. + * Return the constructor for the specified class + * and formal parameter type. + * Set accessible to true, so we can access + * private/package/protected constructors. + * Class#constructor(Class<?> parameterType) throws NoSuchMethodException + */ + public static <T> Constructor<T> constructor(Class<T> javaClass, Class<?> parameterType) throws NoSuchMethodException { + return constructor(javaClass, new Class[] {parameterType}); + } + + /** + * Return the declared fields for the specified class. + * Set accessible to true, so we can access + * private/package/protected fields. + * Class#accessibleDeclaredFields() + */ + public static Field[] declaredFields(Class<?> javaClass) { + Field[] fields = javaClass.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + } + return fields; + } + + /** + * Return the declared methods for the + * specified class. + * Set accessible to true, so we can access + * private/package/protected methods. + * Class#accessibleDeclaredMethods() + */ + public static Method[] declaredMethods(Class<?> javaClass) { + Method[] methods = javaClass.getDeclaredMethods(); + for (Method method : methods) { + method.setAccessible(true); + } + return methods; + } + + /** + * Return the default (zero-argument) constructor + * for the specified class. + * Set accessible to true, so we can access + * private/package/protected constructors. + * Class#defaultConstructor() + */ + public static <T> Constructor<T> defaultConstructor(Class<T> javaClass) throws NoSuchMethodException { + return constructor(javaClass); + } + + /** + * Return a field for the specified class and field name. + * If the class does not directly + * define the field, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected fields. + */ + public static Field field(Class<?> javaClass, String fieldName) throws NoSuchFieldException { + Field field = null; + try { + field = javaClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException ex) { + Class<?> superclass = javaClass.getSuperclass(); + if (superclass == null) { + throw ex; + } + // recurse + return field(superclass, fieldName); + } + field.setAccessible(true); + return field; + } + + /** + * Convenience method. + * Return a field for the specified object and field name. + * If the object's class does not directly + * define the field, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected fields. + */ + public static Field field(Object object, String fieldName) throws NoSuchFieldException { + return field(object.getClass(), fieldName); + } + + /* + * Return a string representation of the specified constructor. + */ + private static String fullyQualifiedConstructorSignature(Class<?> javaClass, Class<?>[] parameterTypes) { + return fullyQualifiedMethodSignature(javaClass, null, parameterTypes); + } + + /* + * Return a string representation of the specified field. + */ + private static String fullyQualifiedFieldName(Class<?> javaClass, String fieldName) { + StringBuilder sb = new StringBuilder(200); + sb.append(javaClass.getName()); + sb.append('.'); + sb.append(fieldName); + return sb.toString(); + } + + /* + * Return a string representation of the specified field. + */ + private static String fullyQualifiedFieldName(Object object, String fieldName) { + return fullyQualifiedFieldName(object.getClass(), fieldName); + } + + /* + * Return a string representation of the specified method. + */ + private static String fullyQualifiedMethodSignature(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) { + StringBuilder sb = new StringBuilder(200); + sb.append(javaClass.getName()); + // this check allows us to use this code for constructors, where the methodName is null + if (methodName != null) { + sb.append('.'); + sb.append(methodName); + } + sb.append('('); + int max = parameterTypes.length - 1; + if (max != -1) { + // stop one short of the end of the array + for (int i = 0; i < max; i++) { + sb.append(parameterTypes[i].getName()); + sb.append(", "); + } + sb.append(parameterTypes[max].getName()); + } + sb.append(')'); + return sb.toString(); + } + + /* + * Return a string representation of the specified method. + */ + private static String fullyQualifiedMethodSignature(Object receiver, String methodName, Class<?>[] parameterTypes) { + return fullyQualifiedMethodSignature(receiver.getClass(), methodName, parameterTypes); + } + + /** + * Get a field value, given the containing object and field name. + * Return its result. + * Useful for accessing private, package, or protected fields. + * Object#getFieldValue(String fieldName) + */ + public static Object fieldValue(Object object, String fieldName) { + try { + return attemptToGetFieldValue(object, fieldName); + } catch (NoSuchFieldException nsfe) { + throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe); + } + } + + /** + * Get a static field value, given the containing class and field name. + * Return its result. + * Useful for accessing private, package, or protected fields. + * Class#getStaticFieldValue(String fieldName) + */ + public static Object staticFieldValue(Class<?> javaClass, String fieldName) { + try { + return attemptToGetStaticFieldValue(javaClass, fieldName); + } catch (NoSuchFieldException nsfe) { + throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe); + } + } + + /** + * Convenience method. + * Execute a zero-argument method, given the receiver and method name. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName) + */ + public static Object executeMethod(Object receiver, String methodName) { + return executeMethod(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Execute a method, given the receiver, + * method name, parameter types, and parameters. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) + */ + public static Object executeMethod(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) { + try { + return attemptToExecuteMethod(receiver, methodName, parameterTypes, parameters); + } catch (NoSuchMethodException nsme) { + throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); + } + } + + /** + * Convenience method. + * Execute a one-argument method, given the receiver, + * method name, parameter type, and parameter. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?> parameterType, Object parameter) + */ + public static Object executeMethod(Object receiver, String methodName, Class<?> parameterType, Object parameter) { + return executeMethod(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Convenience method. + * Execute a zero-argument method, given the receiver and method name. + * Return its result. + * If the method throws an exception, rethrow that exception. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName) + */ + public static Object executeMethodWithException(Object receiver, String methodName) + throws Throwable + { + return executeMethodWithException(receiver, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Convenience method. + * Execute a one-argument method, given the receiver, + * method name, parameter type, and parameter. + * Return its result. + * If the method throws an exception, rethrow that exception. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?> parameterType, Object parameter) + */ + public static Object executeMethodWithException(Object receiver, String methodName, Class<?> parameterType, Object parameter) + throws Throwable + { + return executeMethodWithException(receiver, methodName, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Execute a method, given the receiver, + * method name, parameter types, and parameters. + * Return its result. + * If the method throws an exception, rethrow that exception. + * Useful for invoking private, package, or protected methods. + * Object#execute(String methodName, Class<?>[] parameterTypes, Object[] parameters) + */ + public static Object executeMethodWithException(Object receiver, String methodName, Class<?>[] parameterTypes, Object[] parameters) + throws Throwable + { + try { + return attemptToExecuteMethodWithException(receiver, methodName, parameterTypes, parameters); + } catch (NoSuchMethodException nsme) { + throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(receiver, methodName, parameterTypes), nsme); + } + } + + /** + * Execute the specified method with the specified parameters. + * Return its result. + * Convert exceptions to RuntimeExceptions. + */ + public static Object executeMethod(Method method, Object receiver, Object[] parameters) { + try { + return method.invoke(receiver, parameters); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + method, iae); + } catch (InvocationTargetException ite) { + throw new RuntimeException(method + CR + ite.getTargetException(), ite); + } + } + + /** + * Execute the specified method with the specified parameters. + * Return its result. + * If the method throws an exception, rethrow that exception. + * Convert all other exceptions to RuntimeExceptions. + */ + public static Object executeMethodWithException(Method method, Object receiver, Object[] parameters) + throws Throwable + { + try { + return method.invoke(receiver, parameters); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae + CR + method, iae); + } catch (InvocationTargetException ite) { + Throwable cause = ite.getCause(); + if (cause == null) { + throw new RuntimeException(method.toString(), ite); + } + throw cause; + } + } + + /** + * Convenience method. + * Execute a zero-argument static method, + * given the class and method name. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName) + */ + public static Object executeStaticMethod(Class<?> javaClass, String methodName) { + return executeStaticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Execute a static method, given the class, + * method name, parameter types, and parameters. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName, Class<?>[] parameterTypes, Object[] parameters) + */ + public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes, Object[] parameters) { + try { + return attemptToExecuteStaticMethod(javaClass, methodName, parameterTypes, parameters); + } catch (NoSuchMethodException nsme) { + throw new RuntimeException(nsme + CR + fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes), nsme); + } + } + + /** + * Convenience method. + * Execute a static method, given the class, + * method name, parameter type, and parameter. + * Return its result. + * Useful for invoking private, package, or protected methods. + * Class#executeStaticMethod(String methodName, Class<?> parameterType, Object parameter) + */ + public static Object executeStaticMethod(Class<?> javaClass, String methodName, Class<?> parameterType, Object parameter) { + return executeStaticMethod(javaClass, methodName, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Execute the specified static method with the specified parameters. + * Return its result. + * Convert exceptions to RuntimeExceptions. + */ + public static Object executeStaticMethod(Method method, Object[] parameters) { + return executeMethod(method, null, parameters); + } + + /** + * Convenience method. + * Return a zero-argument method for the specified class + * and method name. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Class<?> javaClass, String methodName) throws NoSuchMethodException { + return method(javaClass, methodName, ZERO_PARAMETER_TYPES); + } + + /** + * Return a method for the specified class, method name, + * and formal parameter types. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { + Method method = null; + try { + method = javaClass.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException ex) { + Class<?> superclass = javaClass.getSuperclass(); + if (superclass == null) { + throw ex; + } + // recurse + return method(superclass, methodName, parameterTypes); + } + method.setAccessible(true); + return method; + } + + /** + * Convenience method. + * Return a method for the specified class, method name, + * and formal parameter type. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Class<?> javaClass, String methodName, Class<?> parameterType) throws NoSuchMethodException { + return method(javaClass, methodName, new Class[] {parameterType}); + } + + /** + * Convenience method. + * Return a zero-argument method for the specified object + * and method name. If the object's class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Object object, String methodName) throws NoSuchMethodException { + return method(object.getClass(), methodName); + } + + /** + * Convenience method. + * Return a method for the specified object, method name, + * and formal parameter types. If the object's class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Object object, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { + return method(object.getClass(), methodName, parameterTypes); + } + + /** + * Convenience method. + * Return a method for the specified object, method name, + * and formal parameter type. If the object's class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method method(Object object, String methodName, Class<?> parameterType) throws NoSuchMethodException { + return method(object.getClass(), methodName, parameterType); + } + + /** + * Convenience method. + * Return the specified class (without the checked exception). + */ + public static Class<?> classForName(String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new RuntimeException(className, ex); + } + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * using the class's default (zero-argument) constructor. + * Class#newInstance() + */ + public static <T> T newInstance(Class<T> javaClass) { + return newInstance(javaClass, ZERO_PARAMETER_TYPES, ZERO_PARAMETERS); + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * using the class's default (zero-argument) constructor. + * Class#newInstance() + */ + public static Object newInstance(String className) throws ClassNotFoundException { + return newInstance(className, null); + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * using the class's default (zero-argument) constructor. + * Class#newInstance() + */ + public static Object newInstance(String className, ClassLoader classLoader) throws ClassNotFoundException { + return newInstance(Class.forName(className, true, classLoader)); + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter types and parameters. + * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) + */ + public static <T> T newInstance(Class<T> javaClass, Class<?>[] parameterTypes, Object[] parameters) { + try { + return attemptNewInstance(javaClass, parameterTypes, parameters); + } catch (NoSuchMethodException nsme) { + throw new RuntimeException(nsme + CR + fullyQualifiedConstructorSignature(javaClass, parameterTypes), nsme); + } + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter types and parameters. + * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) + */ + public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters) throws ClassNotFoundException { + return newInstance(className, parameterTypes, parameters, null); + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter types and parameters. + * Class#newInstance(Class<?>[] parameterTypes, Object[] parameters) + */ + public static Object newInstance(String className, Class<?>[] parameterTypes, Object[] parameters, ClassLoader classLoader) throws ClassNotFoundException { + return newInstance(Class.forName(className, true, classLoader), parameterTypes, parameters); + } + + /** + * Convenience method. + * Return a new instance of the specified class, + * given the constructor parameter type and parameter. + * Class#newInstance(Class<?> parameterType, Object parameter) + */ + public static <T> T newInstance(Class<T> javaClass, Class<?> parameterType, Object parameter) { + return newInstance(javaClass, new Class[] {parameterType}, new Object[] {parameter}); + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter type and parameter. + * Class#newInstance(Class<?> parameterType, Object parameter) + */ + public static Object newInstance(String className, Class<?> parameterType, Object parameter) throws ClassNotFoundException { + return newInstance(className, parameterType, parameter, null); + } + + /** + * Return a new instance of the specified class, + * given the constructor parameter type and parameter. + * Class#newInstance(Class<?> parameterType, Object parameter) + */ + public static Object newInstance(String className, Class<?> parameterType, Object parameter, ClassLoader classLoader) throws ClassNotFoundException { + return newInstance(Class.forName(className, false, classLoader), parameterType, parameter); + } + + /* + * Push the declared fields for the specified class + * onto the top of the stack. + */ + private static void pushDeclaredFields(Class<?> javaClass, Stack<Field> stack) { + Field[] fields = declaredFields(javaClass); + for (int i = fields.length; i-- > 0; ) { + stack.push(fields[i]); + } + } + + /* + * Push the declared methods for the specified class + * onto the top of the stack. + */ + private static void pushDeclaredMethods(Class<?> javaClass, Stack<Method> stack) { + Method[] methods = declaredMethods(javaClass); + for (int i = methods.length; i-- > 0; ) { + stack.push(methods[i]); + } + } + + /** + * Set a field value, given the containing object, field name, and new field value. + * Useful for accessing private, package, or protected fields. + * Object#setFieldValue(String fieldName, Object fieldValue) + */ + public static void setFieldValue(Object object, String fieldName, Object fieldValue) { + try { + attemptToSetFieldValue(object, fieldName, fieldValue); + } catch (NoSuchFieldException nsfe) { + throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(object, fieldName), nsfe); + } + } + + /** + * Set a static field value, given the containing class, field name, and new field value. + * Useful for accessing private, package, or protected fields. + * Class#setStaticFieldValue(String fieldName, Object fieldValue) + */ + public static void setStaticFieldValue(Class<?> javaClass, String fieldName, Object fieldValue) { + try { + attemptToSetStaticFieldValue(javaClass, fieldName, fieldValue); + } catch (NoSuchFieldException nsfe) { + throw new RuntimeException(nsfe + CR + fullyQualifiedFieldName(javaClass, fieldName), nsfe); + } + } + + /** + * Return the short name of the object's class. + * Class#getShortName() + */ + public static String shortClassNameForObject(Object object) { + return shortNameFor(object.getClass()); + } + + /** + * Return the short name of the class (e.g. "Object"). + * Class#getShortName() + */ + public static String shortNameForClassNamed(String className) { + return className.substring(className.lastIndexOf('.') + 1); + } + + /** + * Return the short name of the class (e.g. "Object"). + * Class#getShortName() + */ + public static String shortNameFor(Class<?> javaClass) { + return shortNameForClassNamed(javaClass.getName()); + } + + /** + * Return the nested name of the object's class. + * Class#getNestedName() + */ + public static String nestedClassNameForObject(Object object) { + return nestedNameFor(object.getClass()); + } + + /** + * Return the nested name of the class (e.g. "Entry"). + * Class#getNestedName() + */ + public static String nestedNameForClassNamed(String className) { + return className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1); + } + + /** + * Return the nested name of the class (e.g. "Entry"). + * Class#getNestedName() + */ + public static String nestedNameFor(Class<?> javaClass) { + return nestedNameForClassNamed(javaClass.getName()); + } + + /** + * Return the "toString()" name of the object's class. + */ + public static String toStringClassNameForObject(Object object) { + return toStringNameFor(object.getClass()); + } + + /** + * Return the "toString()" name of the class. + * "Member" classes will return only the final name: + * "com.foo.bar.TopLevelClass$MemberClass$NestedMemberClass" + * => "NestedMemberClass" + * "Local" and "anonymous" classes will still return the embedded '$'s: + * "com.foo.bar.TopLevelClass$1LocalClass" + * => "TopLevelClass$1LocalClass" + * "com.foo.bar.TopLevelClass$1" + * => "TopLevelClass$1" + */ + public static String toStringNameForClassNamed(String className) { + return classNamedIsMember(className) ? + className.substring(className.lastIndexOf(NESTED_CLASS_NAME_SEPARATOR) + 1) + : + className.substring(className.lastIndexOf('.') + 1); + } + + /** + * Return the "toString()" name of the class. + */ + public static String toStringNameFor(Class<?> javaClass) { + return toStringNameForClassNamed(javaClass.getName()); + } + + /** + * Return the package name of the class (e.g. "java.lang"). + * Class#getPackageName() + */ + public static String packageNameFor(Class<?> javaClass) { + return packageNameForClassNamed(javaClass.getName()); + } + + /** + * Return the package name of the class (e.g. "java.lang"). + * Class#getPackageName() + */ + public static String packageNameForClassNamed(String className) { + int lastPeriod = className.lastIndexOf('.'); + if (lastPeriod == -1) { + return ""; + } + return className.substring(0, lastPeriod); + } + + /** + * Return the short name of the class, + * followed by its package name (e.g. "Object (java.lang)"). + * Class#getShortNameWithPackage() + */ + public static String shortNameWithPackage(Class<?> javaClass) { + StringBuilder sb = new StringBuilder(200); + sb.append(shortNameFor(javaClass)); + if ( ! javaClass.isPrimitive()) { + sb.append(" ("); + sb.append(packageNameFor(javaClass)); + sb.append(')'); + } + return sb.toString(); + } + + /** + * Convenience method. + * Return a zero-argument, static method for the specified class + * and method name. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method staticMethod(Class<?> javaClass, String methodName) throws NoSuchMethodException { + return staticMethod(javaClass, methodName, ZERO_PARAMETER_TYPES); + } + + /** + * Return a static method for the specified class, method name, + * and formal parameter types. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method staticMethod(Class<?> javaClass, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException { + Method method = method(javaClass, methodName, parameterTypes); + if (Modifier.isStatic(method.getModifiers())) { + return method; + } + throw new NoSuchMethodException(fullyQualifiedMethodSignature(javaClass, methodName, parameterTypes)); + } + + /** + * Convenience method. + * Return a static method for the specified class, method name, + * and formal parameter type. If the class does not directly + * implement the method, look for it in the class's superclasses. + * Set accessible to true, so we can access + * private/package/protected methods. + */ + public static Method staticMethod(Class<?> javaClass, String methodName, Class<?> parameterTypes) throws NoSuchMethodException { + return staticMethod(javaClass, methodName, new Class[] {parameterTypes}); + } + + /** + * Return whether the specified class can be "declared" in code; + * i.e. it is either a "top-level" class or a "member" class, but it + * is not an "array" class. This method rolls together all the checks + * from the other methods for a bit of a performance tweak. + * Class#isDeclarable() + */ + public static boolean classNamedIsDeclarable(String className) { + if (className.charAt(0) == ARRAY_INDICATOR) { + return false; // it is an "array" class + } + int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); + if (index == -1) { + return true; // it is a "top-level" class + } + do { + // the character immediately after each dollar sign cannot be a digit + index++; + if (Character.isDigit(className.charAt(index))) { + return false; + } + index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index); + } while (index != -1); + return true; + } + + /** + * Return whether the specified class is a "top-level" class, + * as opposed to a "member", "local", or "anonymous" class, + * using the standard jdk naming conventions (i.e. the class + * name does NOT contain a '$': "TopLevelClass"). + * Class#isTopLevel() + */ + public static boolean classNamedIsTopLevel(String className) { + if (classNamedIsArray(className)) { + return false; + } + return className.indexOf(NESTED_CLASS_NAME_SEPARATOR) == -1; + } + + /** + * Return whether the specified class is a "member" class, + * as opposed to a "top-level", "local", or "anonymous" class, + * using the standard jdk naming conventions (i.e. the class + * name contains at least one '$' and all the names between + * each '$' are legal class names: + * "TopLevelClass$MemberClass$NestedMemberClass"). + * Class#isMember() + */ + public static boolean classNamedIsMember(String className) { + if (classNamedIsArray(className)) { + return false; + } + int index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); + if (index == -1) { + return false; // it is a "top-level" class + } + do { + // the character immediately after each dollar sign cannot be a digit + index++; + if (Character.isDigit(className.charAt(index))) { + return false; + } + index = className.indexOf(NESTED_CLASS_NAME_SEPARATOR, index); + } while (index != -1); + return true; + } + + /** + * Return whether the specified class is a "local" class, + * as opposed to a "top-level", "member", or "anonymous" class, + * using the standard jdk (or Eclipse) naming conventions. + * In the jdk, the class name ends with '$nnnXXX' where the '$' is + * followed by a series of numeric digits which are followed by the + * local class name: "TopLevelClass$1LocalClass". + * In Eclipse, the class name ends with '$nnn$XXX' where the '$' is + * followed by a series of numeric digits which are separated from + * the local class name by another '$': "TopLevelClass$1$LocalClass". + * Class#isLocal() + */ + public static boolean classNamedIsLocal(String className) { + if (classNamedIsArray(className)) { + return false; + } + int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); + if (dollar == -1) { + return false; + } + if ( ! Character.isDigit(className.charAt(dollar + 1))) { + return false; + } + int len = className.length(); + for (int i = dollar + 2; i < len; i++) { + if (Character.isJavaIdentifierStart(className.charAt(i))) { + return true; + } + } + // all the characters past the $ are digits (anonymous) + return false; + } + + /** + * Return whether the specified class is an "anonymous" class, + * as opposed to a "top-level", "member", or "local" class, + * using the standard jdk naming conventions (i.e. the class + * name ends with '$nnn' where all the characters past the + * last '$' are numeric digits: "TopLevelClass$1"). + * Class#isAnonymous() + */ + public static boolean classNamedIsAnonymous(String className) { + if (classNamedIsArray(className)) { + return false; + } + int dollar = className.indexOf(NESTED_CLASS_NAME_SEPARATOR); + if (dollar == -1) { + return false; + } + int start = dollar + 1; + for (int i = className.length(); i-- > start; ) { + if ( ! Character.isDigit(className.charAt(i))) { + return false; + } + } + // all the characters past the $ are digits + return true; + } + + /** + * Return the "array depth" of the specified class. + * The depth is the number of dimensions for an array type. + * Non-array types have a depth of zero. + * Class#getArrayDepth() + */ + public static int arrayDepthFor(Class<?> javaClass) { + int depth = 0; + while (javaClass.isArray()) { + depth++; + javaClass = javaClass.getComponentType(); + } + return depth; + } + + /** + * Return the "array depth" of the specified object. + * The depth is the number of dimensions for an array. + * Non-arrays have a depth of zero. + */ + public static int arrayDepthForObject(Object object) { + return arrayDepthFor(object.getClass()); + } + + /** + * Return the "array depth" of the specified class. + * The depth is the number of dimensions for an array type. + * Non-array types have a depth of zero. + * @see java.lang.Class#getName() + * Class#getArrayDepth() + */ + public static int arrayDepthForClassNamed(String className) { + int depth = 0; + while (className.charAt(depth) == ARRAY_INDICATOR) { + depth++; + } + return depth; + } + + /** + * Return whether the specified class is an array type. + * @see java.lang.Class#getName() + */ + public static boolean classNamedIsArray(String className) { + return className.charAt(0) == ARRAY_INDICATOR; + } + + /** + * Return the "element type" of the specified class. + * The element type is the base type held by an array type. + * A non-array type simply returns itself. + * Class#getElementType() + */ + public static Class<?> elementTypeFor(Class<?> javaClass) { + while (javaClass.isArray()) { + javaClass = javaClass.getComponentType(); + } + return javaClass; + } + + /** + * Return the "element type" of the specified object. + * The element type is the base type held by an array. + * A non-array simply returns its class. + */ + public static Class<?> elementTypeForObject(Object object) { + return elementTypeFor(object.getClass()); + } + + /** + * Return the "element type" of the specified class. + * The element type is the base type held by an array type. + * Non-array types simply return themselves. + * Class#getElementType() + */ + public static String elementTypeNameFor(Class<?> javaClass) { + return elementTypeFor(javaClass).getName(); + } + + /** + * Return the "element type" of the specified class. + * The element type is the base type held by an array type. + * Non-array types simply return themselves. + * @see java.lang.Class#getName() + * Class#getElementType() + */ + public static String elementTypeNameForClassNamed(String className) { + int depth = arrayDepthForClassNamed(className); + if (depth == 0) { + // the name is in the form: "java.lang.Object" or "int" + return className; + } + int last = className.length() - 1; + if (className.charAt(depth) == REFERENCE_CLASS_CODE) { + // the name is in the form: "[[[Ljava.lang.Object;" + return className.substring(depth + 1, last); // drop the trailing ';' + } + // the name is in the form: "[[[I" + return classNameForCode(className.charAt(last)); + } + + /** + * Return whether the specified class is a "reference" + * class (i.e. neither 'void' nor one of the primitive variable classes, + * ['boolean', 'int', 'float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsReference(String className) { + return ! classNamedIsPrimitive(className); + } + + /** + * Return whether the specified class is a primitive + * class (i.e. 'void' or one of the primitive variable classes, + * ['boolean', 'int', 'float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsPrimitive(String className) { + if (classNamedIsArray(className) || (className.length() > maxPrimitiveClassNameLength())) { + return false; // performance tweak + } + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].javaClass.getName().equals(className)) { + return true; + } + } + return false; + } + + /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsVariablePrimitive(String className) { + return classNamedIsPrimitive(className) + && ( ! className.equals(VOID_CLASS_NAME)); + } + + /** + * Return whether the specified class is a primitive wrapper + * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, + * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsPrimitiveWrapperClass(String className) { + if (classNamedIsArray(className) || (className.length() > maxPrimitiveWrapperClassNameLength())) { + return false; // performance tweak + } + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].wrapperClass.getName().equals(className)) { + return true; + } + } + return false; + } + + /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classNamedIsVariablePrimitiveWrapperClass(String className) { + return classNamedIsPrimitiveWrapperClass(className) + && ( ! className.equals(VOID_WRAPPER_CLASS_NAME)); + } + + /** + * Return whether the specified class is a primitive wrapper + * class (i.e. 'java.lang.Void' or one of the primitive variable wrapper classes, + * ['java.lang.Boolean', 'java.lang.Integer', 'java.lang.Float', etc.]). + * NB: void.class.isPrimitive() == true + */ + public static boolean classIsPrimitiveWrapperClass(Class<?> javaClass) { + if (javaClass.isArray() || (javaClass.getName().length() > maxPrimitiveWrapperClassNameLength())) { + return false; // performance tweak + } + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].wrapperClass == javaClass) { + return true; + } + } + return false; + } + + /** + * Return whether the specified class is a "variable" primitive + * class (i.e. 'boolean', 'int', 'float', etc., but not 'void'). + * NB: void.class.isPrimitive() == true + */ + public static boolean classIsVariablePrimitiveWrapperClass(Class<?> javaClass) { + return classIsPrimitiveWrapperClass(javaClass) + && (javaClass != java.lang.Void.class); + } + + /** + * Return the class name for the specified class code. + * @see java.lang.Class#getName() + */ + public static String classNameForCode(char classCode) { + return classForCode(classCode).getName(); + } + + /** + * Return the class name for the specified class code. + * @see java.lang.Class#getName() + */ + public static String classNameForCode(int classCode) { + return classNameForCode((char) classCode); + } + + /** + * Return the class for the specified class code. + * @see java.lang.Class#getName() + */ + public static Class<?> classForCode(char classCode) { + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].code == classCode) { + return codes[i].javaClass; + } + } + throw new IllegalArgumentException(String.valueOf(classCode)); + } + + /** + * Return the class for the specified class code. + * @see java.lang.Class#getName() + */ + public static Class<?> classForCode(int classCode) { + return classForCode((char) classCode); + } + + /** + * Return the class code for the specified class. + * @see java.lang.Class#getName() + */ + public static char codeForClass(Class<?> javaClass) { + if (( ! javaClass.isArray()) && (javaClass.getName().length() <= maxPrimitiveClassNameLength())) { + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].javaClass == javaClass) { + return codes[i].code; + } + } + } + throw new IllegalArgumentException(javaClass.getName()); + } + + /** + * Return the class code for the specified class. + * @see java.lang.Class#getName() + */ + public static char codeForClassNamed(String className) { + if (( ! classNamedIsArray(className)) && (className.length() <= maxPrimitiveClassNameLength())) { + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].javaClass.getName().equals(className)) { + return codes[i].code; + } + } + } + throw new IllegalArgumentException(className); + } + + /** + * Return the class for the specified "type declaration". + */ + public static Class<?> classForTypeDeclaration(String typeDeclaration) throws ClassNotFoundException { + return classForTypeDeclaration(typeDeclaration, ClassTools.class.getClassLoader()); + } + + /** + * Return the class for the specified "type declaration", + * using the specified class loader. + */ + public static Class<?> classForTypeDeclaration(String typeDeclaration, ClassLoader classLoader) throws ClassNotFoundException { + TypeDeclaration td = typeDeclaration(typeDeclaration); + return classForTypeDeclaration(td.elementTypeName, td.arrayDepth); + } + + private static TypeDeclaration typeDeclaration(String typeDeclaration) { + typeDeclaration = StringTools.removeAllWhitespace(typeDeclaration); + int arrayDepth = arrayDepthForTypeDeclaration_(typeDeclaration); + String elementTypeName = typeDeclaration.substring(0, typeDeclaration.length() - (arrayDepth * 2)); + return new TypeDeclaration(elementTypeName, arrayDepth); + } + + /** + * Return the class for the specified "type declaration". + */ + public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth) throws ClassNotFoundException { + return classForTypeDeclaration(elementTypeName, arrayDepth, null); + } + + /** + * Return the class for the specified "type declaration", + * using the specified class loader. + */ + // see the "Evaluation" of jdk bug 6446627 for a discussion of loading classes + public static Class<?> classForTypeDeclaration(String elementTypeName, int arrayDepth, ClassLoader classLoader) throws ClassNotFoundException { + // primitives cannot be loaded via Class#forName(), + // so check for a primitive class name first + Primitive pcc = null; + if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].javaClass.getName().equals(elementTypeName)) { + pcc = codes[i]; + break; + } + } + } + + // non-array + if (arrayDepth == 0) { + return (pcc == null) ? Class.forName(elementTypeName, false, classLoader) : pcc.javaClass; + } + + // array + StringBuilder sb = new StringBuilder(100); + for (int i = arrayDepth; i-- > 0; ) { + sb.append(ARRAY_INDICATOR); + } + if (pcc == null) { + sb.append(REFERENCE_CLASS_CODE); + sb.append(elementTypeName); + sb.append(REFERENCE_CLASS_NAME_DELIMITER); + } else { + sb.append(pcc.code); + } + return Class.forName(sb.toString(), false, classLoader); + } + + /** + * Return the class name for the specified "type declaration"; e.g. + * "int[]" -> "[I" + * @see java.lang.Class#getName() + */ + public static String classNameForTypeDeclaration(String typeDeclaration) { + TypeDeclaration td = typeDeclaration(typeDeclaration); + return classNameForTypeDeclaration(td.elementTypeName, td.arrayDepth); + } + + /** + * Return the array depth for the specified "type declaration"; e.g. + * "int[]" -> 1 + */ + public static int arrayDepthForTypeDeclaration(String typeDeclaration) { + return arrayDepthForTypeDeclaration_(StringTools.removeAllWhitespace(typeDeclaration)); + } + + /* + * Assume no whitespace in the type declaration. + */ + private static int arrayDepthForTypeDeclaration_(String typeDeclaration) { + int last = typeDeclaration.length() - 1; + int depth = 0; + int close = last; + while (typeDeclaration.charAt(close) == TYPE_DECLARATION_ARRAY_CLOSE) { + if (typeDeclaration.charAt(close - 1) == TYPE_DECLARATION_ARRAY_OPEN) { + depth++; + } else { + throw new IllegalArgumentException("invalid type declaration: " + typeDeclaration); + } + close = last - (depth * 2); + } + return depth; + } + + /** + * Return the class name for the specified "type declaration". + * @see java.lang.Class#getName() + */ + public static String classNameForTypeDeclaration(String elementTypeName, int arrayDepth) { + // non-array + if (arrayDepth == 0) { + return elementTypeName; + } + + if (elementTypeName.equals(VOID_CLASS_NAME)) { + throw new IllegalArgumentException("'" + VOID_CLASS_NAME + "' must have an array depth of zero: " + arrayDepth + '.'); + } + // array + StringBuilder sb = new StringBuilder(100); + for (int i = arrayDepth; i-- > 0; ) { + sb.append(ARRAY_INDICATOR); + } + + // look for a primitive first + Primitive pcc = null; + if (elementTypeName.length() <= maxPrimitiveClassNameLength()) { // performance tweak + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + if (codes[i].javaClass.getName().equals(elementTypeName)) { + pcc = codes[i]; + break; + } + } + } + + if (pcc == null) { + sb.append(REFERENCE_CLASS_CODE); + sb.append(elementTypeName); + sb.append(REFERENCE_CLASS_NAME_DELIMITER); + } else { + sb.append(pcc.code); + } + + return sb.toString(); + } + + private static int maxPrimitiveClassNameLength() { + if (MAX_PRIMITIVE_CLASS_NAME_LENGTH == -1) { + MAX_PRIMITIVE_CLASS_NAME_LENGTH = calculateMaxPrimitiveClassNameLength(); + } + return MAX_PRIMITIVE_CLASS_NAME_LENGTH; + } + + private static int calculateMaxPrimitiveClassNameLength() { + int max = -1; + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + int len = codes[i].javaClass.getName().length(); + if (len > max) { + max = len; + } + } + return max; + } + + private static int maxPrimitiveWrapperClassNameLength() { + if (MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH == -1) { + MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH = calculateMaxPrimitiveWrapperClassNameLength(); + } + return MAX_PRIMITIVE_WRAPPER_CLASS_NAME_LENGTH; + } + + private static int calculateMaxPrimitiveWrapperClassNameLength() { + int max = -1; + Primitive[] codes = primitives(); + for (int i = codes.length; i-- > 0; ) { + int len = codes[i].wrapperClass.getName().length(); + if (len > max) { + max = len; + } + } + return max; + } + + private static Primitive[] primitives() { + if (PRIMITIVES == null) { + PRIMITIVES = buildPrimitives(); + } + return PRIMITIVES; + } + + /** + * NB: void.class.isPrimitive() == true + */ + private static Primitive[] buildPrimitives() { + Primitive[] result = new Primitive[9]; + result[0] = new Primitive(BYTE_CODE, java.lang.Byte.class); + result[1] = new Primitive(CHAR_CODE, java.lang.Character.class); + result[2] = new Primitive(DOUBLE_CODE, java.lang.Double.class); + result[3] = new Primitive(FLOAT_CODE, java.lang.Float.class); + result[4] = new Primitive(INT_CODE, java.lang.Integer.class); + result[5] = new Primitive(LONG_CODE, java.lang.Long.class); + result[6] = new Primitive(SHORT_CODE, java.lang.Short.class); + result[7] = new Primitive(BOOLEAN_CODE, java.lang.Boolean.class); + result[8] = new Primitive(VOID_CODE, java.lang.Void.class); + return result; + } + + /** + * Suppress default constructor, ensuring non-instantiability. + */ + private ClassTools() { + super(); + throw new UnsupportedOperationException(); + } + + + // ********** member classes ********** + + private static class Primitive { + final char code; + final Class<?> javaClass; + final Class<?> wrapperClass; + private static final String WRAPPER_CLASS_TYPE_FIELD_NAME = "TYPE"; + // e.g. java.lang.Boolean.TYPE => boolean.class + Primitive(char code, Class<?> wrapperClass) { + this.code = code; + this.wrapperClass = wrapperClass; + this.javaClass = (Class<?>) staticFieldValue(wrapperClass, WRAPPER_CLASS_TYPE_FIELD_NAME); + } + } + + private static class TypeDeclaration { + final String elementTypeName; + final int arrayDepth; + TypeDeclaration(String elementTypeName, int arrayDepth) { + this.elementTypeName = elementTypeName; + this.arrayDepth = arrayDepth; + } + } + +} diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/JptUtilityTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/JptUtilityTests.java index c411aaf4f4..ae844ed0af 100644 --- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/JptUtilityTests.java +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/JptUtilityTests.java @@ -40,6 +40,7 @@ public class JptUtilityTests { suite.addTestSuite(IndentingPrintWriterTests.class); suite.addTestSuite(JavaTypeTests.class); suite.addTestSuite(JDBCTypeTests.class); + suite.addTestSuite(MethodSignatureTests.class); suite.addTestSuite(NameToolsTests.class); suite.addTestSuite(ReverseComparatorTests.class); suite.addTestSuite(SimpleAssociationTests.class); diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/MethodSignatureTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/MethodSignatureTests.java new file mode 100644 index 0000000000..b1d6f5bc1d --- /dev/null +++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/MethodSignatureTests.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2008 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.utility.tests.internal; + +import java.lang.reflect.Method; +import java.util.Arrays; + +import org.eclipse.jpt.utility.JavaType; +import org.eclipse.jpt.utility.MethodSignature; +import org.eclipse.jpt.utility.internal.SimpleJavaType; +import org.eclipse.jpt.utility.internal.SimpleMethodSignature; + +import junit.framework.TestCase; + +public class MethodSignatureTests extends TestCase { + + public MethodSignatureTests(String name) { + super(name); + } + + public void testInvalidNameNull() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature((String) null); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidNameEmpty() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature(""); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterTypesNull() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", (JavaType[]) null); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterTypesNullItem() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", new JavaType[1]); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterTypesVoidItem() throws Exception { + JavaType jt = new SimpleJavaType(void.class.getName()); + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", new JavaType[] {jt}); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterTypeNamesNull() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", (String[]) null); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterTypeNamesNullItem() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", new String[1]); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterJavaClassesNull() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", (Class<?>[]) null); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testInvalidParameterJavaClassesNullItem() throws Exception { + boolean exCaught = false; + try { + MethodSignature methodSignature = new SimpleMethodSignature("foo", new Class[1]); + fail("invalid MethodSignature: " + methodSignature); + } catch (IllegalArgumentException ex) { + exCaught = true; + } + assertTrue(exCaught); + } + + public void testGetSignature0() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method0")); + assertEquals("method0()", ms.getSignature()); + } + + public void testGetSignature1() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method1")); + assertEquals("method1(int)", ms.getSignature()); + } + + public void testGetSignature2() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method2")); + assertEquals("method2(int, java.lang.String)", ms.getSignature()); + } + + public void testGetSignature3() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method3")); + assertEquals("method3(int, java.lang.String, java.lang.Object[][])", ms.getSignature()); + } + + public void testGetName() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method2")); + assertEquals("method2", ms.getName()); + } + + public void testGetParameterTypes() throws Exception { + MethodSignature ms = new SimpleMethodSignature(this.getMethod("method3")); + JavaType[] expected = new JavaType[3]; + expected[0] = new SimpleJavaType("int"); + expected[1] = new SimpleJavaType("java.lang.String"); + expected[2] = new SimpleJavaType("java.lang.Object", 2); + assertTrue(Arrays.equals(expected, ms.getParameterTypes())); + } + + public void testEquals() throws Exception { + Object ms1 = new SimpleMethodSignature(this.getMethod("method3")); + Object ms2 = new SimpleMethodSignature(this.getMethod("method3")); + assertNotSame(ms1, ms2); + assertEquals(ms1, ms1); + assertEquals(ms1, ms2); + assertEquals(ms1.hashCode(), ms2.hashCode()); + + Object ms3 = new SimpleMethodSignature(this.getMethod("method2")); + assertNotSame(ms1, ms3); + assertFalse(ms1.equals(ms3)); + } + + public void testCompareTo1() throws Exception { + MethodSignature ms1 = new SimpleMethodSignature(this.getMethod("method3")); + MethodSignature ms2 = new SimpleMethodSignature(this.getMethod("method3")); + assertEquals(0, ms1.compareTo(ms2)); + } + + public void testCompareTo2() throws Exception { + MethodSignature ms1 = new SimpleMethodSignature(this.getMethod("method3")); + MethodSignature ms2 = new SimpleMethodSignature(this.getMethod("method2")); + assertTrue(ms1.compareTo(ms2) > 0); + } + + public void testCompareTo3() throws Exception { + MethodSignature msA1 = new SimpleMethodSignature(this.getMethod("methodA", new Class[] {int.class, String.class})); + MethodSignature msA2 = new SimpleMethodSignature(this.getMethod("methodA", new Class[] {int.class, String.class, String.class})); + assertTrue(msA1.compareTo(msA2) < 0); + } + + public void testCompareTo4() throws Exception { + MethodSignature msB1 = new SimpleMethodSignature(this.getMethod("methodB", new Class[] {int.class, Object.class})); + MethodSignature msB2 = new SimpleMethodSignature(this.getMethod("methodB", new Class[] {int.class, String.class})); + assertTrue(msB1.compareTo(msB2) < 0); + } + + public void testClone() throws Exception { + SimpleMethodSignature ms1 = new SimpleMethodSignature(this.getMethod("method3")); + SimpleMethodSignature ms2 = (SimpleMethodSignature) ms1.clone(); + assertNotSame(ms1, ms2); + assertEquals(ms1, ms2); + } + + public void testSerialization() throws Exception { + SimpleMethodSignature ms1 = new SimpleMethodSignature(this.getMethod("method3")); + SimpleMethodSignature ms2 = TestTools.serialize(ms1); + assertNotSame(ms1, ms2); + assertEquals(ms1, ms2); + } + + private Method getMethod(String methodName) { + for (Method method : this.getClass().getMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException("method not found: " + methodName); + } + + private Method getMethod(String methodName, Class<?>... parameterTypes) throws Exception { + return this.getClass().getMethod(methodName, parameterTypes); + } + + public void method0() { /* used by tests */ } + public void method1(int foo) { /* used by tests */ } + public void method2(int foo, String bar) { /* used by tests */ } + public void method3(int foo, String bar, Object[][] baz) { /* used by tests */ } + + public void methodA(int foo, String bar) { /* used by tests */ } + public void methodA(int foo, String bar, String baz) { /* used by tests */ } + + public void methodB(int foo, Object bar) { /* used by tests */ } + public void methodB(int foo, String bar) { /* used by tests */ } + +} |