blob: 5667c5e54b219e856615a96aef964f2053624ea8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 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.jar;
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.IAnnotation;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jpt.core.JptCorePlugin;
import org.eclipse.jpt.core.internal.utility.jdt.JPTTools;
import org.eclipse.jpt.core.resource.jar.JarResourcePersistentAttribute;
import org.eclipse.jpt.core.resource.jar.JarResourcePersistentType;
import org.eclipse.jpt.core.resource.java.AccessAnnotation;
import org.eclipse.jpt.core.resource.java.AccessType;
import org.eclipse.jpt.core.resource.java.Annotation;
import org.eclipse.jpt.utility.MethodSignature;
import org.eclipse.jpt.utility.internal.ClassTools;
import org.eclipse.jpt.utility.internal.NameTools;
import org.eclipse.jpt.utility.internal.iterators.CloneIterator;
import org.eclipse.jpt.utility.internal.iterators.CloneListIterator;
/**
* JAR persistent attribute (field or property)
*/
public class JarResourcePersistentAttributeImpl
extends AbstractJarResourcePersistentMember
implements JarResourcePersistentAttribute
{
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>();
protected JarResourcePersistentAttributeImpl(JarResourcePersistentType parent, IField field) {
this(parent, new FieldAdapter(field));
}
protected JarResourcePersistentAttributeImpl(JarResourcePersistentType parent, IMethod method) {
this(parent, new MethodAdapter(method));
}
protected JarResourcePersistentAttributeImpl(JarResourcePersistentType parent, Adapter adapter) {
super(parent, adapter);
this.modifiers = this.buildModifiers();
this.typeName = this.buildTypeName();
this.typeIsInterface = this.buildTypeIsInterface();
this.typeIsEnum = this.buildTypeIsEnum();
this.typeSuperclassNames.addAll(this.buildTypeSuperclassNames());
this.typeInterfaceNames.addAll(this.buildTypeInterfaceNames());
this.typeTypeArgumentNames.addAll(this.buildTypeTypeArgumentNames());
}
// ******** overrides ********
@Override
public void update() {
super.update();
// TODO
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
// ********** AbstractJarResourcePersistentMember implementation **********
@Override
protected Adapter getAdapter() {
return (Adapter) super.getAdapter();
}
@Override
protected Annotation buildMappingAnnotation(IAnnotation jdtAnnotation) {
return this.getAnnotationProvider().buildAttributeMappingAnnotation(this, jdtAnnotation);
}
@Override
protected Annotation buildSupportingAnnotation(IAnnotation jdtAnnotation) {
return this.getAnnotationProvider().buildAttributeSupportingAnnotation(this, jdtAnnotation);
}
@Override
protected Annotation buildNullSupportingAnnotation(String annotationName) {
return this.getAnnotationProvider().buildNullAttributeSupportingAnnotation(this, annotationName);
}
@Override
protected Annotation buildNullMappingAnnotation(String annotationName) {
return this.getAnnotationProvider().buildNullAttributeMappingAnnotation(this, annotationName);
}
@Override
protected ListIterator<String> validMappingAnnotationNames() {
return this.getAnnotationProvider().attributeMappingAnnotationNames();
}
@Override
protected ListIterator<String> validSupportingAnnotationNames() {
return this.getAnnotationProvider().attributeSupportingAnnotationNames();
}
// ********** JarResourcePersistentAttribute implementation **********
public String getName() {
return this.getAdapter().getAttributeName();
}
public boolean isField() {
return this.getAdapter().isField();
}
public boolean isProperty() {
return ! this.isField();
}
public boolean hasAnyPersistenceAnnotations() {
return (this.mappingAnnotationsSize() > 0)
|| (this.supportingAnnotationsSize() > 0);
}
public AccessType getSpecifiedAccess() {
AccessAnnotation accessAnnotation = (AccessAnnotation) this.getSupportingAnnotation(AccessAnnotation.ANNOTATION_NAME);
return accessAnnotation == null ? null : accessAnnotation.getValue();
}
public boolean typeIsSubTypeOf(String tn) {
return ((this.typeName != null) && this.typeName.equals(tn))
|| this.typeInterfaceNames.contains(tn)
|| this.typeSuperclassNames.contains(tn);
}
public boolean typeIsVariablePrimitive() {
return (this.typeName != null) && ClassTools.classNamedIsVariablePrimitive(this.typeName);
}
// ***** modifiers
public int getModifiers() {
return this.modifiers;
}
protected void setModifiers(int modifiers) {
int old = this.modifiers;
this.modifiers = modifiers;
this.firePropertyChanged(MODIFIERS_PROPERTY, old, modifiers);
}
/**
* zero seems like a reasonable default...
*/
protected int buildModifiers() {
try {
return this.getMember().getFlags();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return 0;
}
}
// ***** type name
public String getTypeName() {
return this.typeName;
}
protected void setTypeName(String typeName) {
String old = this.typeName;
this.typeName = typeName;
this.firePropertyChanged(TYPE_NAME_PROPERTY, old, typeName);
}
/**
* JARs don't have array types;
* also, no generic type arguments
*/
protected String buildTypeName() {
return convertTypeSignatureToTypeName(this.getTypeSignature());
}
// ***** type is interface
public boolean typeIsInterface() {
return this.typeIsInterface;
}
protected void setTypeIsInterface(boolean typeIsInterface) {
boolean old = this.typeIsInterface;
this.typeIsInterface = typeIsInterface;
this.firePropertyChanged(TYPE_IS_INTERFACE_PROPERTY, old, typeIsInterface);
}
protected boolean buildTypeIsInterface() {
IType type = this.getType(); // shouldn't be an array...
try {
return (type != null) && type.isInterface();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return false;
}
}
// ***** type is enum
public boolean typeIsEnum() {
return this.typeIsEnum;
}
protected void setTypeIsEnum(boolean typeIsEnum) {
boolean old = this.typeIsEnum;
this.typeIsEnum = typeIsEnum;
this.firePropertyChanged(TYPE_IS_ENUM_PROPERTY, old, typeIsEnum);
}
protected boolean buildTypeIsEnum() {
IType type = this.getType(); // shouldn't be an array...
try {
return (type != null) && type.isEnum();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return false;
}
}
// ***** type superclass hierarchy
public ListIterator<String> typeSuperclassNames() {
return new CloneListIterator<String>(this.typeSuperclassNames);
}
public boolean typeSuperclassNamesContains(String superclassName) {
return this.typeSuperclassNames.contains(superclassName);
}
protected void setTypeSuperclassNames(List<String> typeSuperclassNames) {
synchronized (this.typeSuperclassNames) {
this.synchronizeList(typeSuperclassNames, this.typeSuperclassNames, TYPE_SUPERCLASS_NAMES_COLLECTION);
}
}
protected List<String> buildTypeSuperclassNames() {
IType type = this.getType();
if (type == null) {
return Collections.emptyList();
}
ArrayList<String> names = new ArrayList<String>();
type = this.findSuperclass(type);
while (type != null) {
names.add(type.getFullyQualifiedName());
type = this.findSuperclass(type);
}
return names;
}
// ***** type interface hierarchy
public Iterator<String> typeInterfaceNames() {
return new CloneIterator<String>(this.typeInterfaceNames);
}
public boolean typeInterfaceNamesContains(String interfaceName) {
return this.typeInterfaceNames.contains(interfaceName);
}
protected void setTypeInterfaceNames(Collection<String> typeInterfaceNames) {
synchronized (this.typeInterfaceNames) {
this.synchronizeCollection(typeInterfaceNames, this.typeInterfaceNames, TYPE_INTERFACE_NAMES_COLLECTION);
}
}
protected Collection<String> buildTypeInterfaceNames() {
IType type = this.getType();
if (type == null) {
return Collections.emptySet();
}
HashSet<String> names = new HashSet<String>();
while (type != null) {
this.addInterfaceNamesTo(type, names);
type = this.findSuperclass(type);
}
return names;
}
protected void addInterfaceNamesTo(IType type, HashSet<String> names) {
for (String interfaceSignature : this.getSuperInterfaceTypeSignatures(type)) {
String interfaceName = convertTypeSignatureToTypeName(interfaceSignature);
names.add(interfaceName);
IType interfaceType = this.findType(interfaceName);
if (interfaceType != null) {
this.addInterfaceNamesTo(interfaceType, 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);
}
protected void setTypeTypeArgumentNames(List<String> typeTypeArgumentNames) {
synchronized (this.typeTypeArgumentNames) {
this.synchronizeList(typeTypeArgumentNames, this.typeTypeArgumentNames, TYPE_TYPE_ARGUMENT_NAMES_COLLECTION);
}
}
/**
* 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>")
*/
protected List<String> buildTypeTypeArgumentNames() {
String typeSignature = this.getTypeSignature();
if (typeSignature == null) {
return Collections.emptyList();
}
String[] typeArgumentSignatures = Signature.getTypeArguments(typeSignature);
if (typeArgumentSignatures.length == 0) {
return Collections.emptyList();
}
ArrayList<String> names = new ArrayList<String>(typeArgumentSignatures.length);
for (String typeArgumentSignature : typeArgumentSignatures) {
names.add(convertTypeSignatureToTypeName(typeArgumentSignature));
}
return names;
}
// ********** convenience methods **********
protected String getTypeSignature() {
try {
return this.getAdapter().getTypeSignature();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return null;
}
}
protected IType findSuperclass(IType type) {
return this.findTypeBySignature(this.getSuperclassSignature(type));
}
protected String getSuperclassSignature(IType type) {
try {
return type.getSuperclassTypeSignature();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return null;
}
}
protected String[] getSuperInterfaceTypeSignatures(IType type) {
try {
return type.getSuperInterfaceTypeSignatures();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return EMPTY_STRING_ARRAY;
}
}
protected static final String[] EMPTY_STRING_ARRAY = new String[0];
/**
* Strip off the type signature's parameters if present.
* Convert to a readable string.
*/
protected static String convertTypeSignatureToTypeName(String typeSignature) {
return (typeSignature == null) ? null : convertTypeSignatureToTypeName_(typeSignature);
}
/**
* no null check
*/
protected static String convertTypeSignatureToTypeName_(String typeSignature) {
return Signature.toString(Signature.getTypeErasure(typeSignature));
}
protected IType findTypeBySignature(String typeSignature) {
return (typeSignature == null) ? null : this.findType(convertTypeSignatureToTypeName_(typeSignature));
}
protected IType getType() {
return (this.typeName == null) ? null : this.findType(this.typeName);
}
protected IType findType(String fullyQualifiedName) {
try {
return this.getJavaProject().findType(fullyQualifiedName);
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return null;
}
}
protected IJavaProject getJavaProject() {
return this.getMember().getJavaProject();
}
// ********** adapters **********
protected interface Adapter extends AbstractJarResourcePersistentMember.Adapter {
String getAttributeName();
boolean isField();
String getTypeSignature() throws JavaModelException;
}
protected static class FieldAdapter implements Adapter {
private final IField field;
protected FieldAdapter(IField field) {
super();
this.field = field;
}
public IField getMember() {
return this.field;
}
public boolean isPersistable() {
return this.field.exists() && JPTTools.fieldIsPersistable(new JPTToolsAdapter(this.field));
}
public IAnnotation[] getAnnotations() throws JavaModelException {
return this.field.getAnnotations();
}
public String getAttributeName() {
return this.field.getElementName();
}
public boolean isField() {
return true;
}
public String getTypeSignature() throws JavaModelException {
return this.field.getTypeSignature();
}
/**
* JPTTools needs an adapter so it can work with either an IField
* or an IVariableBinding etc.
*/
protected static class JPTToolsAdapter implements JPTTools.FieldAdapter {
private final IField field;
protected JPTToolsAdapter(IField field) {
super();
if (field == null) {
throw new NullPointerException();
}
this.field = field;
}
public int getModifiers() {
try {
return this.field.getFlags();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return 0;
}
}
}
}
protected static class MethodAdapter implements Adapter {
private final IMethod method;
protected MethodAdapter(IMethod method) {
super();
this.method = method;
}
public IMethod getMember() {
return this.method;
}
public boolean isPersistable() {
return JPTTools.methodIsPersistablePropertyGetter(new JPTToolsAdapter(this.method));
}
public IAnnotation[] getAnnotations() throws JavaModelException {
return this.method.getAnnotations();
}
public String getAttributeName() {
return NameTools.convertGetterMethodNameToPropertyName(this.method.getElementName());
}
public boolean isField() {
return false;
}
public String getTypeSignature() throws JavaModelException {
return this.method.getReturnType();
}
/**
* JPTTools needs an adapter so it can work with either an IMethod
* or an IMethodBinding etc.
*/
protected static class JPTToolsAdapter implements JPTTools.MethodAdapter {
private final IMethod method;
protected JPTToolsAdapter(IMethod method) {
super();
if (method == null) {
throw new NullPointerException();
}
this.method = method;
}
public String getName() {
return this.method.getElementName();
}
public int getModifiers() {
try {
return this.method.getFlags();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return 0;
}
}
public String getReturnTypeName() {
try {
return this.method.getReturnType();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return null;
}
}
public boolean isConstructor() {
try {
return this.method.isConstructor();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return false;
}
}
public int getParametersLength() {
return this.method.getParameterTypes().length;
}
public JPTTools.MethodAdapter getSibling(String name) {
for (IMethod sibling : this.getSiblings()) {
if ((sibling.getParameterTypes().length == 0)
&& sibling.getElementName().equals(name)) {
return new JPTToolsAdapter(sibling);
}
}
return null;
}
public JPTTools.MethodAdapter getSibling(String name, String parameterTypeName) {
for (IMethod sibling : this.getSiblings()) {
String[] parmTypes = sibling.getParameterTypes();
if ((parmTypes.length == 1)
&& parmTypes[0].equals(parameterTypeName)
&& sibling.getElementName().equals(name)) {
return new JPTToolsAdapter(sibling);
}
}
return null;
}
protected IMethod[] getSiblings() {
try {
return this.method.getDeclaringType().getMethods();
} catch (JavaModelException ex) {
JptCorePlugin.log(ex);
return EMPTY_METHOD_ARRAY;
}
}
protected static final IMethod[] EMPTY_METHOD_ARRAY = new IMethod[0];
}
}
// TODO ============== remove ========================
public boolean isFor(MethodSignature methodSignature, int occurrence) {
throw new UnsupportedOperationException();
}
}