blob: c864ae94defa756066f1412a4f948f813d0620a4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.core.internal.resource.java.source;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
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.jpt.core.jpa2.resource.java.Access2_0Annotation;
import org.eclipse.jpt.core.resource.java.AccessType;
import org.eclipse.jpt.core.resource.java.Annotation;
import org.eclipse.jpt.core.resource.java.JavaResourceCompilationUnit;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType;
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.ClassName;
import org.eclipse.jpt.utility.internal.iterators.CloneIterator;
import org.eclipse.jpt.utility.internal.iterators.CloneListIterator;
/**
* Java source persistent attribute (field or property)
*/
final class SourcePersistentAttribute
extends SourcePersistentMember<Attribute>
implements JavaResourcePersistentAttribute
{
private int modifiers;
private String typeName;
private boolean typeIsInterface;
private boolean typeIsEnum;
private final Vector<String> typeSuperclassNames = new Vector<String>();
private final Vector<String> typeInterfaceNames = new Vector<String>();
private final Vector<String> typeTypeArgumentNames = new Vector<String>();
/**
* construct field attribute
*/
static JavaResourcePersistentAttribute newInstance(
JavaResourcePersistentType parent,
Type declaringType,
String name,
int occurrence,
JavaResourceCompilationUnit javaResourceCompilationUnit,
CompilationUnit astRoot) {
Attribute attribute = new JDTFieldAttribute(
declaringType,
name,
occurrence,
javaResourceCompilationUnit.getCompilationUnit(),
javaResourceCompilationUnit.getModifySharedDocumentCommandExecutor(),
javaResourceCompilationUnit.getAnnotationEditFormatter());
JavaResourcePersistentAttribute jrpa = new SourcePersistentAttribute(parent, attribute);
jrpa.initialize(astRoot);
return jrpa;
}
/**
* construct property attribute
*/
static JavaResourcePersistentAttribute newInstance(
JavaResourcePersistentType parent,
Type declaringType,
MethodSignature signature,
int occurrence,
JavaResourceCompilationUnit javaResourceCompilationUnit,
CompilationUnit astRoot) {
Attribute attribute = JDTMethodAttribute.newInstance(
declaringType,
signature,
occurrence,
javaResourceCompilationUnit.getCompilationUnit(),
javaResourceCompilationUnit.getModifySharedDocumentCommandExecutor(),
javaResourceCompilationUnit.getAnnotationEditFormatter());
JavaResourcePersistentAttribute jrpa = new SourcePersistentAttribute(parent, attribute);
jrpa.initialize(astRoot);
return jrpa;
}
private SourcePersistentAttribute(JavaResourcePersistentType parent, Attribute attribute){
super(parent, attribute);
}
@Override
public void initialize(CompilationUnit astRoot) {
super.initialize(astRoot);
this.modifiers = this.buildModifiers(astRoot);
this.typeName = this.buildTypeName(astRoot);
this.typeIsInterface = this.buildTypeIsInterface(astRoot);
this.typeIsEnum = this.buildTypeIsEnum(astRoot);
this.typeSuperclassNames.addAll(this.buildTypeSuperclassNames(astRoot));
this.typeInterfaceNames.addAll(this.buildTypeInterfaceNames(astRoot));
this.typeTypeArgumentNames.addAll(this.buildTypeTypeArgumentNames(astRoot));
}
// ******** overrides ********
@Override
public void resolveTypes(CompilationUnit astRoot) {
super.resolveTypes(astRoot);
this.syncTypeName(this.buildTypeName(astRoot));
this.syncTypeSuperclassNames(this.buildTypeSuperclassNames(astRoot));
this.syncTypeInterfaceNames(this.buildTypeInterfaceNames(astRoot));
this.syncTypeTypeArgumentNames(this.buildTypeTypeArgumentNames(astRoot));
}
@Override
public void synchronizeWith(CompilationUnit astRoot) {
super.synchronizeWith(astRoot);
this.syncModifiers(this.buildModifiers(astRoot));
this.syncTypeName(this.buildTypeName(astRoot));
this.syncTypeIsInterface(this.buildTypeIsInterface(astRoot));
this.syncTypeIsEnum(this.buildTypeIsEnum(astRoot));
this.syncTypeSuperclassNames(this.buildTypeSuperclassNames(astRoot));
this.syncTypeInterfaceNames(this.buildTypeInterfaceNames(astRoot));
this.syncTypeTypeArgumentNames(this.buildTypeTypeArgumentNames(astRoot));
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
// ******** AbstractJavaResourcePersistentMember implementation ********
@Override
Iterator<String> validAnnotationNames() {
return this.getAnnotationProvider().attributeAnnotationNames();
}
@Override
Annotation buildAnnotation(String annotationName) {
return this.getAnnotationProvider().buildAttributeAnnotation(this, this.member, annotationName);
}
Annotation buildNullAnnotation_(String annotationName) {
return this.getAnnotationProvider().buildNullAttributeAnnotation(this, annotationName);
}
public boolean isFor(MethodSignature signature, int occurrence) {
return ((MethodAttribute) this.member).matches(signature, occurrence);
}
// ******** JavaResourcePersistentAttribute implementation ********
public String getName() {
return this.member.getAttributeName();
}
@Override
public Annotation buildNullAnnotation(String annotationName) {
return (annotationName == null) ? null : this.buildNullAnnotation_(annotationName);
}
public boolean isField() {
return this.member.isField();
}
public boolean isProperty() {
return ! this.isField();
}
public AccessType getSpecifiedAccess() {
Access2_0Annotation accessAnnotation = this.getAccessAnnotation();
return (accessAnnotation == null) ? null : accessAnnotation.getValue();
}
private Access2_0Annotation getAccessAnnotation() {
return (Access2_0Annotation) this.getAnnotation(Access2_0Annotation.ANNOTATION_NAME);
}
public boolean typeIsSubTypeOf(String tn) {
if (this.typeName == null) {
return false;
}
return this.typeName.equals(tn)
|| this.typeInterfaceNames.contains(tn)
|| this.typeSuperclassNames.contains(tn);
}
public boolean typeIsVariablePrimitive() {
return (this.typeName != null) && ClassName.isVariablePrimitive(this.typeName);
}
private ITypeBinding getTypeBinding(CompilationUnit astRoot) {
return this.member.getTypeBinding(astRoot);
}
// ***** modifiers
public int getModifiers() {
return this.modifiers;
}
private void syncModifiers(int astModifiers) {
int old = this.modifiers;
this.modifiers = astModifiers;
this.firePropertyChanged(MODIFIERS_PROPERTY, old, astModifiers);
}
/**
* zero seems like a reasonable default...
*/
private int buildModifiers(CompilationUnit astRoot) {
IBinding binding = this.member.getBinding(astRoot);
return (binding == null) ? 0 : binding.getModifiers();
}
// ***** type name
public String getTypeName() {
return this.typeName;
}
private void syncTypeName(String astTypeName) {
String old = this.typeName;
this.typeName = astTypeName;
this.firePropertyChanged(TYPE_NAME_PROPERTY, old, astTypeName);
}
/**
* this can be an array (e.g. "java.lang.String[]");
* but no generic type arguments
*/
private String buildTypeName(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
return (typeBinding == null) ? null : typeBinding.getTypeDeclaration().getQualifiedName();
}
// ***** type is interface
public boolean typeIsInterface() {
return this.typeIsInterface;
}
private void syncTypeIsInterface(boolean astTypeIsInterface) {
boolean old = this.typeIsInterface;
this.typeIsInterface = astTypeIsInterface;
this.firePropertyChanged(TYPE_IS_INTERFACE_PROPERTY, old, astTypeIsInterface);
}
private boolean buildTypeIsInterface(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
return (typeBinding != null) && ( ! typeBinding.isArray()) && typeBinding.isInterface();
}
// ***** type is enum
public boolean typeIsEnum() {
return this.typeIsEnum;
}
private void syncTypeIsEnum(boolean astTypeIsEnum) {
boolean old = this.typeIsEnum;
this.typeIsEnum = astTypeIsEnum;
this.firePropertyChanged(TYPE_IS_ENUM_PROPERTY, old, astTypeIsEnum);
}
private boolean buildTypeIsEnum(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
return (typeBinding != null) && ( ! typeBinding.isArray()) && typeBinding.isEnum();
}
// ***** type superclass hierarchy
public ListIterator<String> typeSuperclassNames() {
return new CloneListIterator<String>(this.typeSuperclassNames);
}
private void syncTypeSuperclassNames(List<String> astTypeSuperclassNames) {
this.synchronizeList(astTypeSuperclassNames, this.typeSuperclassNames, TYPE_SUPERCLASS_NAMES_LIST);
}
private List<String> buildTypeSuperclassNames(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
if (typeBinding == null) {
return Collections.emptyList();
}
ArrayList<String> names = new ArrayList<String>();
typeBinding = typeBinding.getSuperclass();
while (typeBinding != null) {
names.add(typeBinding.getQualifiedName());
typeBinding = typeBinding.getSuperclass();
}
return names;
}
// ***** type interface hierarchy
public Iterator<String> typeInterfaceNames() {
return new CloneIterator<String>(this.typeInterfaceNames);
}
// private boolean typeInterfaceNamesContains(String interfaceName) {
// return this.typeInterfaceNames.contains(interfaceName);
// }
//
private void syncTypeInterfaceNames(Collection<String> astTypeInterfaceNames) {
this.synchronizeCollection(astTypeInterfaceNames, this.typeInterfaceNames, TYPE_INTERFACE_NAMES_COLLECTION);
}
private Collection<String> buildTypeInterfaceNames(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
if (typeBinding == null) {
return Collections.emptySet();
}
HashSet<String> names = new HashSet<String>();
while (typeBinding != null) {
this.addInterfaceNamesTo(typeBinding, names);
typeBinding = typeBinding.getSuperclass();
}
return names;
}
private void addInterfaceNamesTo(ITypeBinding typeBinding, HashSet<String> names) {
for (ITypeBinding interfaceBinding : typeBinding.getInterfaces()) {
names.add(interfaceBinding.getTypeDeclaration().getQualifiedName());
this.addInterfaceNamesTo(interfaceBinding, names); // recurse
}
}
// ***** type type argument names
public ListIterator<String> typeTypeArgumentNames() {
return new CloneListIterator<String>(this.typeTypeArgumentNames);
}
public int typeTypeArgumentNamesSize() {
return this.typeTypeArgumentNames.size();
}
public String getTypeTypeArgumentName(int index) {
return this.typeTypeArgumentNames.get(index);
}
private void syncTypeTypeArgumentNames(List<String> astTypeTypeArgumentNames) {
this.synchronizeList(astTypeTypeArgumentNames, this.typeTypeArgumentNames, TYPE_TYPE_ARGUMENT_NAMES_LIST);
}
/**
* these types can be arrays (e.g. "java.lang.String[]");
* but they won't have any further nested generic type arguments
* (e.g. "java.util.Collection<java.lang.String>")
*/
private List<String> buildTypeTypeArgumentNames(CompilationUnit astRoot) {
ITypeBinding typeBinding = this.getTypeBinding(astRoot);
if (typeBinding == null) {
return Collections.emptyList();
}
ITypeBinding[] typeArguments = typeBinding.getTypeArguments();
if (typeArguments.length == 0) {
return Collections.emptyList();
}
ArrayList<String> names = new ArrayList<String>(typeArguments.length);
for (ITypeBinding typeArgument : typeArguments) {
if (typeArgument == null) {
names.add(null);
} else {
names.add(typeArgument.getTypeDeclaration().getQualifiedName());
}
}
return names;
}
}